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.lethe.ui.dialog;
18  
19  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
20  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
21  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateConfig;
22  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
23  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
24  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusPrice;
25  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
26  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusUnits;
27  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
28  import io.github.tonywasher.joceanus.metis.field.MetisFieldRequired;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetBase;
30  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetBase.MoneyWiseAssetBaseList;
31  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetDirection;
32  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetType;
33  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
34  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
35  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseCash.MoneyWiseCashList;
36  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataSet;
37  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataValidator.MoneyWiseDataValidatorTrans;
38  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDeposit.MoneyWiseDepositList;
39  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseLoan.MoneyWiseLoanList;
40  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee.MoneyWisePayeeList;
41  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePortfolio;
42  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePortfolio.MoneyWisePortfolioList;
43  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurity;
44  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurityHolding;
45  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurityHolding.MoneyWiseSecurityHoldingMap;
46  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransAsset;
47  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransCategory;
48  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransCategory.MoneyWiseTransCategoryList;
49  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransInfoSet;
50  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransTag;
51  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransaction;
52  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransaction.MoneyWiseTransactionList;
53  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTransCategoryClass;
54  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTransInfoClass;
55  import io.github.tonywasher.joceanus.moneywise.data.validate.MoneyWiseValidateTransaction;
56  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysis;
57  import io.github.tonywasher.joceanus.moneywise.lethe.ui.controls.MoneyWiseAnalysisSelect;
58  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseAnalysisFilter;
59  import io.github.tonywasher.joceanus.moneywise.lethe.views.MoneyWiseTransactionFilters;
60  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseIcon;
61  import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseUIResource;
62  import io.github.tonywasher.joceanus.moneywise.ui.base.MoneyWiseBaseTable;
63  import io.github.tonywasher.joceanus.moneywise.ui.base.MoneyWiseItemPanel;
64  import io.github.tonywasher.joceanus.prometheus.ui.fieldset.PrometheusFieldSet;
65  import io.github.tonywasher.joceanus.prometheus.ui.fieldset.PrometheusFieldSetEvent;
66  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
67  import io.github.tonywasher.joceanus.tethys.api.control.TethysUIControl.TethysUIIconMapSet;
68  import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
69  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIDateButtonField;
70  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIIconButtonField;
71  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIIntegerEditField;
72  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIListButtonField;
73  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIMoneyEditField;
74  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIPriceEditField;
75  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIRatioEditField;
76  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIScrollButtonField;
77  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIStringEditField;
78  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIDataEditField.TethysUIUnitsEditField;
79  import io.github.tonywasher.joceanus.tethys.api.field.TethysUIFieldFactory;
80  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollItem;
81  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollMenu;
82  import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollSubMenu;
83  
84  import java.util.ArrayList;
85  import java.util.HashMap;
86  import java.util.Iterator;
87  import java.util.List;
88  import java.util.Map;
89  
90  /**
91   * Panel to display/edit/create a Transaction.
92   */
93  public class MoneyWiseTransactionDialog
94          extends MoneyWiseItemPanel<MoneyWiseTransaction> {
95      /**
96       * Info Tab Title.
97       */
98      private static final String TAB_INFO = MoneyWiseUIResource.TRANSPANEL_TAB_INFO.getValue();
99  
100     /**
101      * Tax Tab Title.
102      */
103     private static final String TAB_TAXES = MoneyWiseUIResource.TRANSPANEL_TAB_TAXES.getValue();
104 
105     /**
106      * Securities Tab Title.
107      */
108     private static final String TAB_SECURITIES = MoneyWiseUIResource.TRANSPANEL_TAB_SECURITIES.getValue();
109 
110     /**
111      * Returned Tab Title.
112      */
113     private static final String TAB_RETURNED = MoneyWiseUIResource.TRANSPANEL_TAB_RETURNED.getValue();
114 
115     /**
116      * The fieldSet.
117      */
118     private final PrometheusFieldSet<MoneyWiseTransaction> theFieldSet;
119 
120     /**
121      * Analysis selection panel.
122      */
123     private final MoneyWiseAnalysisSelect theAnalysisSelect;
124 
125     /**
126      * dateRange.
127      */
128     private OceanusDateRange theRange;
129 
130     /**
131      * reconciledState.
132      */
133     private Boolean theReconciledState = Boolean.FALSE;
134 
135     /**
136      * directionState.
137      */
138     private Boolean theDirectionState = Boolean.FALSE;
139 
140     /**
141      * Constructor.
142      *
143      * @param pFactory        the GUI factory
144      * @param pEditSet        the edit set
145      * @param pAnalysisSelect the analysis selection panel
146      * @param pOwner          the owning table
147      */
148     public MoneyWiseTransactionDialog(final TethysUIFactory<?> pFactory,
149                                       final PrometheusEditSet pEditSet,
150                                       final MoneyWiseAnalysisSelect pAnalysisSelect,
151                                       final MoneyWiseBaseTable<MoneyWiseTransaction> pOwner) {
152         /* Initialise the panel */
153         super(pFactory, pEditSet, pOwner);
154         theAnalysisSelect = pAnalysisSelect;
155 
156         /* Access the fieldSet */
157         theFieldSet = getFieldSet();
158 
159         /* Build the main panel */
160         buildMainPanel(pFactory);
161 
162         /* Build the info panel */
163         buildInfoPanel(pFactory);
164 
165         /* Build the tax panel */
166         buildTaxPanel(pFactory);
167 
168         /* Build the securities panel */
169         buildSecuritiesPanel(pFactory);
170 
171         /* Build the returned panel */
172         buildReturnedPanel(pFactory);
173     }
174 
175     /**
176      * Build Main subPanel.
177      *
178      * @param pFactory the GUI factory
179      */
180     private void buildMainPanel(final TethysUIFactory<?> pFactory) {
181         /* Allocate fields */
182         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
183         final TethysUIMoneyEditField myAmount = myFields.newMoneyField();
184 
185         /* Create the buttons */
186         final TethysUIDateButtonField myDateButton = myFields.newDateField();
187         final TethysUIScrollButtonField<MoneyWiseTransAsset> myAccountButton = myFields.newScrollField(MoneyWiseTransAsset.class);
188         final TethysUIScrollButtonField<MoneyWiseTransAsset> myPartnerButton = myFields.newScrollField(MoneyWiseTransAsset.class);
189         final TethysUIScrollButtonField<MoneyWiseTransCategory> myCategoryButton = myFields.newScrollField(MoneyWiseTransCategory.class);
190         final TethysUIIconButtonField<Boolean> myReconciledButton = myFields.newIconField(Boolean.class);
191         final TethysUIIconButtonField<MoneyWiseAssetDirection> myDirectionButton = myFields.newIconField(MoneyWiseAssetDirection.class);
192 
193         /* Assign the fields to the panel */
194         theFieldSet.addField(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE, myDateButton, MoneyWiseTransaction::getDate);
195         theFieldSet.addField(MoneyWiseBasicResource.TRANSACTION_ACCOUNT, myAccountButton, MoneyWiseTransaction::getAccount);
196         theFieldSet.addField(MoneyWiseBasicDataType.TRANSCATEGORY, myCategoryButton, MoneyWiseTransaction::getCategory);
197         theFieldSet.addField(MoneyWiseBasicResource.TRANSACTION_DIRECTION, myDirectionButton, MoneyWiseTransaction::getDirection);
198         theFieldSet.addField(MoneyWiseBasicResource.TRANSACTION_PARTNER, myPartnerButton, MoneyWiseTransaction::getPartner);
199         theFieldSet.addField(MoneyWiseBasicResource.TRANSACTION_AMOUNT, myAmount, MoneyWiseTransaction::getAmount);
200         theFieldSet.addField(MoneyWiseBasicResource.TRANSACTION_RECONCILED, myReconciledButton, MoneyWiseTransaction::isReconciled);
201 
202         /* Configure the menuBuilders */
203         myDateButton.setDateConfigurator(this::handleDateConfig);
204         myAccountButton.setMenuConfigurator(c -> buildAccountMenu(c, getItem()));
205         myCategoryButton.setMenuConfigurator(c -> buildCategoryMenu(c, getItem()));
206         myPartnerButton.setMenuConfigurator(c -> buildPartnerMenu(c, getItem()));
207         final Map<Boolean, TethysUIIconMapSet<Boolean>> myRecMapSets = MoneyWiseIcon.configureReconciledIconButton(pFactory);
208         myReconciledButton.setIconMapSet(() -> myRecMapSets.get(theReconciledState));
209         final Map<Boolean, TethysUIIconMapSet<MoneyWiseAssetDirection>> myDirMapSets = MoneyWiseIcon.configureDirectionIconButton(pFactory);
210         myDirectionButton.setIconMapSet(() -> myDirMapSets.get(theDirectionState));
211         myAmount.setDeemedCurrency(() -> getItem().getAccount().getCurrency());
212     }
213 
214     /**
215      * Build info subPanel.
216      *
217      * @param pFactory the GUI factory
218      */
219     private void buildInfoPanel(final TethysUIFactory<?> pFactory) {
220         /* Create a new panel */
221         theFieldSet.newPanel(TAB_INFO);
222 
223         /* Allocate fields */
224         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
225         final TethysUIMoneyEditField myAmount = myFields.newMoneyField();
226         final TethysUIStringEditField myComments = myFields.newStringField();
227         final TethysUIStringEditField myReference = myFields.newStringField();
228         final TethysUIRatioEditField myRate = myFields.newRatioField();
229 
230         /* Create the buttons */
231         final TethysUIListButtonField<MoneyWiseTransTag> myTagButton = myFields.newListField();
232 
233         /* Assign the fields to the panel */
234         theFieldSet.addField(MoneyWiseTransInfoClass.PARTNERAMOUNT, myAmount, MoneyWiseTransaction::getPartnerAmount);
235         theFieldSet.addField(MoneyWiseTransInfoClass.COMMENTS, myComments, MoneyWiseTransaction::getComments);
236         theFieldSet.addField(MoneyWiseTransInfoClass.REFERENCE, myReference, MoneyWiseTransaction::getReference);
237         theFieldSet.addField(MoneyWiseTransInfoClass.TRANSTAG, myTagButton, MoneyWiseTransaction::getTransactionTags);
238         theFieldSet.addField(MoneyWiseTransInfoClass.XCHANGERATE, myRate, MoneyWiseTransaction::getExchangeRate);
239 
240         /* Configure the tag button */
241         myTagButton.setSelectables(this::buildTransactionTags);
242 
243         /* Set currency */
244         myAmount.setDeemedCurrency(() -> getItem().getPartner().getCurrency());
245     }
246 
247     /**
248      * Build tax subPanel.
249      *
250      * @param pFactory the GUI factory
251      */
252     private void buildTaxPanel(final TethysUIFactory<?> pFactory) {
253         /* Create a new panel */
254         theFieldSet.newPanel(TAB_TAXES);
255 
256         /* Allocate fields */
257         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
258         final TethysUIMoneyEditField myTaxCredit = myFields.newMoneyField();
259         final TethysUIMoneyEditField myEeNatIns = myFields.newMoneyField();
260         final TethysUIMoneyEditField myErNatIns = myFields.newMoneyField();
261         final TethysUIMoneyEditField myBenefit = myFields.newMoneyField();
262         final TethysUIMoneyEditField myWithheld = myFields.newMoneyField();
263         final TethysUIIntegerEditField myYears = myFields.newIntegerField();
264 
265         /* Assign the fields to the panel */
266         theFieldSet.addField(MoneyWiseTransInfoClass.TAXCREDIT, myTaxCredit, MoneyWiseTransaction::getTaxCredit);
267         theFieldSet.addField(MoneyWiseTransInfoClass.EMPLOYEENATINS, myEeNatIns, MoneyWiseTransaction::getEmployeeNatIns);
268         theFieldSet.addField(MoneyWiseTransInfoClass.EMPLOYERNATINS, myErNatIns, MoneyWiseTransaction::getEmployerNatIns);
269         theFieldSet.addField(MoneyWiseTransInfoClass.DEEMEDBENEFIT, myBenefit, MoneyWiseTransaction::getDeemedBenefit);
270         theFieldSet.addField(MoneyWiseTransInfoClass.WITHHELD, myWithheld, MoneyWiseTransaction::getWithheld);
271         theFieldSet.addField(MoneyWiseTransInfoClass.QUALIFYYEARS, myYears, MoneyWiseTransaction::getYears);
272 
273         /* Set currency */
274         myTaxCredit.setDeemedCurrency(() -> getItem().getAccount().getCurrency());
275         myEeNatIns.setDeemedCurrency(() -> getItem().getAccount().getCurrency());
276         myErNatIns.setDeemedCurrency(() -> getItem().getAccount().getCurrency());
277         myBenefit.setDeemedCurrency(() -> getItem().getAccount().getCurrency());
278         myWithheld.setDeemedCurrency(() -> getItem().getAccount().getCurrency());
279     }
280 
281     /**
282      * Build securities subPanel.
283      *
284      * @param pFactory the GUI factory
285      */
286     private void buildSecuritiesPanel(final TethysUIFactory<?> pFactory) {
287         /* Create a new panel */
288         theFieldSet.newPanel(TAB_SECURITIES);
289 
290         /* Allocate fields */
291         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
292         final TethysUIUnitsEditField myAccountUnits = myFields.newUnitsField();
293         final TethysUIUnitsEditField myPartnerUnits = myFields.newUnitsField();
294         final TethysUIMoneyEditField myCommission = myFields.newMoneyField();
295         final TethysUIPriceEditField myPrice = myFields.newPriceField();
296         final TethysUIRatioEditField myDilution = myFields.newRatioField();
297 
298         /* Assign the fields to the panel */
299         theFieldSet.addField(MoneyWiseTransInfoClass.ACCOUNTDELTAUNITS, myAccountUnits, MoneyWiseTransaction::getAccountDeltaUnits);
300         theFieldSet.addField(MoneyWiseTransInfoClass.PARTNERDELTAUNITS, myPartnerUnits, MoneyWiseTransaction::getPartnerDeltaUnits);
301         theFieldSet.addField(MoneyWiseTransInfoClass.PRICE, myPrice, MoneyWiseTransaction::getPrice);
302         theFieldSet.addField(MoneyWiseTransInfoClass.COMMISSION, myCommission, MoneyWiseTransaction::getCommission);
303         theFieldSet.addField(MoneyWiseTransInfoClass.DILUTION, myDilution, MoneyWiseTransaction::getDilution);
304 
305         /* Set currency */
306         myCommission.setDeemedCurrency(() -> getItem().getAccount().getCurrency());
307         myPrice.setDeemedCurrency(() -> getItem().getAccount().getCurrency());
308     }
309 
310     /**
311      * Build returned subPanel.
312      *
313      * @param pFactory the GUI factory
314      */
315     private void buildReturnedPanel(final TethysUIFactory<?> pFactory) {
316         /* Create a new panel */
317         theFieldSet.newPanel(TAB_RETURNED);
318 
319         /* Allocate fields */
320         final TethysUIFieldFactory myFields = pFactory.fieldFactory();
321         final TethysUIMoneyEditField myReturnedCash = myFields.newMoneyField();
322 
323         /* Create the buttons */
324         final TethysUIScrollButtonField<MoneyWiseTransAsset> myReturnedAccountButton = myFields.newScrollField(MoneyWiseTransAsset.class);
325 
326         /* Assign the fields to the panel */
327         theFieldSet.addField(MoneyWiseTransInfoClass.RETURNEDCASHACCOUNT, myReturnedAccountButton, MoneyWiseTransaction::getReturnedCashAccount);
328         theFieldSet.addField(MoneyWiseTransInfoClass.RETURNEDCASH, myReturnedCash, MoneyWiseTransaction::getReturnedCash);
329 
330         /* Configure the menuBuilders */
331         myReturnedAccountButton.setMenuConfigurator(c -> buildReturnedAccountMenu(c, getItem()));
332 
333         /* Set currency */
334         myReturnedCash.setDeemedCurrency(() -> getItem().getReturnedCashAccount().getCurrency());
335     }
336 
337     @Override
338     public void refreshData() {
339         /* If we have an item */
340         final MoneyWiseTransaction myItem = getItem();
341         if (myItem != null) {
342             final MoneyWiseTransactionList myTrans = getDataList(MoneyWiseBasicDataType.TRANSACTION, MoneyWiseTransactionList.class);
343             setItem(myTrans.findItemById(myItem.getIndexedId()));
344         }
345 
346         /* Make sure that the item is not editable */
347         setEditable(false);
348     }
349 
350     /**
351      * Update editors.
352      *
353      * @param pRange the date range.
354      */
355     public void updateEditors(final OceanusDateRange pRange) {
356         /* Update the range */
357         theRange = pRange;
358     }
359 
360     /**
361      * Handle dateConfig.
362      *
363      * @param pConfig the dateConfig
364      */
365     private void handleDateConfig(final OceanusDateConfig pConfig) {
366         /* Update Date button */
367         pConfig.setEarliestDate(theRange != null
368                 ? theRange.getStart()
369                 : null);
370         pConfig.setLatestDate(theRange != null
371                 ? theRange.getEnd()
372                 : null);
373     }
374 
375     @Override
376     public boolean isDeletable() {
377         return getItem() != null && !getItem().isReconciled();
378     }
379 
380     @Override
381     protected void adjustFields(final boolean isEditable) {
382         /* Access the item */
383         final MoneyWiseTransaction myTrans = getItem();
384         final boolean bIsReconciled = myTrans.isReconciled();
385         final boolean bIsLocked = myTrans.isLocked();
386 
387         /* Determine whether the comments field should be visible */
388         boolean bShowField = isEditable || myTrans.getComments() != null;
389         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.COMMENTS, bShowField);
390 
391         /* Determine whether the reference field should be visible */
392         bShowField = isEditable || myTrans.getReference() != null;
393         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.REFERENCE, bShowField);
394 
395         /* Determine whether the tags field should be visible */
396         bShowField = isEditable || myTrans.getTransactionTags() != null;
397         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.TRANSTAG, bShowField);
398 
399         /* Determine whether the partnerAmount field should be visible */
400         boolean bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.PARTNERAMOUNT);
401         bShowField = bEditField || myTrans.getPartnerAmount() != null;
402         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.PARTNERAMOUNT, bShowField);
403         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.PARTNERAMOUNT, bEditField);
404 
405         /* Determine whether the exchangeRate field should be visible */
406         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.XCHANGERATE);
407         bShowField = bEditField || myTrans.getExchangeRate() != null;
408         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.XCHANGERATE, bShowField);
409         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.XCHANGERATE, bEditField);
410 
411         /* Determine whether the taxCredit field should be visible */
412         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.TAXCREDIT);
413         bShowField = bEditField || myTrans.getTaxCredit() != null;
414         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.TAXCREDIT, bShowField);
415         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.TAXCREDIT, bEditField);
416 
417         /* Determine whether the EeNatIns field should be visible */
418         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.EMPLOYEENATINS);
419         bShowField = bEditField || myTrans.getEmployeeNatIns() != null;
420         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.EMPLOYEENATINS, bShowField);
421         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.EMPLOYEENATINS, bEditField);
422 
423         /* Determine whether the ErnatIns field should be visible */
424         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.EMPLOYERNATINS);
425         bShowField = bEditField || myTrans.getEmployerNatIns() != null;
426         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.EMPLOYERNATINS, bShowField);
427         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.EMPLOYERNATINS, bEditField);
428 
429         /* Determine whether the benefit field should be visible */
430         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.DEEMEDBENEFIT);
431         bShowField = bEditField || myTrans.getDeemedBenefit() != null;
432         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.DEEMEDBENEFIT, bShowField);
433         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.DEEMEDBENEFIT, bEditField);
434 
435         /* Determine whether the donation field should be visible */
436         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.WITHHELD);
437         bShowField = bEditField || myTrans.getWithheld() != null;
438         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.WITHHELD, bShowField);
439         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.WITHHELD, bEditField);
440 
441         /* Determine whether the account units field should be visible */
442         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.ACCOUNTDELTAUNITS);
443         bShowField = bEditField || myTrans.getAccountDeltaUnits() != null;
444         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.ACCOUNTDELTAUNITS, bShowField);
445         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.ACCOUNTDELTAUNITS, bEditField);
446 
447         /* Determine whether the partnerDeltaUnits field should be visible */
448         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.PARTNERDELTAUNITS);
449         bShowField = bEditField || myTrans.getPartnerDeltaUnits() != null;
450         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.PARTNERDELTAUNITS, bShowField);
451         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.PARTNERDELTAUNITS, bEditField);
452 
453         /* Determine whether the price field should be visible */
454         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.PRICE);
455         bShowField = bEditField || myTrans.getPrice() != null;
456         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.PRICE, bShowField);
457         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.PRICE, bEditField);
458 
459         /* Determine whether the commission field should be visible */
460         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.COMMISSION);
461         bShowField = bEditField || myTrans.getCommission() != null;
462         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.COMMISSION, bShowField);
463         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.COMMISSION, bEditField);
464 
465         /* Determine whether the dilution field should be visible */
466         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.DILUTION);
467         bShowField = bEditField || myTrans.getDilution() != null;
468         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.DILUTION, bShowField);
469         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.DILUTION, bEditField);
470 
471         /* Determine whether the returnedAccount field should be visible */
472         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.RETURNEDCASHACCOUNT);
473         bShowField = bEditField || myTrans.getReturnedCashAccount() != null;
474         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.RETURNEDCASHACCOUNT, bShowField);
475         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.RETURNEDCASHACCOUNT, bEditField);
476 
477         /* Determine whether the returnedCash field should be visible */
478         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.RETURNEDCASH);
479         bShowField = bEditField || myTrans.getReturnedCash() != null;
480         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.RETURNEDCASH, bShowField);
481         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.RETURNEDCASH, bEditField);
482 
483         /* Determine whether the years field should be visible */
484         bEditField = isEditable && isEditableField(myTrans, MoneyWiseTransInfoClass.QUALIFYYEARS);
485         bShowField = bEditField || myTrans.getYears() != null;
486         theFieldSet.setFieldVisible(MoneyWiseTransInfoClass.QUALIFYYEARS, bShowField);
487         theFieldSet.setFieldEditable(MoneyWiseTransInfoClass.QUALIFYYEARS, bEditField);
488 
489         /* Determine whether the reconciled field should be visible */
490         final boolean bShowReconciled = isEditable || bIsReconciled;
491         theReconciledState = bIsLocked;
492         theDirectionState = bIsReconciled;
493         theFieldSet.setFieldVisible(MoneyWiseBasicResource.TRANSACTION_RECONCILED, bShowReconciled);
494         theFieldSet.setFieldEditable(MoneyWiseBasicResource.TRANSACTION_RECONCILED, isEditable && !bIsLocked);
495 
496         /* Determine basic editing */
497         final boolean canEdit = isEditable && !bIsReconciled;
498         final boolean needsNullAmount = myTrans.needsNullAmount();
499         theFieldSet.setFieldEditable(MoneyWiseBasicResource.TRANSACTION_DIRECTION, canEdit && myTrans.canSwitchDirection());
500         theFieldSet.setFieldEditable(MoneyWiseBasicResource.TRANSACTION_ACCOUNT, canEdit);
501         theFieldSet.setFieldEditable(MoneyWiseBasicResource.TRANSACTION_PARTNER, canEdit);
502         theFieldSet.setFieldEditable(MoneyWiseBasicDataType.TRANSCATEGORY, canEdit);
503         theFieldSet.setFieldEditable(MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE, canEdit);
504         theFieldSet.setFieldEditable(MoneyWiseBasicResource.TRANSACTION_AMOUNT, canEdit && !needsNullAmount);
505         theFieldSet.setFieldVisible(MoneyWiseBasicResource.TRANSACTION_AMOUNT, !needsNullAmount);
506 
507         /* Set the range for the dateButton */
508         final MoneyWiseValidateTransaction myBuilder = (MoneyWiseValidateTransaction) myTrans.getList().getValidator();
509         theRange = myBuilder.getRange();
510     }
511 
512     /**
513      * Is the field editable?
514      *
515      * @param pTrans the transaction
516      * @param pField the field class
517      * @return true/false
518      */
519     public static boolean isEditableField(final MoneyWiseTransaction pTrans,
520                                           final MoneyWiseTransInfoClass pField) {
521         /* Access the infoSet */
522         final MoneyWiseTransInfoSet myInfoSet = pTrans.getInfoSet();
523 
524         /* If the transaction is reconciled */
525         if (Boolean.TRUE.equals(pTrans.isReconciled())) {
526             /* Only allow editing of metaData */
527             return myInfoSet.isMetaData(pField);
528         }
529 
530         /* Check whether the field is available */
531         final MoneyWiseValidateTransaction myValidator = (MoneyWiseValidateTransaction) pTrans.getList().getValidator();
532         final MetisFieldRequired isRequired = myValidator.isClassRequired(pTrans, pField);
533         return !isRequired.equals(MetisFieldRequired.NOTALLOWED);
534     }
535 
536     @SuppressWarnings("unchecked")
537     @Override
538     protected void updateField(final PrometheusFieldSetEvent pUpdate) throws OceanusException {
539         /* Access the field */
540         final MetisDataFieldId myField = pUpdate.getFieldId();
541         final MoneyWiseTransaction myTrans = getItem();
542         final MoneyWiseValidateTransaction myBuilder = (MoneyWiseValidateTransaction) myTrans.getList().getValidator();
543 
544         /* Process updates */
545         if (MoneyWiseBasicResource.MONEYWISEDATA_FIELD_DATE.equals(myField)) {
546             /* Update the Date */
547             myTrans.setDate(pUpdate.getValue(OceanusDate.class));
548         } else if (MoneyWiseBasicResource.TRANSACTION_AMOUNT.equals(myField)) {
549             /* Update the Amount */
550             myTrans.setAmount(pUpdate.getValue(OceanusMoney.class));
551             myBuilder.autoCorrect(myTrans);
552         } else if (MoneyWiseBasicResource.TRANSACTION_ACCOUNT.equals(myField)) {
553             /* Update the Account */
554             myTrans.setAccount(resolveAsset(pUpdate.getValue(MoneyWiseTransAsset.class)));
555             myBuilder.autoCorrect(myTrans);
556         } else if (MoneyWiseBasicResource.TRANSACTION_DIRECTION.equals(myField)) {
557             /* Update the Direction */
558             myTrans.switchDirection();
559             myBuilder.autoCorrect(myTrans);
560         } else if (MoneyWiseBasicResource.TRANSACTION_PARTNER.equals(myField)) {
561             /* Update the Partner */
562             myTrans.setPartner(resolveAsset(pUpdate.getValue(MoneyWiseTransAsset.class)));
563             myBuilder.autoCorrect(myTrans);
564         } else if (MoneyWiseBasicDataType.TRANSCATEGORY.equals(myField)) {
565             /* Update the Category */
566             myTrans.setCategory(pUpdate.getValue(MoneyWiseTransCategory.class));
567             myBuilder.autoCorrect(myTrans);
568         } else if (MoneyWiseBasicResource.TRANSACTION_RECONCILED.equals(myField)) {
569             /* Update the Reconciled indication */
570             myTrans.setReconciled(pUpdate.getValue(Boolean.class));
571         } else if (MoneyWiseTransInfoClass.COMMENTS.equals(myField)) {
572             /* Update the Comments */
573             myTrans.setComments(pUpdate.getValue(String.class));
574         } else if (MoneyWiseTransInfoClass.REFERENCE.equals(myField)) {
575             /* Update the Reference */
576             myTrans.setReference(pUpdate.getValue(String.class));
577         } else if (MoneyWiseTransInfoClass.TRANSTAG.equals(myField)) {
578             /* Update the Tag indication */
579             myTrans.setTransactionTags(pUpdate.getValue(List.class));
580         } else if (MoneyWiseTransInfoClass.PARTNERAMOUNT.equals(myField)) {
581             /* Update the PartnerAmount */
582             myTrans.setPartnerAmount(pUpdate.getValue(OceanusMoney.class));
583         } else if (MoneyWiseTransInfoClass.XCHANGERATE.equals(myField)) {
584             /* Update the ExchangeRate */
585             myTrans.setExchangeRate(pUpdate.getValue(OceanusRatio.class));
586         } else if (MoneyWiseTransInfoClass.ACCOUNTDELTAUNITS.equals(myField)) {
587             /* Update the AccountDeltaUnits */
588             myTrans.setAccountDeltaUnits(pUpdate.getValue(OceanusUnits.class));
589         } else if (MoneyWiseTransInfoClass.PARTNERDELTAUNITS.equals(myField)) {
590             /* Update the PartnerDeltaUnits */
591             myTrans.setPartnerDeltaUnits(pUpdate.getValue(OceanusUnits.class));
592         } else if (MoneyWiseTransInfoClass.PRICE.equals(myField)) {
593             /* Update the Price */
594             myTrans.setPrice(pUpdate.getValue(OceanusPrice.class));
595         } else if (MoneyWiseTransInfoClass.COMMISSION.equals(myField)) {
596             /* Update the Commission */
597             myTrans.setCommission(pUpdate.getValue(OceanusMoney.class));
598         } else if (MoneyWiseTransInfoClass.DILUTION.equals(myField)) {
599             /* Update the Dilution */
600             myTrans.setDilution(pUpdate.getValue(OceanusRatio.class));
601         } else if (MoneyWiseTransInfoClass.QUALIFYYEARS.equals(myField)) {
602             /* Update the QualifyYears */
603             myTrans.setYears(pUpdate.getValue(Integer.class));
604         } else if (MoneyWiseTransInfoClass.RETURNEDCASHACCOUNT.equals(myField)) {
605             /* Update the ReturnedCashAccount */
606             myTrans.setReturnedCashAccount(pUpdate.getValue(MoneyWiseTransAsset.class));
607             myBuilder.autoCorrect(myTrans);
608         } else if (MoneyWiseTransInfoClass.RETURNEDCASH.equals(myField)) {
609             /* Update the ReturnedCash */
610             myTrans.setReturnedCash(pUpdate.getValue(OceanusMoney.class));
611         } else if (MoneyWiseTransInfoClass.TAXCREDIT.equals(myField)) {
612             /* Update the TaxCredit */
613             myTrans.setTaxCredit(pUpdate.getValue(OceanusMoney.class));
614         } else if (MoneyWiseTransInfoClass.EMPLOYEENATINS.equals(myField)) {
615             /* Update the EmployeeNatIns */
616             myTrans.setEmployeeNatIns(pUpdate.getValue(OceanusMoney.class));
617         } else if (MoneyWiseTransInfoClass.EMPLOYERNATINS.equals(myField)) {
618             /* Update the EmployerNayIns */
619             myTrans.setEmployerNatIns(pUpdate.getValue(OceanusMoney.class));
620         } else if (MoneyWiseTransInfoClass.DEEMEDBENEFIT.equals(myField)) {
621             /* Update the Benefit */
622             myTrans.setDeemedBenefit(pUpdate.getValue(OceanusMoney.class));
623         } else if (MoneyWiseTransInfoClass.WITHHELD.equals(myField)) {
624             /* Update the Withheld */
625             myTrans.setWithheld(pUpdate.getValue(OceanusMoney.class));
626         }
627     }
628 
629     @Override
630     protected void declareGoToItems(final boolean pUpdates) {
631         /* Access the item */
632         final MoneyWiseTransaction myItem = getItem();
633 
634         /* Access the analysis and the relevant filters */
635         final MoneyWiseAnalysis myAnalysis = theAnalysisSelect.getAnalysis();
636         final OceanusDateRange myDateRange = theAnalysisSelect.getRange();
637         final MoneyWiseTransactionFilters myFilters = new MoneyWiseTransactionFilters(myAnalysis, myDateRange, myItem);
638 
639         /* Remove the current filter */
640         final MoneyWiseAnalysisFilter<?, ?> myCurrent = theAnalysisSelect.getFilter();
641         myFilters.remove(myCurrent);
642 
643         /* Loop through the filters */
644         final Iterator<MoneyWiseAnalysisFilter<?, ?>> myIterator = myFilters.iterator();
645         while (myIterator.hasNext()) {
646             final MoneyWiseAnalysisFilter<?, ?> myFilter = myIterator.next();
647 
648             /* declare it */
649             declareGoToFilter(myFilter);
650         }
651 
652         /* If we have not had updates */
653         if (!pUpdates) {
654             /* Allow GoTo different panels */
655             buildAssetGoTo(myItem.getAccount());
656             buildAssetGoTo(myItem.getPartner());
657             declareGoToItem(myItem.getCategory());
658             buildAssetGoTo(myItem.getReturnedCashAccount());
659         }
660     }
661 
662     /**
663      * Handle goto declarations for TransactionAssets.
664      *
665      * @param pAsset the asset
666      */
667     private void buildAssetGoTo(final MoneyWiseTransAsset pAsset) {
668         if (pAsset instanceof MoneyWiseSecurityHolding) {
669             /* Build menu Items for Portfolio and Security */
670             final MoneyWiseSecurityHolding myHolding = (MoneyWiseSecurityHolding) pAsset;
671             declareGoToItem(myHolding.getPortfolio());
672             declareGoToItem(myHolding.getSecurity());
673         } else if (pAsset instanceof MoneyWiseAssetBase) {
674             declareGoToItem((MoneyWiseAssetBase) pAsset);
675         }
676     }
677 
678     /**
679      * Resolve Asset.
680      *
681      * @param pAsset the asset to resolve
682      * @return the resolved asset
683      */
684     public static MoneyWiseTransAsset resolveAsset(final MoneyWiseTransAsset pAsset) {
685         /* If this is a security holding */
686         if (pAsset instanceof MoneyWiseSecurityHolding) {
687             /* declare holding via map */
688             final MoneyWiseSecurityHolding myHolding = (MoneyWiseSecurityHolding) pAsset;
689             final MoneyWisePortfolio myPortfolio = myHolding.getPortfolio();
690             final MoneyWiseSecurity mySecurity = myHolding.getSecurity();
691             final MoneyWiseDataSet myData = myPortfolio.getDataSet();
692             final MoneyWiseSecurityHoldingMap myMap = myData.getPortfolios().getSecurityHoldingsMap();
693             return myMap.declareHolding(myPortfolio, mySecurity);
694         }
695 
696         /* Just return the asset */
697         return pAsset;
698     }
699 
700     /**
701      * Build the account menu for an item.
702      *
703      * @param pMenu  the menu
704      * @param pTrans the transaction to build for
705      */
706     public void buildAccountMenu(final TethysUIScrollMenu<MoneyWiseTransAsset> pMenu,
707                                  final MoneyWiseTransaction pTrans) {
708         /* Clear the menu */
709         pMenu.removeAllItems();
710 
711         /* Add possible items */
712         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.DEPOSIT, MoneyWiseDepositList.class), true, pTrans);
713         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.CASH, MoneyWiseCashList.class), true, pTrans);
714         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.LOAN, MoneyWiseLoanList.class), true, pTrans);
715         buildHoldingMenu(pMenu, true, pTrans);
716         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.PORTFOLIO, MoneyWisePortfolioList.class), true, pTrans);
717     }
718 
719     /**
720      * Build the partner menu for an item.
721      *
722      * @param pMenu  the menu
723      * @param pTrans the transaction to build for
724      */
725     public void buildPartnerMenu(final TethysUIScrollMenu<MoneyWiseTransAsset> pMenu,
726                                  final MoneyWiseTransaction pTrans) {
727         /* Clear the menu */
728         pMenu.removeAllItems();
729 
730         /* Add possible items */
731         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.DEPOSIT, MoneyWiseDepositList.class), false, pTrans);
732         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.CASH, MoneyWiseCashList.class), false, pTrans);
733         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.LOAN, MoneyWiseLoanList.class), false, pTrans);
734         buildHoldingMenu(pMenu, false, pTrans);
735         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.PORTFOLIO, MoneyWisePortfolioList.class), false, pTrans);
736         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.PAYEE, MoneyWisePayeeList.class), false, pTrans);
737     }
738 
739     /**
740      * Build the asset menu for an item.
741      *
742      * @param <T>        the Asset type
743      * @param pMenu      the menu
744      * @param pIsAccount is this item the account rather than partner
745      * @param pList      the asset list
746      * @param pTrans     the transaction to build for
747      */
748     private static <T extends MoneyWiseAssetBase> void buildAssetMenu(final TethysUIScrollMenu<MoneyWiseTransAsset> pMenu,
749                                                                       final MoneyWiseAssetBaseList<T> pList,
750                                                                       final boolean pIsAccount,
751                                                                       final MoneyWiseTransaction pTrans) {
752         /* Record active item */
753         final MoneyWiseTransAsset myAccount = pTrans.getAccount();
754         final MoneyWiseTransCategory myCategory = pTrans.getCategory();
755         final MoneyWiseDataValidatorTrans<?> myValidator = pTrans.getList().getValidator();
756         final MoneyWiseTransAsset myCurr = pIsAccount
757                 ? myAccount
758                 : pTrans.getPartner();
759         TethysUIScrollItem<MoneyWiseTransAsset> myActive = null;
760         TethysUIScrollSubMenu<MoneyWiseTransAsset> myMenu = null;
761 
762         /* Loop through the available values */
763         final Iterator<T> myIterator = pList.iterator();
764         while (myIterator.hasNext()) {
765             final T myAsset = myIterator.next();
766 
767             /* Only process non-deleted/non-closed items */
768             boolean bIgnore = myAsset.isDeleted() || myAsset.isClosed();
769 
770             /* Check whether the asset is allowable for the owner */
771             bIgnore |= !(pIsAccount
772                     ? myValidator.isValidAccount(myAsset)
773                     : myValidator.isValidPartner(myAccount, myCategory, myAsset));
774             if (bIgnore) {
775                 continue;
776             }
777 
778             /* If this the first item */
779             if (myMenu == null) {
780                 /* Create a new subMenu and add it to the popUp */
781                 myMenu = pMenu.addSubMenu(pList.getItemType().getItemName());
782             }
783 
784             /* Create a new MenuItem and add it to the popUp */
785             final TethysUIScrollItem<MoneyWiseTransAsset> myItem = myMenu.getSubMenu().addItem(myAsset);
786 
787             /* If this is the active category */
788             if (myAsset.equals(myCurr)) {
789                 /* Record it */
790                 myActive = myItem;
791             }
792         }
793 
794         /* Ensure active item is visible */
795         if (myActive != null) {
796             myActive.scrollToItem();
797         }
798     }
799 
800     /**
801      * Build the holding asset menu for an item.
802      *
803      * @param pMenu      the menu
804      * @param pIsAccount is this item the account rather than partner
805      * @param pTrans     the transaction to build for
806      */
807     private static void buildHoldingMenu(final TethysUIScrollMenu<MoneyWiseTransAsset> pMenu,
808                                          final boolean pIsAccount,
809                                          final MoneyWiseTransaction pTrans) {
810         /* Record active item */
811         final MoneyWiseTransAsset myAccount = pTrans.getAccount();
812         final MoneyWiseTransCategory myCategory = pTrans.getCategory();
813         final MoneyWiseDataValidatorTrans<?> myValidator = pTrans.getList().getValidator();
814         final MoneyWiseTransAsset myCurr = pIsAccount
815                 ? myAccount
816                 : pTrans.getPartner();
817         TethysUIScrollItem<MoneyWiseTransAsset> myActive = null;
818         TethysUIScrollSubMenu<MoneyWiseTransAsset> myMenu = null;
819 
820         /* Access Portfolios and Holdings Map */
821         final MoneyWiseDataSet myData = pTrans.getDataSet();
822         final MoneyWisePortfolioList myPortfolios = myData.getPortfolios();
823         final MoneyWiseSecurityHoldingMap myMap = myPortfolios.getSecurityHoldingsMap();
824 
825         /* Loop through the Portfolios */
826         final Iterator<MoneyWisePortfolio> myPortIterator = myPortfolios.iterator();
827         while (myPortIterator.hasNext()) {
828             final MoneyWisePortfolio myPortfolio = myPortIterator.next();
829             TethysUIScrollSubMenu<MoneyWiseTransAsset> myCoreMenu = null;
830 
831             /* Ignore deleted or closed */
832             if (myPortfolio.isDeleted()
833                     || Boolean.TRUE.equals(myPortfolio.isClosed())) {
834                 continue;
835             }
836 
837             /* Look for existing and new holdings */
838             final Iterator<MoneyWiseSecurityHolding> myExistIterator = myMap.existingIterator(myPortfolio);
839             final Iterator<MoneyWiseSecurityHolding> myNewIterator = myMap.newIterator(myPortfolio);
840             if ((myExistIterator != null) || (myNewIterator != null)) {
841                 /* If there are existing elements */
842                 if (myExistIterator != null) {
843                     /* Loop through them */
844                     while (myExistIterator.hasNext()) {
845                         final MoneyWiseSecurityHolding myHolding = myExistIterator.next();
846                         final MoneyWiseSecurity mySecurity = myHolding.getSecurity();
847 
848                         /* Check whether the asset is allowable for the owner */
849                         final boolean bIgnore = !(pIsAccount
850                                 ? myValidator.isValidAccount(myHolding)
851                                 : myValidator.isValidPartner(myAccount, myCategory, myHolding));
852                         if (bIgnore) {
853                             continue;
854                         }
855 
856                         /* Ensure that hierarchy is created */
857                         if (myMenu == null) {
858                             /* Create a new JMenu and add it to the popUp */
859                             myMenu = pMenu.addSubMenu(MoneyWiseAssetType.SECURITYHOLDING.toString());
860                         }
861                         if (myCoreMenu == null) {
862                             /* Create a new JMenu and add it to the popUp */
863                             myCoreMenu = myMenu.getSubMenu().addSubMenu(myPortfolio.getName());
864                         }
865 
866                         /* Add the item to the menu */
867                         final TethysUIScrollItem<MoneyWiseTransAsset> myItem = myCoreMenu.getSubMenu().addItem(myHolding, mySecurity.getName());
868 
869                         /* If this is the active holding */
870                         if (mySecurity.equals(myCurr)) {
871                             /* Record it */
872                             myActive = myItem;
873                         }
874                     }
875                 }
876 
877                 /* If there are new elements */
878                 if (myNewIterator != null) {
879                     /* Loop through them */
880                     TethysUIScrollSubMenu<MoneyWiseTransAsset> mySubMenu = null;
881                     while (myNewIterator.hasNext()) {
882                         final MoneyWiseSecurityHolding myHolding = myNewIterator.next();
883                         final MoneyWiseSecurity mySecurity = myHolding.getSecurity();
884 
885                         /* Check whether the asset is allowable for the owner */
886                         final boolean bIgnore = !(pIsAccount
887                                 ? myValidator.isValidAccount(myHolding)
888                                 : myValidator.isValidPartner(myAccount, myCategory, myHolding));
889                         if (bIgnore) {
890                             continue;
891                         }
892 
893                         /* Ensure that hierarchy is created */
894                         if (myMenu == null) {
895                             /* Create a new subMenu and add it to the popUp */
896                             myMenu = pMenu.addSubMenu(MoneyWiseAssetType.SECURITYHOLDING.toString());
897                         }
898                         if (myCoreMenu == null) {
899                             /* Create a new subMenu and add it to the popUp */
900                             myCoreMenu = myMenu.getSubMenu().addSubMenu(myPortfolio.getName());
901                         }
902                         if (mySubMenu == null) {
903                             /* Create a new subMenu */
904                             mySubMenu = myCoreMenu.getSubMenu().addSubMenu(MoneyWiseSecurityHolding.SECURITYHOLDING_NEW);
905                         }
906 
907                         /* Add the item to the menu */
908                         mySubMenu.getSubMenu().addItem(myHolding, mySecurity.getName());
909                     }
910                 }
911             }
912         }
913 
914         /* Ensure active item is visible */
915         if (myActive != null) {
916             myActive.scrollToItem();
917         }
918     }
919 
920     /**
921      * Build the category menu for an item.
922      *
923      * @param pMenu  the menu
924      * @param pTrans the transaction to build for
925      */
926     public void buildCategoryMenu(final TethysUIScrollMenu<MoneyWiseTransCategory> pMenu,
927                                   final MoneyWiseTransaction pTrans) {
928         /* Clear the menu */
929         pMenu.removeAllItems();
930 
931         /* Record active item */
932         final MoneyWiseTransAsset myAccount = pTrans.getAccount();
933         final MoneyWiseTransCategory myCurr = pTrans.getCategory();
934         TethysUIScrollItem<MoneyWiseTransCategory> myActive = null;
935         TethysUIScrollItem<MoneyWiseTransCategory> myItem;
936 
937         /* Create a simple map for top-level categories */
938         final Map<String, TethysUIScrollSubMenu<MoneyWiseTransCategory>> myMap = new HashMap<>();
939 
940         /* Access Categories */
941         final MoneyWiseTransCategoryList myCategories = getDataList(MoneyWiseBasicDataType.TRANSCATEGORY, MoneyWiseTransCategoryList.class);
942         final MoneyWiseDataValidatorTrans<?> myValidator = pTrans.getList().getValidator();
943 
944         /* Loop through the available category values */
945         final Iterator<MoneyWiseTransCategory> myIterator = myCategories.iterator();
946         while (myIterator.hasNext()) {
947             final MoneyWiseTransCategory myCategory = myIterator.next();
948 
949             /* Only process non-deleted low-level items */
950             final MoneyWiseTransCategoryClass myClass = myCategory.getCategoryTypeClass();
951             boolean bIgnore = myCategory.isDeleted() || myClass.canParentCategory();
952 
953             /* Check whether the category is allowable for the owner */
954             bIgnore |= !myValidator.isValidCategory(myAccount, myCategory);
955             if (bIgnore) {
956                 continue;
957             }
958 
959             /* Determine parent */
960             final MoneyWiseTransCategory myParent = myCategory.getParentCategory();
961 
962             /* If we have a parent */
963             if (myParent != null) {
964                 final String myParentName = myParent.getName();
965                 final TethysUIScrollSubMenu<MoneyWiseTransCategory> myMenu = myMap.computeIfAbsent(myParentName, pMenu::addSubMenu);
966 
967                 /* Create a new MenuItem and add it to the subMenu */
968                 myItem = myMenu.getSubMenu().addItem(myCategory, myCategory.getSubCategory());
969 
970             } else {
971                 /* Create a new MenuItem and add it to the popUp */
972                 myItem = pMenu.addItem(myCategory);
973             }
974 
975             /* If this is the active category */
976             if (myCategory.equals(myCurr)) {
977                 /* Record it */
978                 myActive = myItem;
979             }
980         }
981 
982         /* Ensure active item is visible */
983         if (myActive != null) {
984             myActive.scrollToItem();
985         }
986     }
987 
988     /**
989      * Build the ReturnedAccount menu for an item.
990      *
991      * @param pMenu  the menu
992      * @param pTrans the transaction to build for
993      */
994     public void buildReturnedAccountMenu(final TethysUIScrollMenu<MoneyWiseTransAsset> pMenu,
995                                          final MoneyWiseTransaction pTrans) {
996         /* Clear the menu */
997         pMenu.removeAllItems();
998 
999         /* Add possible items */
1000         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.DEPOSIT, MoneyWiseDepositList.class), false, pTrans);
1001         buildAssetMenu(pMenu, getDataList(MoneyWiseBasicDataType.PORTFOLIO, MoneyWisePortfolioList.class), false, pTrans);
1002     }
1003 
1004     /**
1005      * Build the possible TransactionTag list.
1006      *
1007      * @return the transaction tag iterator
1008      */
1009     public Iterator<MoneyWiseTransTag> buildTransactionTags() {
1010         /* Create a list */
1011         final List<MoneyWiseTransTag> myList = new ArrayList<>();
1012 
1013         /* Loop through the TransactionTags */
1014         final Iterator<MoneyWiseTransTag> myIterator = getItem().getDataSet().getTransactionTags().iterator();
1015         while (myIterator.hasNext()) {
1016             final MoneyWiseTransTag myTag = myIterator.next();
1017 
1018             /* Add to list if available */
1019             if (!myTag.isDeleted()) {
1020                 myList.add(myTag);
1021             }
1022         }
1023 
1024         /* Return the iterator */
1025         return myList.iterator();
1026     }
1027 }