diff --git a/looks/.classpath b/looks/.classpath
index 4b19d49ccc..069fcb28f2 100644
--- a/looks/.classpath
+++ b/looks/.classpath
@@ -3,5 +3,6 @@
CTable
's
+ * columns.
+ * It's main purpose is to allow toggling of table columns' visibility.
+ * Additionally, arbitrary configuration actions can be exposed.
+ *
+ *
+ * This component is installed in the CTable
's
+ * trailing corner, if enabled:
+ *
+ *
+ * table.setColumnControlVisible(true);
+ *
+ *
+ * From the perspective of a CTable
, the component's behaviour is
+ * opaque. Typically, the button's action is to popup a component for user
+ * interaction.
+ *
+ * This class is responsible for handling/providing/updating the lists of
+ * actions and to keep all action's state in synch with Table-/Column state.
+ * The visible behaviour of the popup is delegated to a
+ * ColumnControlPopup
.
+ *
+ * @see CTable#setColumnControl
+ *
+ */
+public class CColumnControlButton extends JButton {
+ /** Marker to auto-recognize actions which should be added to the popup. */
+ public static final String COLUMN_CONTROL_MARKER = "column.";
+ /** exposed for testing. */
+ protected ColumnControlPopup popup;
+ // TODO: the table reference is a potential leak?
+ /** The table which is controlled by this. */
+ private CTable table;
+ /** Listener for table property changes. */
+ private PropertyChangeListener tablePropertyChangeListener;
+ /** Listener for table's columnModel. */
+ TableColumnModelListener columnModelListener;
+ /** the list of actions for column menuitems.*/
+ private List
+ *
+ * Here: delegates to getControlPopup().
+ */
+ public void togglePopup() {
+ getColumnControlPopup().toggleVisibility(this);
+ }
+
+ @Override
+ public void applyComponentOrientation(ComponentOrientation o) {
+ super.applyComponentOrientation(o);
+ getColumnControlPopup().applyComponentOrientation(o);
+ }
+
+
+//-------------------------- Action in synch with column properties
+ /**
+ * A specialized
+ * Implementation note: this listener reacts to column's
+ *
+ * PRE: columnVisibilityActions populated before calling this.
+ *
+ */
+ protected void addVisibilityActionItems() {
+ getColumnControlPopup().addVisibilityActionItems(
+ Collections.unmodifiableList(getColumnVisibilityActions()));
+ }
+
+ /**
+ * Adds additional actions to the popup.
+ * Here: delegates the list of actions as returned by #getAdditionalActions()
+ * to the DefaultColumnControlPopup.
+ * Does nothing if #getColumnActions() is empty.
+ *
+ */
+ protected void addAdditionalActionItems() {
+ getColumnControlPopup().addAdditionalActionItems(
+ Collections.unmodifiableList(getAdditionalActions()));
+ }
+
+
+ /**
+ * Creates and adds a ColumnVisiblityAction for every column that should be
+ * togglable via the column control.
+ *
+ * Here: all table columns contained in the
+ * PRE: canControl()
+ *
+ * @see #createColumnVisibilityAction
+ */
+ protected void createVisibilityActions() {
+ Enumeration
+ * Implementation note: this listener reacts to table's
+ * Implementation note: this listener reacts to "real" columnRemoved/-Added by
+ * populating the popups content from scratch.
+ *
+ * @return the
+ *
+ * @return boolean to indicate whether the column control is visible.
+ * @see #setColumnControlVisible(boolean)
+ * @see #setColumnControl(JComponent)
+ */
+ public boolean isColumnControlVisible() {
+ return columnControlVisible;
+ }
+
+ /**
+ * Sets the column control visible property. If true and
+ *
+ *
+ * Note: if the table is not inside a
+ *
+ * The default value is
+ *
+ * @see #setColumnControlVisible(boolean)
+ * @see #setColumnControl(JComponent)
+ */
+ protected void configureColumnControl() {
+ Container p = getParent();
+ if (p instanceof JViewport) {
+ Container gp = p.getParent();
+ if (gp instanceof JScrollPane) {
+ JScrollPane scrollPane = (JScrollPane) gp;
+ // Make certain we are the viewPort's view and not, for
+ // example, the rowHeaderView of the scrollPane -
+ // an implementor of fixed columns might do this.
+ JViewport viewport = scrollPane.getViewport();
+ if (viewport == null || viewport.getView() != this) {
+ return;
+ }
+ if (isColumnControlVisible()) {
+ verticalScrollPolicy = scrollPane
+ .getVerticalScrollBarPolicy();
+ scrollPane.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
+ getColumnControl());
+
+ scrollPane
+ .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
+ } else {
+ if (verticalScrollPolicy != 0) {
+ // Fix #155-swingx: reset only if we had force always before
+ // PENDING: JW - doesn't cope with dynamically changing the policy
+ // shouldn't be much of a problem because doesn't happen too often??
+ scrollPane.setVerticalScrollBarPolicy(verticalScrollPolicy);
+ }
+ try {
+ scrollPane.setCorner(JScrollPane.UPPER_TRAILING_CORNER,
+ null);
+ } catch (Exception ex) {
+ // Ignore spurious exception thrown by JScrollPane. This
+ // is a Swing bug!
+ }
+
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ * @param column
+ * @return boolean
+ */
+ public boolean isColumnVisible(TableColumn column)
+ {
+ return !hiddenColumns.contains(column);
+ }
+
+ /**
+ * Hide or show column
+ * @param column
+ * @param visible
+ */
+ public void setColumnVisibility(TableColumn column, boolean visible)
+ {
+ if (visible)
+ {
+ if (isColumnVisible(column)) return;
+ ColumnAttributes attributes = columnAttributesMap.get(column);
+ if (attributes == null) return;
+
+ column.setCellEditor(attributes.cellEditor);
+ column.setCellRenderer(attributes.cellRenderer);
+ column.setMinWidth(attributes.minWidth);
+ column.setMaxWidth(attributes.maxWidth);
+ column.setPreferredWidth(attributes.preferredWidth);
+ columnAttributesMap.remove(column);
+ hiddenColumns.remove(column);
+ }
+ else
+ {
+ if (!isColumnVisible(column)) return;
+
+ ColumnAttributes attributes = new ColumnAttributes();
+ attributes.cellEditor = column.getCellEditor();
+ attributes.cellRenderer = column.getCellRenderer();
+ attributes.minWidth = column.getMinWidth();
+ attributes.maxWidth = column.getMaxWidth();
+ attributes.preferredWidth = column.getPreferredWidth();
+ columnAttributesMap.put(column, attributes);
+
+ TableCellNone h = new TableCellNone(column.getIdentifier() != null ?
+ column.getIdentifier().toString() : column.getHeaderValue().toString());
+ column.setCellEditor(h);
+ column.setCellRenderer(h);
+ column.setMinWidth(0);
+ column.setMaxWidth(0);
+ column.setPreferredWidth(0);
+
+ hiddenColumns.add(column);
+ }
+ }
+
+ class ColumnAttributes {
+ protected TableCellEditor cellEditor;
+
+ protected TableCellRenderer cellRenderer;
+
+ protected Object headerValue;
+
+ protected int minWidth;
+
+ protected int maxWidth;
+
+ protected int preferredWidth;
+ }
} // CTable
diff --git a/looks/src/org/compiere/swing/TableCellNone.java b/looks/src/org/compiere/swing/TableCellNone.java
new file mode 100644
index 0000000000..feb723ddaa
--- /dev/null
+++ b/looks/src/org/compiere/swing/TableCellNone.java
@@ -0,0 +1,75 @@
+/******************************************************************************
+ * Product: Adempiere ERP & CRM Smart Business Solution *
+ * Copyright (C) 2007 Adempiere, Inc. All Rights Reserved. *
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms version 2 of the GNU General Public License as published *
+ * by the Free Software Foundation. This program is distributed in the hope *
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * You should have received a copy of the GNU General Public License along *
+ * with this program; if not, write to the Free Software Foundation, Inc., *
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
+ *****************************************************************************/
+package org.compiere.swing;
+
+import java.awt.Component;
+import java.util.EventObject;
+
+import javax.swing.JTable;
+import javax.swing.event.CellEditorListener;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
+
+/**
+ * Dummy editor and renderer use for invisible column
+ * @author Low Heng Sin
+ *
+ */
+public class TableCellNone implements TableCellEditor, TableCellRenderer {
+
+ private Object m_value;
+ private String m_columnName;
+
+ public TableCellNone(String columnName) {
+ m_columnName = columnName;
+ }
+
+ public Component getTableCellEditorComponent(JTable table, Object value,
+ boolean isSelected, int row, int column) {
+ m_value = value;
+ return null;
+ }
+
+ public void addCellEditorListener(CellEditorListener l) {
+ }
+
+ public void cancelCellEditing() {
+ }
+
+ public Object getCellEditorValue() {
+ return m_value;
+ }
+
+ public boolean isCellEditable(EventObject anEvent) {
+ return false;
+ }
+
+ public void removeCellEditorListener(CellEditorListener l) {
+ }
+
+ public boolean shouldSelectCell(EventObject anEvent) {
+ return false;
+ }
+
+ public boolean stopCellEditing() {
+ return true;
+ }
+
+ public Component getTableCellRendererComponent(JTable table, Object value,
+ boolean isSelected, boolean hasFocus, int row, int column) {
+ m_value = value;
+ return null;
+ }
+
+}
JTable
controlled by this component
+ * @param icon the Icon
to show
+ */
+ public CColumnControlButton(CTable table, Icon icon) {
+ super();
+ init();
+ // JW: icon LF dependent?
+ setAction(createControlAction(icon));
+ installTable(table);
+ }
+
+
+ @Override
+ public void updateUI() {
+ super.updateUI();
+ // JW: icon LF dependent?
+ setMargin(new Insets(1, 2, 2, 1)); // Make this LAF-independent
+ getColumnControlPopup().updateUI();
+ }
+
+ /**
+ * Toggles the popup component's visibility. This method is
+ * called by this control's default action. Action
which takes care of keeping in synch with
+ * TableColumn state.
+ *
+ * NOTE: client must call releaseColumn if this action is no longer needed!
+ *
+ */
+ public class ColumnVisibilityAction extends AbstractActionExt {
+
+ private TableColumn column;
+
+ private PropertyChangeListener columnListener;
+
+ /** flag to distinguish selection changes triggered by
+ * column's property change from those triggered by
+ * user interaction. Hack around #212-swingx.
+ */
+ private boolean fromColumn;
+
+ /**
+ * Creates a action synched to the table column.
+ *
+ * @param column the TableColumn
to keep synched to.
+ */
+ public ColumnVisibilityAction(TableColumn column) {
+ super((String) null);
+ setStateAction();
+ installColumn(column);
+ }
+
+ /**
+ * Releases all references to the synched TableColumn
.
+ * Client code must call this method if the
+ * action is no longer needed. After calling this action must not be
+ * used any longer.
+ */
+ public void releaseColumn() {
+ column.removePropertyChangeListener(columnListener);
+ column = null;
+ }
+
+ @Override
+ public void itemStateChanged(final ItemEvent e) {
+ if ((e.getStateChange() == ItemEvent.DESELECTED)
+ //JW: guarding against 1 leads to #212-swingx: setting
+ // column visibility programatically fails if
+ // the current column is the second last visible
+ // guarding against 0 leads to hiding all columns
+ // by deselecting the menu item.
+ && (table.getColumnCount() <= 1)
+ // JW Fixed #212: basically implemented Rob's idea to distinguish
+ // event sources instead of unconditionally reselect
+ // not entirely sure if the state transitions are completely
+ // defined but all related tests are passing now.
+ && !fromColumn) {
+ reselect();
+ } else {
+ setSelected(e.getStateChange() == ItemEvent.SELECTED);
+ }
+ }
+
+
+ @Override
+ public synchronized void setSelected(boolean newValue) {
+ super.setSelected(newValue);
+ if (!newValue) {
+ if (table.isColumnVisible(column)) {
+ table.setColumnVisibility(column, newValue);
+ }
+ } else {
+ if (!table.isColumnVisible(column)) {
+ table.setColumnVisibility(column, newValue);
+ }
+ }
+ }
+
+ /**
+ * Does nothing. Synch from action state to TableColumn state
+ * is done in itemStateChanged.
+ */
+ public void actionPerformed(ActionEvent e) {
+
+ }
+
+ /**
+ * Synchs selected property to visible. This
+ * is called on change of tablecolumn's visible
property.
+ *
+ * @param visible column visible state to synch to.
+ */
+ private void updateFromColumnVisible(boolean visible) {
+ fromColumn = true;
+ setSelected(visible);
+ fromColumn = false;
+ }
+
+ /**
+ * Synchs name property to value. This is called on change of
+ * tableColumn's headerValue
property.
+ *
+ * @param value
+ */
+ private void updateFromColumnHeader(Object value) {
+ if (value == null) {
+ this.setEnabled(false);
+ } else {
+ setName(String.valueOf(value));
+ this.setEnabled(true);
+ }
+ }
+
+ /**
+ * Enforces selected to true
. Called if user interaction
+ * tried to de-select the last single visible column.
+ *
+ */
+ private void reselect() {
+ firePropertyChange("selected", null, Boolean.TRUE);
+ }
+
+ // -------------- init
+ private void installColumn(TableColumn column) {
+ this.column = column;
+ column.addPropertyChangeListener(getColumnListener());
+ updateFromColumnHeader(column.getHeaderValue());
+ // #429-swing: actionCommand must be string
+ if (column.getIdentifier() != null) {
+ setActionCommand(column.getIdentifier().toString());
+ }
+ boolean visible = table.isColumnVisible(column);
+ updateFromColumnVisible(visible);
+ }
+
+ /**
+ * Returns the listener to column's property changes. The listener
+ * is created lazily if necessary.
+ *
+ * @return the PropertyChangeListener
listening to
+ * TableColumn
's property changes, guaranteed to be
+ * not null
.
+ */
+ protected PropertyChangeListener getColumnListener() {
+ if (columnListener == null) {
+ columnListener = createPropertyChangeListener();
+ }
+ return columnListener;
+ }
+
+ /**
+ * Creates and returns the listener to column's property changes.
+ * Subclasses are free to roll their own.
+ * visible
and headerValue
properties and
+ * calls the respective updateFromXX
methodes.
+ *
+ * @return the PropertyChangeListener
to use with the
+ * column
+ */
+ protected PropertyChangeListener createPropertyChangeListener() {
+ return new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent evt) {
+ if ("visible".equals(evt.getPropertyName())) {
+ updateFromColumnVisible((Boolean) evt.getNewValue());
+ } else if ("headerValue".equals(evt.getPropertyName())) {
+ updateFromColumnHeader(evt.getNewValue());
+ if (evt.getNewValue() == null)
+ populatePopup();
+ }
+ }
+ };
+ }
+ }
+
+ // ---------------------- the popup
+
+ /**
+ * A default implementation of ColumnControlPopup.
+ * It uses a JPopupMenu with
+ * MenuItems corresponding to the Actions as
+ * provided by the ColumnControlButton.
+ *
+ *
+ */
+ public class DefaultColumnControlPopup implements ColumnControlPopup {
+ private JPopupMenu popupMenu;
+ private JScrollPane scroller;
+ private JPanel panelMenus;
+
+ //------------------ public methods to control visibility status
+
+ /**
+ * @inheritDoc
+ *
+ */
+ public void updateUI() {
+ SwingUtilities.updateComponentTreeUI(getPopupMenu());
+ }
+
+ private JPanel getPanelMenu() {
+ if (panelMenus == null) {
+ panelMenus = new JPanel();
+ panelMenus.setLayout(new VerticalLayout());
+ panelMenus.setBackground(UIManager.getColor("MenuItem.background"));
+ panelMenus.setBorder(BorderFactory.createEmptyBorder());
+ }
+ return panelMenus;
+ }
+
+ private JScrollPane getScroller() {
+ if (scroller == null) {
+ scroller = createScroller();
+ scroller.getVerticalScrollBar().setFocusable( false );
+ scroller.setViewportView(getPanelMenu());
+ }
+ return scroller;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ */
+ public void toggleVisibility(JComponent owner) {
+ JPopupMenu popupMenu = getPopupMenu();
+ JPanel panel = getPanelMenu();
+ if (popupMenu.isVisible()) {
+ popupMenu.setVisible(false);
+ } else if (panel.getComponentCount() > 0) {
+ JScrollPane scroller = getScroller();
+ panel.validate();
+
+ Dimension pSize = table.getParent().getSize();
+ Dimension size = panel.getPreferredSize();
+ if (size.height >= pSize.height) {
+ scroller.setPreferredSize(new Dimension(size.width, pSize.height - 30));
+ } else {
+ scroller.setPreferredSize(size);
+ }
+ popupMenu.setPopupSize(new Dimension(scroller.getPreferredSize().width + 20,
+ scroller.getPreferredSize().height - 20));
+
+ Dimension buttonSize = owner.getSize();
+ int xPos = owner.getComponentOrientation().isLeftToRight() ? buttonSize.width
+ - popupMenu.getPreferredSize().width
+ : 0;
+
+ popupMenu.show(owner,
+ xPos, buttonSize.height);
+ }
+
+ }
+
+ /**
+ * @inheritDoc
+ *
+ */
+ public void applyComponentOrientation(ComponentOrientation o) {
+ getPopupMenu().applyComponentOrientation(o);
+
+ }
+
+ //-------------------- public methods to manipulate popup contents.
+
+ /**
+ * @inheritDoc
+ *
+ */
+ public void removeAll() {
+ getPanelMenu().removeAll();
+ }
+
+
+ /**
+ * @inheritDoc
+ *
+ */
+ public void addVisibilityActionItems(
+ List extends AbstractActionExt> actions) {
+ addItems(new ArrayListnull
.
+ * @see #createColumnControlPopup()
+ */
+ protected ColumnControlPopup getColumnControlPopup() {
+ if (popup == null) {
+ popup = createColumnControlPopup();
+ }
+ return popup;
+ }
+
+ /**
+ * Factory method to return a ColumnControlPopup
.
+ * Subclasses can override to hook custom implementations.
+ *
+ * @return the ColumnControlPopup
used.
+ */
+ protected ColumnControlPopup createColumnControlPopup() {
+ return new DefaultColumnControlPopup();
+ }
+
+
+//-------------------------- updates from table propertyChangelistnere
+
+ /**
+ * Adjusts internal state after table's column model property has changed.
+ * Handles cleanup of listeners to the old/new columnModel (Note, that
+ * it listens to the column model only if it can control column visibility).
+ * Updates content of popup.
+ *
+ * @param oldModel the old TableColumnModel
we had been listening to.
+ */
+ protected void updateFromColumnModelChange(TableColumnModel oldModel) {
+ if (oldModel != null && columnModelListener != null) {
+ oldModel.removeColumnModelListener(columnModelListener);
+ }
+ populatePopup();
+ table.getColumnModel().addColumnModelListener(getColumnModelListener());
+ }
+
+ /**
+ * Synchs this button's enabled with table's enabled.
+ *
+ */
+ protected void updateFromTableEnabledChanged() {
+ getAction().setEnabled(table.isEnabled());
+
+ }
+
+// ------------------------ updating the popup
+ /**
+ * Populates the popup from scratch.
+ *
+ * If applicable, creates and adds column visibility actions. Always adds
+ * additional actions.
+ */
+ protected void populatePopup() {
+ clearAll();
+ createVisibilityActions();
+ addVisibilityActionItems();
+ addAdditionalActionItems();
+ }
+
+ /**
+ *
+ * removes all components from the popup, making sure to release all
+ * columnVisibility actions.
+ *
+ */
+ protected void clearAll() {
+ clearColumnVisibilityActions();
+ getColumnControlPopup().removeAll();
+ }
+
+
+ /**
+ * Releases actions and clears list of actions.
+ *
+ */
+ protected void clearColumnVisibilityActions() {
+ if (columnVisibilityActions == null)
+ return;
+ for (ColumnVisibilityAction action : columnVisibilityActions) {
+ action.releaseColumn();
+ }
+ columnVisibilityActions.clear();
+ }
+
+
+ /**
+ * Adds visibility actions into the popup view.
+ *
+ * Here: delegates the list of actions to the DefaultColumnControlPopup.
+ * TableColumnModel
-
+ * visible and invisible columns - to createColumnVisibilityAction
and
+ * adds all not null
return values.
+ *
+ * ColumnVisibilityAction
for the given
+ * TableColumn
. The return value might be null, f.i. if the
+ * column should not be allowed to be toggled.
+ *
+ * @param column the TableColumn
to use for the action
+ * @return a ColumnVisibilityAction to use for the given column,
+ * may be null
.
+ */
+ protected ColumnVisibilityAction createColumnVisibilityAction(TableColumn column) {
+ return new ColumnVisibilityAction(column);
+ }
+
+ /**
+ * Lazyly creates and returns the List of visibility actions.
+ *
+ * @return the list of visibility actions, guaranteed to be != null.
+ */
+ protected ListPropertyChangeListener
for use with the
+ * table, guaranteed to be not null
.
+ */
+ protected PropertyChangeListener getTablePropertyChangeListener() {
+ if (tablePropertyChangeListener == null) {
+ tablePropertyChangeListener = createTablePropertyChangeListener();
+ }
+ return tablePropertyChangeListener;
+ }
+
+ /**
+ * Creates the listener to table's property changes. Subclasses are free
+ * to roll their own. enabled
and
+ * columnModel
properties and calls the respective
+ * updateFromXX
methodes.
+ *
+ * @return the PropertyChangeListener
for use with the table.
+ */
+ protected PropertyChangeListener createTablePropertyChangeListener() {
+ return new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent evt) {
+ if ("columnModel".equals(evt.getPropertyName())) {
+ updateFromColumnModelChange((TableColumnModel) evt
+ .getOldValue());
+ } else if ("enabled".equals(evt.getPropertyName())) {
+ updateFromTableEnabledChanged();
+ }
+ }
+ };
+ }
+
+ /**
+ * Returns the listener to table's column model. The listener is
+ * lazily created if necessary.
+ * @return the TableColumnModelListener
for use with the
+ * table's column model, guaranteed to be not null
.
+ */
+ protected TableColumnModelListener getColumnModelListener() {
+ if (columnModelListener == null) {
+ columnModelListener = createColumnModelListener();
+ }
+ return columnModelListener;
+ }
+
+ /**
+ * Creates the listener to columnModel. Subclasses are free to roll their
+ * own.
+ * TableColumnModelListener
for use with the
+ * table's columnModel.
+ */
+ protected TableColumnModelListener createColumnModelListener() {
+ return new TableColumnModelListener() {
+ /** Tells listeners that a column was added to the model. */
+ public void columnAdded(TableColumnModelEvent e) {
+ populatePopup();
+ }
+
+ /** Tells listeners that a column was removed from the model. */
+ public void columnRemoved(TableColumnModelEvent e) {
+ populatePopup();
+ }
+
+
+ /** Tells listeners that a column was repositioned. */
+ public void columnMoved(TableColumnModelEvent e) {
+ }
+
+ /** Tells listeners that a column was moved due to a margin change. */
+ public void columnMarginChanged(ChangeEvent e) {
+ }
+
+ /**
+ * Tells listeners that the selection model of the TableColumnModel
+ * changed.
+ */
+ public void columnSelectionChanged(ListSelectionEvent e) {
+ }
+ };
+ }
+
+} // end class ColumnControlButton
diff --git a/looks/src/org/compiere/swing/CTable.java b/looks/src/org/compiere/swing/CTable.java
index a95cd98e79..a2d2f94b35 100644
--- a/looks/src/org/compiere/swing/CTable.java
+++ b/looks/src/org/compiere/swing/CTable.java
@@ -19,11 +19,14 @@ package org.compiere.swing;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
+import java.util.List;
import java.util.logging.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
+
import org.compiere.util.*;
+import org.jdesktop.swingx.icon.ColumnControlIcon;
/**
* Model Independent enhanced JTable.
@@ -49,8 +52,22 @@ public class CTable extends JTable
setSurrendersFocusOnKeystroke(true);
//Default row height too narrow
setRowHeight(getFont().getSize() + 8);
+
+ setColumnControlVisible(true);
+ addHierarchyListener(createHierarchyListener());
} // CTable
+ private HierarchyListener createHierarchyListener() {
+ return new HierarchyListener() {
+
+ public void hierarchyChanged(HierarchyEvent e) {
+ if (e.getChangeFlags() == HierarchyEvent.PARENT_CHANGED)
+ configureColumnControl();
+ }
+
+ };
+ }
+
/** Last model index sorted */
protected int p_lastSortIndex = -1;
/** Sort direction */
@@ -68,7 +85,28 @@ public class CTable extends JTable
/** Logger */
private static Logger log = Logger.getLogger(CTable.class.getName());
-
+ /**
+ * ScrollPane's original vertical scroll policy. If the column control is
+ * visible the policy is set to ALWAYS.
+ */
+ private int verticalScrollPolicy;
+
+ /**
+ * Flag to indicate if the column control is visible.
+ */
+ private boolean columnControlVisible = false;
+
+ /**
+ * The component used a column control in the upper trailing corner of
+ * an enclosing JScrollPane
.
+ */
+ private JComponent columnControlButton;
+
+ private ListJXTable
is contained in a JScrollPane
, the
+ * table adds the column control to the trailing corner of the scroll pane.
+ * JScrollPane
the column
+ * control is not shown even if this returns true. In this case it's the
+ * responsibility of the client code to actually show it.
+ * false
.
+ *
+ * @param visible boolean to indicate if the column control should be shown
+ * @see #isColumnControlVisible()
+ * @see #setColumnControl(JComponent)
+ *
+ */
+ public void setColumnControlVisible(boolean visible) {
+ boolean old = isColumnControlVisible();
+ this.columnControlVisible = visible;
+ if (old != isColumnControlVisible()) {
+ configureColumnControl();
+ firePropertyChange("columnControlVisible", old, !old);
+ }
+ }
+
+ /**
+ * Returns the component used as column control. Lazily creates the
+ * control to the default if it is null
.
+ *
+ * @return component for column control, guaranteed to be != null.
+ * @see #setColumnControl(JComponent)
+ * @see #createDefaultColumnControl()
+ */
+ public JComponent getColumnControl() {
+ if (columnControlButton == null) {
+ columnControlButton = createDefaultColumnControl();
+ }
+ return columnControlButton;
+ }
+
+ /**
+ * Creates the default column control used by this table.
+ * This implementation returns a ColumnControlButton
configured
+ * with default ColumnControlIcon
.
+ *
+ * @return the default component used as column control.
+ * @see #setColumnControl(JComponent)
+ * @see org.jdesktop.swingx.table.ColumnControlButton
+ * @see org.jdesktop.swingx.icon.ColumnControlIcon
+ */
+ protected JComponent createDefaultColumnControl() {
+ return new CColumnControlButton(this, new ColumnControlIcon());
+ }
+
+ /**
+ * Configures the upper trailing corner of an enclosing
+ * JScrollPane
.
+ *
+ * Adds/removes the ColumnControl
depending on the
+ * columnControlVisible
property.