All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.jonestimd.swing.component.ValidatedTablePanel Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
// The MIT License (MIT)
//
// Copyright (c) 2018 Timothy D. Jones
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package io.github.jonestimd.swing.component;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.ResourceBundle;

import javax.swing.Action;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;
import javax.swing.table.TableRowSorter;

import io.github.jonestimd.swing.ChangeBuffer;
import io.github.jonestimd.swing.ComponentFactory;
import io.github.jonestimd.swing.ComponentTreeUtils;
import io.github.jonestimd.swing.UnsavedChangesIndicator;
import io.github.jonestimd.swing.action.LocalizedAction;
import io.github.jonestimd.swing.table.DecoratedTable;
import io.github.jonestimd.swing.table.TableSummary;
import io.github.jonestimd.swing.table.TableSummaryPanel;
import io.github.jonestimd.swing.table.action.AddRowAction;
import io.github.jonestimd.swing.table.action.ReloadTableAction;
import io.github.jonestimd.swing.table.model.ValidatedBeanListTableModel;
import io.github.jonestimd.swing.window.StatusFrame;

/**
 * A {@link ValidatedPanel} that displays a {@link DecoratedTable} (for a {@link ValidatedBeanListTableModel}) and a
 * {@link TableSummaryPanel}.  The following actions are added to a toolbar on the frame's menu bar.  The actions
 * are initialized using the specified resources from the resource bundle.
 * 
 *     
 *     
 *          
 *     
 *     
 *     
 *          
 *     
 *     
 *     
 *     
 *          
 *     
 *     
 *     
 * 
ActionDescriptionResource Bundle Keys
Addadd a new row to the tableresourceGroup.action.new.mnemonicAndName
resourceGroup.action.new.iconImage
resourceGroup.action.new.accelerator (optional)
Deletemark a row as pending deletionresourceGroup.action.delete.mnemonicAndName
resourceGroup.action.delete.iconImage
resourceGroup.action.delete.accelerator (optional)
Savesave pending changes
Reloadreload the table data and discard pending changesresourceGroup.action.reload.mnemonicAndName
resourceGroup.action.reload.iconImage
resourceGroup.action.reload.accelerator (optional)
resourceGroup.action.reload.status.initialize (optional)
*

If the resource bundle contains the key resourceGroup.menu.mnemonicAndName then the actions are also added * to the specified menu on the frame's menu bar.

*

This panel includes a table model listener that enables/disables the save action and that notifies an ancestor * container that implements {@link UnsavedChangesIndicator} (e.g. a {@link StatusFrame}).

* @param class of the beans in the {@link ValidatedBeanListTableModel} */ public abstract class ValidatedTablePanel extends ValidatedPanel { private final ValidatedBeanListTableModel tableModel; private final DecoratedTable> table; protected final ResourceBundle bundle; protected final String resourceGroup; private final TableSummaryPanel tableSummaryPanel = new TableSummaryPanel(); private Action addAction; private Action deleteAction; private Action saveAction; private Action reloadAction; /** * Constructs a new {@code ValidatedTablePanel} using resources from {@code bundle}. * @param bundle the resource bundle to use for UI components * @param table the table to include on the panel * @param resourceGroup a string used to look up component resources */ protected ValidatedTablePanel(ResourceBundle bundle, DecoratedTable> table, String resourceGroup) { super(bundle, 1, new JScrollPane(table)); this.bundle = bundle; this.table = table; this.tableModel = table.getModel(); this.resourceGroup = resourceGroup; table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); table.getSelectionModel().addListSelectionListener(event -> { if (! event.getValueIsAdjusting()) { tableSelectionChanged(); } }); tableModel.addTableModelListener(event -> { UnsavedChangesIndicator indicator = ComponentTreeUtils.findAncestor(ValidatedTablePanel.this, UnsavedChangesIndicator.class); if (indicator != null) { // table may not be visible indicator.setUnsavedChanges(tableModel.isChanged()); } saveAction.setEnabled(tableModel.isChanged() && tableModel.isNoErrors()); }); createActions(); addTableSummaryPanel(); } private void createActions() { addAction = new AddRowAction<>(bundle, resourceGroup + ".action.new", tableModel, table, this::newBean); deleteAction = new DeleteAction(); saveAction = createSaveAction(); saveAction.setEnabled(false); reloadAction = new ReloadActionHandler(); } protected abstract Action createSaveAction(); @SuppressWarnings("unchecked") protected TableRowSorter> getRowSorter() { return ((TableRowSorter) getTable().getRowSorter()); } private void addTableSummaryPanel() { add(tableSummaryPanel, BorderLayout.NORTH); if (tableModel instanceof TableSummary) { addSummaries((TableSummary) tableModel); } } /** * Add an item to the summary panel. * @param tableSummary the summary item */ public void addSummaries(TableSummary tableSummary) { tableSummaryPanel.addSummaries(tableSummary); } public ValidatedBeanListTableModel getTableModel() { return tableModel; } protected DecoratedTable> getTable() { return table; } /** * Override to create a bean for a new row in the table. * @return the new bean */ protected abstract T newBean(); /** * Override to confirm deleting items from the table. The input list can be modified and used as the return value. * Only items in the returned list will actually be deleted. * @param items the items selected for deletion. * @return the items that have been confirmed for deletion */ protected abstract List confirmDelete(List items); protected boolean isDeleteEnabled(List selectionMinusPendingDeletes) { return ! selectionMinusPendingDeletes.isEmpty(); } protected List getSelectionMinusPendingDeletes() { List selectedItems = table.getSelectedItems(); selectedItems.removeAll(tableModel.getPendingDeletes()); return selectedItems; } /** * Adds a menu and toolbar to the frame's menu bar. * @param menuBar the frame's menu bar * @see #addActions(JMenu) * @see #addActions(JToolBar) */ @Override protected void initializeMenu(JMenuBar menuBar) { addMenu(menuBar); menuBar.add(createToolBar()); reloadAction.actionPerformed(new ActionEvent(this, -1, null)); } /** * Creates the toolbar to add to the frame's menu bar. * @return the new toolbar * @see #addActions(JToolBar) */ protected JToolBar createToolBar() { JToolBar toolbar = ComponentFactory.newMenuToolBar(); addActions(toolbar); return toolbar; } /** * Adds the {@code add}, {@code delete}, {@code save} and {@code reload} actions to the toolbar. * @param toolbar the toolbar on the frame's menu bar */ protected void addActions(JToolBar toolbar) { toolbar.add(ComponentFactory.newToolbarButton(addAction)); toolbar.add(ComponentFactory.newToolbarButton(deleteAction)); toolbar.add(ComponentFactory.newToolbarButton(saveAction)); toolbar.add(ComponentFactory.newToolbarButton(reloadAction)); } private void addMenu(JMenuBar menuBar) { String mnemonicAndNameKey = resourceGroup + ".menu.mnemonicAndName"; if (bundle.containsKey(mnemonicAndNameKey)) { JMenu menu = ComponentFactory.newMenu(bundle, mnemonicAndNameKey); addActions(menu); menuBar.add(menu, 0); menuBar.add(ComponentFactory.newMenuBarSeparator()); } } /** * Adds the {@code add}, {@code delete}, {@code save} and {@code reload} actions to the menu. * @param menu the menu from the frame's menu bar */ protected void addActions(JMenu menu) { menu.add(new JMenuItem(addAction)); menu.add(new JMenuItem(deleteAction)); menu.add(new JMenuItem(saveAction)); menu.add(new JMenuItem(reloadAction)); } protected ChangeBuffer getChangeBuffer() { return tableModel; } protected boolean isSingleRowSelected() { return table.getSelectedRowCount() == 1; } public T getSelectedBean() { return table.getSelectedRow() >= 0 ? tableModel.getRow(getSelectedRow()) : null; } private int getSelectedRow() { return table.convertRowIndexToModel(table.getSelectedRow()); } /** * Override to return the table data. */ protected abstract List getTableData(); /** * Updates the enabled state of actions. May be overridden to handle changes to table selection. */ protected void tableSelectionChanged() { deleteAction.setEnabled(isDeleteEnabled(getSelectionMinusPendingDeletes())); } private class DeleteAction extends LocalizedAction { private DeleteAction() { super(bundle, resourceGroup + ".action.delete"); setEnabled(false); } public void actionPerformed(ActionEvent event) { List selectedItems = getSelectionMinusPendingDeletes(); List items = confirmDelete(selectedItems); if (!items.isEmpty()) { items.forEach(tableModel::queueDelete); saveAction.setEnabled(tableModel.isChanged()); table.requestFocus(); } } } private class ReloadActionHandler extends ReloadTableAction { public ReloadActionHandler() { super(ValidatedTablePanel.this, bundle, resourceGroup + ".action.reload", table, tableModel); } @Override public List performTask() { return getTableData(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy