org.zaproxy.zap.utils.TableColumnManager Maven / Gradle / Ivy
Show all versions of zap Show documentation
/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2013 The ZAP Development Team
*
* 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.zaproxy.zap.utils;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
/**
* It will give the user the ability to hide columns and then re-show them in their last viewed
* position. This functionality is supported by a popup menu added to the table header of the table.
* The TableColumnModel is still used to control the view for the table. The manager will invoke the
* appropriate methods of the TableColumnModel to hide/show columns as required.
* Code taken from tips4java. Written by
* Rob Camick, which states free usage: You are free to use and/or modify any or all code posted on
* the Java Tips Weblog without restriction. A credit in the code comments would be nice, but not in
* any way mandatory.
*/
public class TableColumnManager
implements MouseListener, ActionListener, TableColumnModelListener, PropertyChangeListener {
private JTable table;
private TableColumnModel columnModel;
private boolean menuPopup;
private List allColumns;
/**
* Convenience constructor for creating a TableColumnManager for a table. Support for a popup
* menu on the table header will be enabled.
*
* @param table the table whose TableColumns will managed.
*/
public TableColumnManager(JTable table) {
this(table, true);
}
/**
* Create a TableColumnManager for a table.
*
* @param table the table whose TableColumns will managed.
* @param menuPopup enable or disable a popup menu to allow the users to manager the visibility
* of TableColumns.
*/
public TableColumnManager(JTable table, boolean menuPopup) {
this.table = table;
setMenuPopup(menuPopup);
table.addPropertyChangeListener(this);
reset();
}
/**
* Reset the TableColumnManager to only manage the TableColumns that are currently visible in
* the table.
*
* Generally this method should only be invoked by the TableColumnManager when the TableModel
* of the table is changed.
*/
public void reset() {
table.getColumnModel().removeColumnModelListener(this);
columnModel = table.getColumnModel();
columnModel.addColumnModelListener(this);
// Keep a duplicate TableColumns for managing hidden TableColumns
int count = columnModel.getColumnCount();
allColumns = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
allColumns.add(columnModel.getColumn(i));
}
}
/**
* Get the popup support.
*
* @return the popup support
*/
public boolean isMenuPopup() {
return menuPopup;
}
/**
* Add/remove support for a popup menu to the table header. The popup menu will give the user
* control over which columns are visible.
*
* @param menuPopup when true support for displaying a popup menu is added otherwise the popup
* menu is removed.
*/
public void setMenuPopup(boolean menuPopup) {
table.getTableHeader().removeMouseListener(this);
if (menuPopup) {
table.getTableHeader().addMouseListener(this);
}
this.menuPopup = menuPopup;
}
/**
* Hide a column from view in the table.
*
* @param modelColumn the column index from the TableModel of the column to be removed
*/
public void hideColumn(int modelColumn) {
int viewColumn = table.convertColumnIndexToView(modelColumn);
if (viewColumn != -1) {
TableColumn column = columnModel.getColumn(viewColumn);
hideColumn(column);
}
}
/**
* Hide a column from view in the table.
*
* @param columnName the column name of the column to be removed
*/
public void hideColumn(Object columnName) {
if (columnName == null) {
return;
}
for (int i = 0; i < columnModel.getColumnCount(); i++) {
TableColumn column = columnModel.getColumn(i);
if (columnName.equals(column.getHeaderValue())) {
hideColumn(column);
break;
}
}
}
/**
* Hide a column from view in the table.
*
* @param column the TableColumn to be removed from the TableColumnModel of the table
*/
public void hideColumn(TableColumn column) {
if (columnModel.getColumnCount() == 1) {
return;
}
// Ignore changes to the TableColumnModel made by the TableColumnManager
columnModel.removeColumnModelListener(this);
columnModel.removeColumn(column);
columnModel.addColumnModelListener(this);
}
/**
* Show a hidden column in the table.
*
* @param modelColumn the column index from the TableModel of the column to be added
*/
public void showColumn(int modelColumn) {
for (TableColumn column : allColumns) {
if (column.getModelIndex() == modelColumn) {
showColumn(column);
break;
}
}
}
/**
* Show a hidden column in the table.
*
* @param columnName the column name from the TableModel of the column to be added
*/
public void showColumn(Object columnName) {
for (TableColumn column : allColumns) {
if (column.getHeaderValue().equals(columnName)) {
showColumn(column);
break;
}
}
}
/**
* Show a hidden column in the table. The column will be positioned at its proper place in the
* view of the table.
*
* @param column the TableColumn to be shown.
*/
private void showColumn(TableColumn column) {
// Ignore changes to the TableColumnModel made by the TableColumnManager
columnModel.removeColumnModelListener(this);
// Add the column to the end of the table
columnModel.addColumn(column);
// Move the column to its position before it was hidden.
// (Multiple columns may be hidden so we need to find the first
// visible column before this column so the column can be moved
// to the appropriate position)
int position = allColumns.indexOf(column);
int from = columnModel.getColumnCount() - 1;
int to = 0;
for (int i = position - 1; i > -1; i--) {
try {
TableColumn visibleColumn = allColumns.get(i);
to = columnModel.getColumnIndex(visibleColumn.getHeaderValue()) + 1;
break;
} catch (IllegalArgumentException e) {
}
}
columnModel.moveColumn(from, to);
columnModel.addColumnModelListener(this);
}
//
// Implement MouseListener
//
@Override
public void mousePressed(MouseEvent e) {
checkForPopup(e);
}
@Override
public void mouseReleased(MouseEvent e) {
checkForPopup(e);
}
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
private void checkForPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
JTableHeader header = (JTableHeader) e.getComponent();
int column = header.columnAtPoint(e.getPoint());
showPopup(column);
}
}
/*
* Show a popup containing items for all the columns found in the table
* column manager. The popup will be displayed below the table header
* columns that was clicked.
*
* @param index index of the table header column that was clicked
*/
private void showPopup(int index) {
Object headerValue = columnModel.getColumn(index).getHeaderValue();
int columnCount = columnModel.getColumnCount();
JPopupMenu popup = new SelectPopupMenu();
// Create a menu item for all columns managed by the table column
// manager, checking to see if the column is shown or hidden.
for (TableColumn tableColumn : allColumns) {
Object value = tableColumn.getHeaderValue();
JCheckBoxMenuItem item = new JCheckBoxMenuItem(value.toString());
item.addActionListener(this);
try {
columnModel.getColumnIndex(value);
item.setSelected(true);
if (columnCount == 1) {
item.setEnabled(false);
}
} catch (IllegalArgumentException e) {
item.setSelected(false);
}
popup.add(item);
if (value == headerValue) {
popup.setSelected(item);
}
}
// Display the popup below the TableHeader
JTableHeader header = table.getTableHeader();
Rectangle r = header.getHeaderRect(index);
popup.show(header, r.x, r.height);
}
//
// Implement ActionListener
//
/*
* A table column will either be added to the table or removed from the
* table depending on the state of the menu item that was clicked.
*/
@Override
public void actionPerformed(ActionEvent event) {
JMenuItem item = (JMenuItem) event.getSource();
if (item.isSelected()) {
showColumn(item.getText());
} else {
hideColumn(item.getText());
}
}
//
// Implement TableColumnModelListener
//
@Override
public void columnAdded(TableColumnModelEvent e) {
// A table column was added to the TableColumnModel so we need
// to update the manager to track this column
TableColumn column = columnModel.getColumn(e.getToIndex());
if (!allColumns.contains(column)) {
allColumns.add(column);
}
}
@Override
public void columnMoved(TableColumnModelEvent e) {
if (e.getFromIndex() == e.getToIndex()) {
return;
}
// A table column has been moved one position to the left or right
// in the view of the table so we need to update the manager to
// track the new location
int index = e.getToIndex();
TableColumn column = columnModel.getColumn(index);
allColumns.remove(column);
if (index == 0) {
allColumns.add(0, column);
} else {
index--;
TableColumn visibleColumn = columnModel.getColumn(index);
int insertionColumn = allColumns.indexOf(visibleColumn);
allColumns.add(insertionColumn + 1, column);
}
}
@Override
public void columnMarginChanged(ChangeEvent e) {}
@Override
public void columnRemoved(TableColumnModelEvent e) {}
@Override
public void columnSelectionChanged(ListSelectionEvent e) {}
//
// Implement PropertyChangeListener
//
@Override
public void propertyChange(PropertyChangeEvent e) {
if ("model".equals(e.getPropertyName())) {
if (table.getAutoCreateColumnsFromModel()) {
reset();
}
}
}
/*
* Allows you to select a specific menu item when the popup is displayed.
* (i.e. this is a bug? fix)
*/
class SelectPopupMenu extends JPopupMenu {
private static final long serialVersionUID = 918018121618942657L;
@Override
public void setSelected(Component sel) {
int index = getComponentIndex(sel);
getSelectionModel().setSelectedIndex(index);
final MenuElement[] me = new MenuElement[2];
me[0] = this;
me[1] = getSubElements()[index];
SwingUtilities.invokeLater(
new Runnable() {
@Override
public void run() {
MenuSelectionManager.defaultManager().setSelectedPath(me);
}
});
}
}
}