MoneyWiseCategoryPanel.java
/*
* MoneyWise: Finance Application
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.moneywise.ui.panel;
import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
import io.github.tonywasher.joceanus.oceanus.event.OceanusEvent;
import io.github.tonywasher.joceanus.oceanus.event.OceanusEventManager;
import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar;
import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar.OceanusEventProvider;
import io.github.tonywasher.joceanus.oceanus.profile.OceanusProfile;
import io.github.tonywasher.joceanus.metis.ui.MetisErrorPanel;
import io.github.tonywasher.joceanus.metis.viewer.MetisViewerEntry;
import io.github.tonywasher.joceanus.metis.viewer.MetisViewerManager;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseCashCategory;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDepositCategory;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseLoanCategory;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseRegion;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransCategory;
import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransTag;
import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseGoToId;
import io.github.tonywasher.joceanus.moneywise.ui.MoneyWiseUIResource;
import io.github.tonywasher.joceanus.moneywise.views.MoneyWiseView;
import io.github.tonywasher.joceanus.prometheus.ui.PrometheusActionButtons;
import io.github.tonywasher.joceanus.prometheus.ui.PrometheusGoToEvent;
import io.github.tonywasher.joceanus.prometheus.views.PrometheusDataEvent;
import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
import io.github.tonywasher.joceanus.prometheus.views.PrometheusUIEvent;
import io.github.tonywasher.joceanus.prometheus.views.PrometheusViewerEntryId;
import io.github.tonywasher.joceanus.tethys.api.base.TethysUIComponent;
import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
import io.github.tonywasher.joceanus.tethys.api.button.TethysUIScrollButtonManager;
import io.github.tonywasher.joceanus.tethys.api.control.TethysUILabel;
import io.github.tonywasher.joceanus.tethys.api.factory.TethysUIFactory;
import io.github.tonywasher.joceanus.tethys.api.menu.TethysUIScrollMenu;
import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIBorderPaneManager;
import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIBoxPaneManager;
import io.github.tonywasher.joceanus.tethys.api.pane.TethysUICardPaneManager;
import io.github.tonywasher.joceanus.tethys.api.pane.TethysUIPaneFactory;
/**
* Category panel.
*/
public class MoneyWiseCategoryPanel
implements OceanusEventProvider<PrometheusDataEvent>, TethysUIComponent {
/**
* Text for DataEntry Title.
*/
private static final String NLS_DATAENTRY = MoneyWiseUIResource.CATEGORY_DATAENTRY.getValue();
/**
* Text for Selection Title.
*/
private static final String NLS_SELECT = MoneyWiseUIResource.CATEGORY_TITLE_SELECT.getValue();
/**
* Text for Selection Prompt.
*/
private static final String NLS_DATA = MoneyWiseUIResource.CATEGORY_PROMPT_SELECT.getValue();
/**
* The Event Manager.
*/
private final OceanusEventManager<PrometheusDataEvent> theEventManager;
/**
* The Data View.
*/
private final MoneyWiseView theView;
/**
* The Panel.
*/
private final TethysUIBorderPaneManager thePanel;
/**
* The select button.
*/
private final TethysUIScrollButtonManager<PanelName> theSelectButton;
/**
* The card panel.
*/
private final TethysUICardPaneManager<TethysUIComponent> theCardPanel;
/**
* The select panel.
*/
private final TethysUIBorderPaneManager theSelectPanel;
/**
* The filter card panel.
*/
private final TethysUICardPaneManager<TethysUIComponent> theFilterCardPanel;
/**
* Deposit Categories Table.
*/
private final MoneyWiseDepositCategoryTable theDepositTable;
/**
* Cash Categories Table.
*/
private final MoneyWiseCashCategoryTable theCashTable;
/**
* Loan Categories Table.
*/
private final MoneyWiseLoanCategoryTable theLoanTable;
/**
* Transaction Categories Table.
*/
private final MoneyWiseTransCategoryTable theEventTable;
/**
* Event Tags Table.
*/
private final MoneyWiseTransTagTable theTagTable;
/**
* Regions Table.
*/
private final MoneyWiseRegionTable theRegionTable;
/**
* The UpdateSet.
*/
private final PrometheusEditSet theEditSet;
/**
* The viewer entry.
*/
private final MetisViewerEntry theViewerEntry;
/**
* The action buttons panel.
*/
private final PrometheusActionButtons theActionButtons;
/**
* The error panel.
*/
private final MetisErrorPanel theError;
/**
* Are we refreshing?
*/
private boolean isRefreshing;
/**
* The active panel.
*/
private PanelName theActive;
/**
* Constructor.
*
* @param pView the data view
*/
MoneyWiseCategoryPanel(final MoneyWiseView pView) {
/* Store details */
theView = pView;
/* Access GUI Factory */
final TethysUIFactory<?> myFactory = pView.getGuiFactory();
final MetisViewerManager myViewer = pView.getViewerManager();
/* Create the event manager */
theEventManager = new OceanusEventManager<>();
/* Build the Update set */
theEditSet = new PrometheusEditSet(pView);
/* Create the Panel */
final TethysUIPaneFactory myPanes = myFactory.paneFactory();
thePanel = myPanes.newBorderPane();
/* Create the top level viewer entry for this view */
final MetisViewerEntry mySection = pView.getViewerEntry(PrometheusViewerEntryId.MAINTENANCE);
theViewerEntry = myViewer.newEntry(mySection, NLS_DATAENTRY);
theViewerEntry.setTreeObject(theEditSet);
/* Create the error panel */
theError = pView.getToolkit().getToolkit().newErrorPanel(theViewerEntry);
/* Create the action buttons panel */
theActionButtons = new PrometheusActionButtons(myFactory, theEditSet);
/* Create the table panels */
theDepositTable = new MoneyWiseDepositCategoryTable(pView, theEditSet, theError);
theCashTable = new MoneyWiseCashCategoryTable(pView, theEditSet, theError);
theLoanTable = new MoneyWiseLoanCategoryTable(pView, theEditSet, theError);
theEventTable = new MoneyWiseTransCategoryTable(pView, theEditSet, theError);
theTagTable = new MoneyWiseTransTagTable(pView, theEditSet, theError);
theRegionTable = new MoneyWiseRegionTable(pView, theEditSet, theError);
/* Create selection button and label */
final TethysUILabel myLabel = myFactory.controlFactory().newLabel(NLS_DATA);
theSelectButton = myFactory.buttonFactory().newScrollButton(PanelName.class);
buildSelectMenu();
/* Create the card panel */
theCardPanel = myPanes.newCardPane();
/* Add to the card panels */
theCardPanel.addCard(PanelName.DEPOSITS.toString(), theDepositTable);
theCardPanel.addCard(PanelName.CASH.toString(), theCashTable);
theCardPanel.addCard(PanelName.LOANS.toString(), theLoanTable);
theCardPanel.addCard(PanelName.EVENTS.toString(), theEventTable);
theCardPanel.addCard(PanelName.EVENTTAGS.toString(), theTagTable);
theCardPanel.addCard(PanelName.REGIONS.toString(), theRegionTable);
theActive = PanelName.DEPOSITS;
theSelectButton.setValue(theActive);
/* Create the card panel */
theFilterCardPanel = myPanes.newCardPane();
/* Add to the card panels */
theFilterCardPanel.addCard(PanelName.DEPOSITS.toString(), theDepositTable.getFilterPanel());
theFilterCardPanel.addCard(PanelName.CASH.toString(), theCashTable.getFilterPanel());
theFilterCardPanel.addCard(PanelName.LOANS.toString(), theLoanTable.getFilterPanel());
theFilterCardPanel.addCard(PanelName.EVENTS.toString(), theEventTable.getFilterPanel());
theFilterCardPanel.addCard(PanelName.EVENTTAGS.toString(), theTagTable.getFilterPanel());
theFilterCardPanel.addCard(PanelName.REGIONS.toString(), theRegionTable.getFilterPanel());
/* Create the select prompt */
final TethysUIBoxPaneManager mySelect = myPanes.newHBoxPane();
mySelect.addNode(myLabel);
mySelect.addNode(theSelectButton);
/* Create the selection panel */
theSelectPanel = myPanes.newBorderPane();
theSelectPanel.setBorderTitle(NLS_SELECT);
theSelectPanel.setWest(mySelect);
theSelectPanel.setCentre(theFilterCardPanel);
/* Create the header panel */
final TethysUIBorderPaneManager myHeader = myPanes.newBorderPane();
myHeader.setCentre(theSelectPanel);
myHeader.setNorth(theError);
myHeader.setEast(theActionButtons);
/* Now define the panel */
thePanel.setNorth(myHeader);
thePanel.setCentre(theCardPanel);
/* Hide the action buttons initially */
theActionButtons.setVisible(false);
/* Create the listeners */
theSelectButton.getEventRegistrar().addEventListener(TethysUIEvent.NEWVALUE, e -> handleSelection());
theError.getEventRegistrar().addEventListener(e -> handleErrorPane());
theActionButtons.getEventRegistrar().addEventListener(this::handleActionButtons);
setChildListeners(theDepositTable.getEventRegistrar());
setChildListeners(theCashTable.getEventRegistrar());
setChildListeners(theLoanTable.getEventRegistrar());
setChildListeners(theEventTable.getEventRegistrar());
setChildListeners(theTagTable.getEventRegistrar());
setChildListeners(theRegionTable.getEventRegistrar());
}
@Override
public TethysUIComponent getUnderlying() {
return thePanel;
}
@Override
public OceanusEventRegistrar<PrometheusDataEvent> getEventRegistrar() {
return theEventManager.getEventRegistrar();
}
/**
* setChildListeners.
*
* @param pRegistrar the registrar
*/
private void setChildListeners(final OceanusEventRegistrar<PrometheusDataEvent> pRegistrar) {
pRegistrar.addEventListener(PrometheusDataEvent.ADJUSTVISIBILITY, e -> {
if (!isRefreshing) {
setVisibility();
}
});
pRegistrar.addEventListener(PrometheusDataEvent.GOTOWINDOW, this::handleGoToEvent);
}
@Override
public void setEnabled(final boolean pEnabled) {
theSelectButton.setEnabled(pEnabled);
theCardPanel.setEnabled(pEnabled);
theFilterCardPanel.setEnabled(pEnabled);
}
@Override
public void setVisible(final boolean pVisible) {
thePanel.setVisible(pVisible);
}
/**
* Build select menu.
*/
private void buildSelectMenu() {
/* Create builder */
final TethysUIScrollMenu<PanelName> myMenu = theSelectButton.getMenu();
/* Loop through the panels */
for (PanelName myPanel : PanelName.values()) {
/* Create a new MenuItem for the panel */
myMenu.addItem(myPanel);
}
}
/**
* Refresh data.
*
* @throws OceanusException on error
*/
public void refreshData() throws OceanusException {
/* Obtain the active profile */
OceanusProfile myTask = theView.getActiveTask();
myTask = myTask.startTask("Categories");
/* Note that we are refreshing */
isRefreshing = true;
theEditSet.setDataSet(theView.getData());
/* Refresh the tables */
theDepositTable.refreshData();
theCashTable.refreshData();
theLoanTable.refreshData();
theEventTable.refreshData();
theTagTable.refreshData();
theRegionTable.refreshData();
/* Clear refreshing flag */
isRefreshing = false;
setVisibility();
/* Touch the updateSet */
theViewerEntry.setTreeObject(theEditSet);
/* Complete the task */
myTask.end();
}
/**
* Determine Focus.
*/
public void determineFocus() {
/* Switch on active component */
switch (theActive) {
case DEPOSITS:
theDepositTable.determineFocus(theViewerEntry);
break;
case CASH:
theCashTable.determineFocus(theViewerEntry);
break;
case LOANS:
theLoanTable.determineFocus(theViewerEntry);
break;
case EVENTS:
theEventTable.determineFocus(theViewerEntry);
break;
case EVENTTAGS:
theTagTable.determineFocus(theViewerEntry);
break;
case REGIONS:
theRegionTable.determineFocus(theViewerEntry);
break;
default:
break;
}
}
/**
* Does this panel have updates?
*
* @return true/false
*/
public boolean hasUpdates() {
/* Determine whether we have updates */
boolean hasUpdates = theDepositTable.hasUpdates();
if (!hasUpdates) {
hasUpdates = theCashTable.hasUpdates();
}
if (!hasUpdates) {
hasUpdates = theLoanTable.hasUpdates();
}
if (!hasUpdates) {
hasUpdates = theEventTable.hasUpdates();
}
if (!hasUpdates) {
hasUpdates = theTagTable.hasUpdates();
}
if (!hasUpdates) {
hasUpdates = theRegionTable.hasUpdates();
}
/* Return to caller */
return hasUpdates;
}
/**
* Has this set of panels got the session focus?
*
* @return true/false
*/
public boolean hasSession() {
/* Determine whether we have session focus */
boolean hasSession = theDepositTable.hasSession();
if (!hasSession) {
hasSession = theCashTable.hasSession();
}
if (!hasSession) {
hasSession = theLoanTable.hasSession();
}
if (!hasSession) {
hasSession = theEventTable.hasSession();
}
if (!hasSession) {
hasSession = theTagTable.hasSession();
}
if (!hasSession) {
hasSession = theRegionTable.hasSession();
}
/* Return to caller */
return hasSession;
}
/**
* Does this panel have errors?
*
* @return true/false
*/
public boolean hasErrors() {
/* Determine whether we have errors */
boolean hasErrors = theDepositTable.hasErrors();
if (!hasErrors) {
hasErrors = theCashTable.hasErrors();
}
if (!hasErrors) {
hasErrors = theLoanTable.hasErrors();
}
if (!hasErrors) {
hasErrors = theEventTable.hasErrors();
}
if (!hasErrors) {
hasErrors = theTagTable.hasErrors();
}
if (!hasErrors) {
hasErrors = theRegionTable.hasErrors();
}
/* Return to caller */
return hasErrors;
}
/**
* Does this panel have item editing occurring?
*
* @return true/false
*/
public boolean isItemEditing() {
/* Determine whether we have item editing */
boolean isEditing = theDepositTable.isItemEditing();
if (!isEditing) {
isEditing = theCashTable.isItemEditing();
}
if (!isEditing) {
isEditing = theLoanTable.isItemEditing();
}
if (!isEditing) {
isEditing = theEventTable.isItemEditing();
}
if (!isEditing) {
isEditing = theTagTable.isItemEditing();
}
if (!isEditing) {
isEditing = theRegionTable.isItemEditing();
}
/* Return to caller */
return isEditing;
}
/**
* Select category.
*
* @param pCategory the category to select
*/
public void selectCategory(final Object pCategory) {
/* Determine which panel to show */
if (pCategory instanceof MoneyWiseDepositCategory myCategory) {
theDepositTable.selectCategory(myCategory);
showPanel(PanelName.DEPOSITS);
} else if (pCategory instanceof MoneyWiseCashCategory myCategory) {
theCashTable.selectCategory(myCategory);
showPanel(PanelName.CASH);
} else if (pCategory instanceof MoneyWiseLoanCategory myCategory) {
theLoanTable.selectCategory(myCategory);
showPanel(PanelName.LOANS);
} else if (pCategory instanceof MoneyWiseTransCategory myCategory) {
theEventTable.selectCategory(myCategory);
showPanel(PanelName.EVENTS);
}
}
/**
* Select tag.
*
* @param pTag the category to select
*/
public void selectTag(final Object pTag) {
/* Determine which panel to show */
if (pTag instanceof MoneyWiseTransTag myTag) {
theTagTable.selectTag(myTag);
showPanel(PanelName.EVENTTAGS);
}
}
/**
* Select region.
*
* @param pRegion the region to select
*/
public void selectRegion(final Object pRegion) {
/* Determine which panel to show */
if (pRegion instanceof MoneyWiseRegion myRegion) {
theRegionTable.selectRegion(myRegion);
showPanel(PanelName.REGIONS);
}
}
/**
* Show panel.
*
* @param pName the panel name
*/
private void showPanel(final PanelName pName) {
/* Obtain name of panel */
final String myName = pName.toString();
/* Move correct card to front */
theCardPanel.selectCard(myName);
theFilterCardPanel.selectCard(myName);
/* Note the active panel */
theActive = pName;
theSelectButton.setFixedText(myName);
/* Determine the focus */
determineFocus();
}
/**
* Set Visibility.
*/
protected void setVisibility() {
/* Determine whether we have updates */
final boolean hasUpdates = hasUpdates();
final boolean isItemEditing = isItemEditing();
/* Update the action buttons */
theActionButtons.setEnabled(true);
theActionButtons.setVisible(hasUpdates && !isItemEditing);
/* Update the selection */
theSelectButton.setEnabled(!isItemEditing);
theFilterCardPanel.setEnabled(!isItemEditing);
/* Alert listeners that there has been a change */
theEventManager.fireEvent(PrometheusDataEvent.ADJUSTVISIBILITY);
}
/**
* Cancel Editing of underlying tables.
*/
private void cancelEditing() {
/* Cancel editing on subPanels */
theDepositTable.cancelEditing();
theCashTable.cancelEditing();
theLoanTable.cancelEditing();
theEventTable.cancelEditing();
theTagTable.cancelEditing();
theRegionTable.cancelEditing();
}
/**
* handleErrorPane.
*/
private void handleErrorPane() {
/* Determine whether we have an error */
final boolean isError = theError.hasError();
/* Hide selection panel on error */
theSelectPanel.setVisible(!isError);
/* Lock card panel */
theCardPanel.setEnabled(!isError);
/* Lock Action Buttons */
theActionButtons.setEnabled(!isError);
}
/**
* handleSelection.
*/
private void handleSelection() {
/* Cancel any editing */
cancelEditing();
/* Show selected panel */
showPanel(theSelectButton.getValue());
}
/**
* handle Action Buttons.
*
* @param pEvent the event
*/
private void handleActionButtons(final OceanusEvent<PrometheusUIEvent> pEvent) {
/* Cancel editing */
cancelEditing();
/* Perform the command */
theEditSet.processCommand(pEvent.getEventId(), theError);
}
/**
* handle GoTo Event.
*
* @param pEvent the event
*/
private void handleGoToEvent(final OceanusEvent<PrometheusDataEvent> pEvent) {
/* Access details */
@SuppressWarnings("unchecked") final PrometheusGoToEvent<MoneyWiseGoToId> myEvent = pEvent.getDetails(PrometheusGoToEvent.class);
/* Access event and obtain details */
switch (myEvent.getId()) {
/* Pass through the event */
case STATEMENT:
case ACCOUNT:
case STATIC:
theEventManager.cascadeEvent(pEvent);
break;
/* Access subPanels */
case CATEGORY:
selectCategory(myEvent.getDetails());
break;
case TAG:
selectTag(pEvent.getDetails());
break;
case REGION:
selectRegion(pEvent.getDetails());
break;
default:
break;
}
}
/**
* Panel names.
*/
private enum PanelName {
/**
* Deposits.
*/
DEPOSITS(MoneyWiseBasicDataType.DEPOSITCATEGORY),
/**
* Cash.
*/
CASH(MoneyWiseBasicDataType.CASHCATEGORY),
/**
* Loans.
*/
LOANS(MoneyWiseBasicDataType.LOANCATEGORY),
/**
* Events.
*/
EVENTS(MoneyWiseBasicDataType.TRANSCATEGORY),
/**
* Tags.
*/
EVENTTAGS(MoneyWiseBasicDataType.TRANSTAG),
/**
* Regions.
*/
REGIONS(MoneyWiseBasicDataType.REGION);
/**
* The String name.
*/
private final String theName;
/**
* Constructor.
*
* @param pDataType the dataType
*/
PanelName(final MoneyWiseBasicDataType pDataType) {
theName = pDataType.getListName();
}
@Override
public String toString() {
/* return the name */
return theName;
}
}
}