/*
* Copyright 2002-2010 the original author or authors.
*
* 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 org.jdal.swing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import javax.swing.SortOrder;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.RowSorterEvent;
import javax.swing.event.RowSorterListener;
import javax.swing.table.TableCellRenderer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdal.beans.MessageSourceWrapper;
import org.jdal.dao.Dao;
import org.jdal.dao.Page;
import org.jdal.dao.Page.Order;
import org.jdal.dao.PageChangedEvent;
import org.jdal.dao.PageableDataSource;
import org.jdal.dao.Paginator;
import org.jdal.dao.PaginatorListener;
import org.jdal.model.TableState;
import org.jdal.service.TableService;
import org.jdal.swing.form.FormUtils;
import org.jdal.swing.table.LoadPreferencesAction;
import org.jdal.swing.table.SavePreferencesAction;
import org.jdal.ui.Editor;
import org.jdal.ui.EditorEvent;
import org.jdal.ui.EditorListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
/**
* A JPanel with a JTable and paginator.
*
* <p>This table view uses a {@link PageableDataSource} to query for data by pages.
* Has a paginator control to navigate on records and show page info.
*
* <p> You need to configure the PageableDatasource and the ListTableModel before usage.
*
* @author Jose Luis Martin - (jlm@joseluismartin.info)
*/
@SuppressWarnings("unchecked")
public class PageableTable<T> extends JPanel implements RowSorterListener, PaginatorListener {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(PageableTable.class);
/** Border layout */
private BorderLayout layout = new BorderLayout();
/** table to show data to user */
private JTable table;
/**
* @return the table
*/
public JTable getTable() {
return table;
}
/**
* @param table the table to set
*/
public void setTable(JTable table) {
this.table = table;
}
/** the paginator view */
private PaginatorView paginatorView;
/** Page used to query PageableDataSource */
private Page<T> page = new Page<T>();
/** pageable datasource to request data page by page */
private PageableDataSource<T> dataSource;
/** list table model for the table */
private ListTableModel tableModel;
/** scroll pane used as table container */
private JScrollPane tableScrollPane;
/** row sorter that query a new page for server side order */
private ModelRowSorter<ListTableModel> sorter;
/** visiblity column descriptor in use */
private List<ColumnDescriptor> columnDescriptors;
/** visibility box for select visible columns in visibililty menu */
private VisibilityBox visibilityBox;
/** Gui Factory to gets editors */
private GuiFactory guiFactory;
/** editor name */
private String editorName;
/** Open editors Map hold editors that are open for a model */
private Map<Object, Window> openDialogs = Collections.synchronizedMap(new HashMap<Object, Window>());
/** TableState service */
private TableService tableService;
/** Message Source */
private MessageSourceWrapper messageSource = new MessageSourceWrapper();
/** Show right menu when true */
private boolean showMenu = true;
/** Show paginator */
private boolean showPaginator = true;
/** Change Listeners */
private ArrayList<ChangeListener> changeListeners = new ArrayList<ChangeListener>();
/** Editor Listeners */
private ArrayList<EditorListener> editorListeners = new ArrayList<EditorListener>();
/** true if table propagate persistent service to editors */
private boolean configureEditors = true;
// Menus
JMenuBar rightMenuBar;
// Icons
private Icon visibilityMenuIcon;
private Icon okIcon;
private Icon cancelIcon;
private Icon userMenuIcon;
// Attributes needed to work with Page objects in Reports
private String sortPropertyName;
private Page.Order order;
/**
* Initalize component after properties set. Normally called by context vía init-method
*/
public void init() {
okIcon = FormUtils.getIcon(okIcon, "/images/16x16/dialog-ok.png");
cancelIcon = FormUtils.getIcon(cancelIcon, "/images/16x16/dialog-cancel.png");
visibilityMenuIcon = FormUtils.getIcon(visibilityMenuIcon, "/images/16x16/view-choose.png");
userMenuIcon = FormUtils.getIcon(userMenuIcon, "/images/table/16x16/users.png");
if (tableModel == null) {
tableModel = new ListTableModel();
}
setLayout(layout);
// Server side sorter
sorter = new ModelRowSorter<ListTableModel>(tableModel);
sorter.addRowSorterListener(this);
// configure paginator
if (showPaginator) {
if (paginatorView == null) {
paginatorView = new PaginatorView();
paginatorView.init();
}
paginatorView.setPaginator(page);
page.addPaginatorListener(this);
add(paginatorView.getPanel(), BorderLayout.SOUTH);
}
else {
page.setPageSize(Integer.MAX_VALUE);
}
createColumnDescriptos();
table = new JTable(tableModel, tableModel.getTableColumnModel());
table.setAutoCreateRowSorter(false);
table.setRowSorter(sorter);
table.setRowHeight(22);
table.addMouseListener(new TableListener());
tableScrollPane = new JScrollPane(table);
this.setBackground(Color.WHITE);
add(tableScrollPane, BorderLayout.CENTER);
if (showMenu)
createMenu();
page.setPageableDataSource(dataSource);
// goto first page
page.firstPage();
// restore table state
restoreState();
}
/**
* Create the right menu bar
*/
private void createMenu() {
rightMenuBar = new JMenuBar();
rightMenuBar.setLayout(new BoxLayout(rightMenuBar, BoxLayout.PAGE_AXIS));
rightMenuBar.setMargin(new Insets(0, 0, 0, 0));
// Add Visibility menu
JMenu menu = new JMenu();
menu.setMargin(new Insets(0,0,0,0));
menu.setIcon(visibilityMenuIcon);
menu.setMaximumSize(new Dimension(50,50));
visibilityBox = new VisibilityBox(columnDescriptors);
menu.add(visibilityBox);
menu.getPopupMenu().addPopupMenuListener(new VisibilityPopupListener());
JMenuItem okMenuItem = new JMenuItem(new OkVisibilityAction());
JMenuItem cancelMenuItem = new JMenuItem(new CancelVisibilityAction());
menu.addSeparator();
menu.add(okMenuItem);
menu.add(cancelMenuItem);
rightMenuBar.add(menu);
JMenu prefsMenu = new JMenu();
prefsMenu.setMargin(new Insets(0, 0, 0, 0));
prefsMenu.setIcon(userMenuIcon);
prefsMenu.setMaximumSize(new Dimension(50,50));
prefsMenu.add(new JMenuItem(new LoadPreferencesAction(this,
messageSource.getMessage("PageableTable.loadPreferences", null, "Load Preferences", Locale.getDefault()))));
prefsMenu.add(new JMenuItem(new SavePreferencesAction(this,
messageSource.getMessage("PageableTable.savePreferences", null, "Save Preferences", Locale.getDefault()))));
rightMenuBar.add(prefsMenu);
rightMenuBar.add(Box.createVerticalGlue());
// Add menu bar to right
add (rightMenuBar, BorderLayout.EAST);
}
/**
* Create columns desciptors list for visibility menu
*/
private void createColumnDescriptos() {
// get info about columns on table model
columnDescriptors = new ArrayList<ColumnDescriptor>(tableModel.getPropertyCount());
for (int i = 0; i < tableModel.getPropertyCount(); i++) {
columnDescriptors.add(new ColumnDescriptor(tableModel.getColumnNames().get(i),
tableModel.getDisplayNames().get(i), true));
}
}
/**
* Handle sort changes in model sorter.
* Query PageableDataSource for new page with the sort changes
* @see javax.swing.event.RowSorterListener#sorterChanged(javax.swing.event.RowSorterEvent)
*/
public void sorterChanged(RowSorterEvent e) {
if (sorter.getSortKeys().size() > 0 &&
tableModel.isPropertyColumn(sorter.getSortKeys().get(0).getColumn())) {
// set first page
configurePage();
page.firstPage();
}
}
/**
* Convert the Order from SortKey to Page.Order
* @param key the SortKey
* @return the Page order
*/
private Page.Order converSortOrder(RowSorter.SortKey key) {
Page.Order order = Order.ASC;
if (key.getSortOrder() == SortOrder.DESCENDING) {
order = Order.DESC;
}
return order;
}
/**
* Configure sort and order in page from sorter
*/
private void configurePage() {
Page.Order order = Page.Order.ASC;
String sortPropertyName = null;
List<? extends SortKey> keys = sorter.getSortKeys();
// If sorting, get values to set in page
if (keys.size() > 0) {
RowSorter.SortKey key = sorter.getSortKeys().get(0);
if (tableModel.isPropertyColumn(key.getColumn())) {
sortPropertyName = tableModel.getSortPropertyName(key.getColumn());
order = converSortOrder(key);
}
}
page.setSortName(sortPropertyName);
page.setOrder(order);
}
/**
* Handle paginators changes.
* @see org.jdal.dao.PaginatorListener#pageChanged(org.jdal.dao.PageChangedEvent)
*/
public void pageChanged(PageChangedEvent event) {
tableModel.setList(page.getData());
fireChangeEvent();
}
/**
* Get a dialog for editing a row
*/
public Window getEditor() {
if (editorName == null)
return null;
Window owner = SwingUtilities.getWindowAncestor(this);
Window window;
if (owner instanceof Frame) {
window = (Window) guiFactory.getObject(editorName, new Object[] {owner});
}
else {
window = (Window) guiFactory.getObject(editorName);
}
if (window instanceof Editor) {
Editor<T> editor = (Editor<T>) window;
if (dataSource instanceof Dao && configureEditors) {
editor.setPersistentService((Dao<T,?extends Serializable>) dataSource);
}
// add editor listeners
for (EditorListener listener : editorListeners) {
editor.addEditorListener(listener);
}
}
return window;
}
/**
* @param toEdit model to edit
* @return model editor.
*/
public Window getEditor(Object toEdit) {
Window dlg = openDialogs.get(toEdit);
if (dlg == null) {
dlg = getEditor();
if (dlg == null)
return null;
openDialogs.put(toEdit, dlg);
((View<Object>) dlg).setModel(toEdit);
((View<Object>) dlg).refresh();
dlg.addWindowListener(new DialogWindowListener());
if (dlg instanceof Editor) {
Editor<T> editor = (Editor<T>) dlg;
editor.addEditorListener(new EditorListener() {
public void modelChanged(EditorEvent e) {
refresh();
}
});
}
}
((View<T>) dlg).refresh();
return dlg;
}
/**
* Restore TableState
*/
public void restoreState() {
if (tableService != null) {
TableState state = tableService.getState(getName());
if (state != null)
restoreState(state);
}
}
/**
* Restore the column visibility from TableState
* @param state the table state
*/
public void restoreState(TableState state) {
for (ColumnDescriptor cd : columnDescriptors) {
cd.setVisible(state.getVisibleColumns().contains(cd.getPropertyName()));
}
updateVisibleColumns();
if (paginatorView != null) {
getPaginator().setPageSize(state.getPageSize());
}
}
/**
* Update TableModel column model from columDescriptors
*/
private void updateVisibleColumns() {
List<String> displayNames = new ArrayList<String>(columnDescriptors.size());
List<String> propertyNames = new ArrayList<String>(columnDescriptors.size());
for (ColumnDescriptor cd : columnDescriptors) {
if (cd.isVisible()) {
displayNames.add(cd.getDisplayName());
propertyNames.add(cd.getPropertyName());
}
}
tableModel.setDisplayNames(displayNames);
tableModel.setColumnNames(propertyNames);
tableModel.init();
table.setColumnModel(tableModel.getTableColumnModel());
tableModel.fireTableChanged();
}
public void saveState() {
if (tableService == null)
return; // nothing to do
TableState state = new TableState();
List<String> visible = new ArrayList<String>();
for (ColumnDescriptor cd : columnDescriptors) {
if (cd.isVisible())
visible.add(cd.getPropertyName());
}
state.setName(getName());
state.setVisibleColumns(visible);
state.setPageSize(paginatorView.getPaginator().getPageSize());
tableService.saveState(state);
}
public void addChangeListener(ChangeListener l) {
if (!changeListeners.contains(l))
changeListeners.add(l);
}
public void removeChangeListener(ChangeListener l) {
changeListeners.remove(l);
}
/**
* Notify ChangeListeners that state change
*/
private void fireChangeEvent() {
ChangeEvent e = new ChangeEvent(this);
for (ChangeListener l : changeListeners)
l.stateChanged(e);
}
/**
* @return the paginatorView
*/
public PaginatorView getPaginatorView() {
return paginatorView;
}
/**
* @param paginatorView the paginatorView to set
*/
public void setPaginatorView(PaginatorView paginatorView) {
this.paginatorView = paginatorView;
}
/**
* @return the dataSource
*/
public PageableDataSource<T> getDataSource() {
return dataSource;
}
/**
* @param dataSource the dataSource to set
*/
public void setDataSource(PageableDataSource<T> dataSource) {
this.dataSource = dataSource;
// review datasource duplication
page.setPageableDataSource(dataSource);
}
public Paginator getPaginator() {
return paginatorView.getPaginator();
}
/**
* @return the tableModel
*/
public ListTableModel getTableModel() {
return tableModel;
}
/**
* @param tableModel the tableModel to set
*/
public void setTableModel(ListTableModel tableModel) {
this.tableModel = tableModel;
}
public Icon getVisibilityMenuIcon() {
return visibilityMenuIcon;
}
public void setVisibilityMenuIcon(Icon visibilityMenuIcon) {
this.visibilityMenuIcon = visibilityMenuIcon;
}
public Icon getOkIcon() {
return okIcon;
}
public void setOkIcon(Icon okIcon) {
this.okIcon = okIcon;
}
public Icon getCancelIcon() {
return cancelIcon;
}
public void setCancelIcon(Icon cancelIcon) {
this.cancelIcon = cancelIcon;
}
/**
* Listener to watch visibility popup menu and sync visibility state
* whene popoup is cancelled externally.
* @author Jose Luis Martin - (jlm@joseluismartin.info)
*/
class VisibilityPopupListener implements PopupMenuListener {
/**
* {@inheritDoc}
* @see javax.swing.event.PopupMenuListener#popupMenuCanceled(javax.swing.event.PopupMenuEvent)
*/
public void popupMenuCanceled(PopupMenuEvent e) {
visibilityBox.setColumnDescriptors(columnDescriptors);
}
/**
* {@inheritDoc}
* @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent)
*/
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
/**
* {@inheritDoc}
* @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent)
*/
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
visibilityBox.setColumnDescriptors(columnDescriptors);
}
}
class OkVisibilityAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public OkVisibilityAction() {
super(messageSource.getMessage("Accept"), okIcon);
}
/**
* Copy visibility descriptors to table and change de ListableTableModel
* with new properties
* @param e ActionEvent the JButton ActionEvent
*/
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < columnDescriptors.size(); i++) {
ColumnDescriptor cd = columnDescriptors.get(i);
cd.setVisible(visibilityBox.getColumnDescriptors().get(i).isVisible());
}
updateVisibleColumns();
}
}
class CancelVisibilityAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public CancelVisibilityAction() {
super(messageSource.getMessage("Cancel"), cancelIcon);
}
/**
* When cancel, set visibility descriptors from table
* and discard selection changes.
* @param e ActionEvent from JButton
*/
public void actionPerformed(ActionEvent e) {
visibilityBox.setColumnDescriptors(columnDescriptors);
}
}
private class TableListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
Point point = e.getPoint();
int row = table.rowAtPoint(point);
int col = table.columnAtPoint(point);
// check Actions
if (col != -1 && row != -1 && tableModel.isActionColumn(col)) {
TableRowAction action = (TableRowAction) tableModel.getValueAt(row, col);
action.setTable(PageableTable.this);
action.setRow(tableModel.getList().get(row));
action.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "clicked"));
}
// check double click on rows
if (row != -1 && e.getClickCount() == 2) {
Object toEdit = tableModel.getList().get(row);
Window dlg = getEditor(toEdit);
if (dlg != null) {
if (dlg instanceof Frame) {
((Frame) dlg).setState(Frame.NORMAL);
((Frame) dlg).requestFocus();
}
dlg.setLocationRelativeTo(null);
dlg.setVisible(true);
}
}
}
}
/**
* Remove dialogs from openDialog Map when closed. Will fail if the model
* hashcode change after editing it.
*
* @author Jose Luis Martin - (jlm@joseluismartin.info)
*/
private class DialogWindowListener extends WindowAdapter {
@Override
public void windowClosed(WindowEvent e) {
if (openDialogs.remove(((View<Object>) e.getWindow()).getModel()) == null)
log.warn("Tray to remove a non existant Dialog, ¿may be model hashcode changed?");
}
}
public GuiFactory getGuiFactory() {
return guiFactory;
}
public void setGuiFactory(GuiFactory guiFactory) {
this.guiFactory = guiFactory;
}
public String getEditorName() {
return editorName;
}
public void setEditorName(String editorName) {
this.editorName = editorName;
}
public void refresh() {
page.setPage(page.getPage());
}
/**
* @return the filter
*/
public Object getFilter() {
return page.getFilter();
}
/**
* @param filter the filter to set
*/
public void setFilter(Object filter) {
page.setFilter(filter);
}
/**
* @param columnClass
* @param renderer
* @see javax.swing.JTable#setDefaultRenderer(java.lang.Class, javax.swing.table.TableCellRenderer)
*/
public void setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) {
table.setDefaultRenderer(columnClass, renderer);
}
public String getSortPropertyName() {
return sortPropertyName;
}
public void setSortPropertyName(String sortPropertyName) {
this.sortPropertyName = sortPropertyName;
}
public Page.Order getOrder() {
return order;
}
public void setOrder(Page.Order order) {
this.order = order;
}
/**
* @return the tableService
*/
public TableService getTableService() {
return tableService;
}
/**
* @param tableService the tableService to set
*/
public void setTableService(TableService tableService) {
this.tableService = tableService;
}
/**
* @return the userMenuIcon
*/
public Icon getUserMenuIcon() {
return userMenuIcon;
}
/**
* @param userMenuIcon the userMenuIcon to set
*/
public void setUserMenuIcon(Icon userMenuIcon) {
this.userMenuIcon = userMenuIcon;
}
/**
* @return the messageSource
*/
public MessageSource getMessageSource() {
return messageSource.getMessageSource();
}
/**
* @param messageSource the messageSource to set
*/
@Autowired
public void setMessageSource(MessageSource messageSource) {
this.messageSource.setMessageSource(messageSource);
}
/**
* @return the showMenu
*/
public boolean isShowMenu() {
return showMenu;
}
/**
* @param showMenu the showMenu to set
*/
public void setShowMenu(boolean showMenu) {
this.showMenu = showMenu;
}
/**
* @return List of checked keys
*/
public List<Serializable> getChecked() {
return tableModel.getChecked();
}
/**
* @return model selected and visible in current page
*/
public List<T> getVisibleSelected() {
return tableModel.getVisibleChecked();
}
/**
* Select all posible filtered results.
*/
public void selectAll() {
Page<T> page = new Page<T>(Integer.MAX_VALUE);
page.setFilter(this.page.getFilter());
tableModel.check(dataSource.getKeys(page));
}
/**
* Un select all selected
*/
public void unSelectAll() {
tableModel.uncheckAll();
}
/**
* @return the configureEditors
*/
public boolean isConfigureEditors() {
return configureEditors;
}
/**
* @param configureEditors the configureEditors to set
*/
public void setConfigureEditors(boolean configureEditors) {
this.configureEditors = configureEditors;
}
public void addEditorListener(EditorListener listener) {
if (!editorListeners.contains(listener))
editorListeners.add(listener);
}
public void removeEditorListener(EditorListener listener) {
editorListeners.remove(listener);
}
/**
* @return the showPaginator
*/
public boolean isShowPaginator() {
return showPaginator;
}
/**
* @param showPaginator the showPaginator to set
*/
public void setShowPaginator(boolean showPaginator) {
this.showPaginator = showPaginator;
}
/**
* @return the page size
* @see org.jdal.dao.Page#getPageSize()
*/
public int getPageSize() {
return page.getPageSize();
}
/**
* @param pageSize
* @see org.jdal.dao.Page#setPageSize(int)
*/
public void setPageSize(int pageSize) {
page.setPageSize(pageSize);
}
}
/**
* Simple data model for description of table column in visibility menu
*
* @author Jose Luis Martin - (jlm@joseluismartin.info)
*/
class ColumnDescriptor implements Cloneable {
private String propertyName;
private String displayName;
private boolean visible;
/**
* Create a new ColumnDescriptor
* @param propertyName
* @param displayName
* @param visible
*/
public ColumnDescriptor(String propertyName, String displayName,
boolean visible) {
this.propertyName = propertyName;
this.displayName = displayName;
this.visible = visible;
}
public String getPropertyName() {
return propertyName;
}
public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
/**
* Clone this object
*/
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
/**
* Simple Box Component that hold a ColumnDescriptor and a checkbox
* to show visibility state of a table column
*
* @author Jose Luis Martin - (jlm@joseluismartin.info)
*/
class VisibilityItem extends JComponent implements ChangeListener {
private static final long serialVersionUID = 1L;
private ColumnDescriptor cd;
private JCheckBox check;
/**
* @param cd
*/
public VisibilityItem(ColumnDescriptor cd) {
this.cd = cd;
BoxLayout layout = new BoxLayout(this, BoxLayout.LINE_AXIS);
setLayout(layout);
this.setAlignmentX(0f);
check = new JCheckBox(cd.getDisplayName(), cd.isVisible());
check.setAlignmentX(0f);
add(check);
check.addChangeListener(this);
refresh();
}
public void refresh() {
check.setSelected(cd.isVisible());
}
/**
* Update the columnDescriptor when check change
* @param e the ChangeEvent
*/
public void stateChanged(ChangeEvent e) {
cd.setVisible(check.isSelected());
}
/**
* @param columnDescriptor
*/
public void setColumnDescriptor(ColumnDescriptor columnDescriptor) {
this.cd = columnDescriptor;
refresh();
}
}
/**
* Box to show visibility column state in a JMenu popup window.
*
* @author Jose Luis Martin - (jlm@joseluismartin.info)
*/
class VisibilityBox extends JComponent {
private static final long serialVersionUID = 1L;
private final static Log log = LogFactory.getLog(VisibilityBox.class);
/** column descriptors copy */
List<ColumnDescriptor> columnDescriptors;
/**
* Create a new VisiblityBox initialized with column descriptors
* @param columnDescriptors column descriptors
*/
public VisibilityBox(List<ColumnDescriptor> columnDescriptors) {
setColumnDescriptors(columnDescriptors);
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
for (ColumnDescriptor cd : this.columnDescriptors) {
add(new VisibilityItem(cd));
}
}
/**
* refresh the state of visibility item when column descriptor list changes
*/
public void refresh() {
for (int i = 0; i < getComponents().length; i++) {
Component c = getComponent(i);
if (c instanceof VisibilityItem) {
if (log.isDebugEnabled())
log.debug("refresh: " + columnDescriptors.get(i).isVisible());
((VisibilityItem) c).setColumnDescriptor(columnDescriptors.get(i));
}
}
}
/**
* get the column descriptors
* @return the column descriptor list
*/
public List<ColumnDescriptor> getColumnDescriptors() {
return columnDescriptors;
}
/**
* Sets the column descriptor list.
* We clone all column descriptor list to easy discard changes when the
* user cancel changes to visibility column state.
* @param columnDescriptors
*/
public void setColumnDescriptors(List<ColumnDescriptor> columnDescriptors) {
this.columnDescriptors = new ArrayList<ColumnDescriptor>(columnDescriptors.size());
for (ColumnDescriptor cd : columnDescriptors) {
this.columnDescriptors.add((ColumnDescriptor) cd.clone());
}
refresh();
}
}