/* PANDA -- a simple transaction monitor Copyright (C) 1998-1999 Ogochan. 2000-2003 Ogochan & JMA (Japan Medical Association). 2002-2006 OZAWA Sakuro. This module is part of PANDA. PANDA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the GNU General Public License for full details. Everyone is granted permission to copy, modify and redistribute PANDA, but only under the conditions described in the GNU General Public License. A copy of this license is supposed to have been given to you along with PANDA so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ package org.montsuqi.widgets; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.montsuqi.util.SafeColorDecoder; public class PandaCList extends JTable { protected static final Logger logger = LogManager.getLogger(PandaCList.class); public static final int SELECTION_MODE_SINGLE = 1; public static final int SELECTION_MODE_MULTI = 2; private Color[] bgColors; private Color[] fgColors; private boolean[] selection; private int mode; /* mouse selection */ private int msStartRow; private int msPrevRow; private boolean msDragged; private boolean msValue; private Color selectionBGColor; private Color selectionFGColor; public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); } public void removeChangeListener(ChangeListener l) { listenerList.remove(ChangeListener.class, l); } public int getMode() { return mode; } public void setMode(int mode) { this.mode = mode; } public void setBGColors(Color[] bgColors) { this.bgColors = bgColors; } public void setFGColors(Color[] fgColors) { this.fgColors = fgColors; } public void setSelection(boolean[] s) { this.selection = s; } public boolean[] getSelection() { return this.selection; } public PandaCList() { super(); setFocusable(true); setAutoResizeMode(AUTO_RESIZE_OFF); setAutoscrolls(true); setRowSelectionAllowed(false); initActions(); if (System.getProperty("monsia.pandaclist.rowheight") != null) { int rowheight = Integer.parseInt(System.getProperty("monsia.pandaclist.rowheight")); this.setRowHeight(rowheight); } String strColor = System.getProperty("monsia.pandaclist.selection_bg_color"); if (strColor != null) { selectionBGColor = SafeColorDecoder.decode(strColor); } else { selectionBGColor = new Color(0x33, 0x66, 0xFF); } strColor = System.getProperty("monsia.pandaclist.selection_fg_color"); if (strColor != null) { selectionFGColor = SafeColorDecoder.decode(strColor); } else { selectionFGColor = new Color(0xFF, 0xFF, 0xFF); } if (System.getProperty("monsia.widget.pandaclist.showgrid") == null) { this.setShowGrid(false); } mode = PandaCList.SELECTION_MODE_SINGLE; addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { msDragged = false; int row = PandaCList.this.rowAtPoint(e.getPoint()); if (row == -1) { return; } msStartRow = row; msPrevRow = row; msValue = !selection[row]; } @Override public void mouseReleased(MouseEvent e) { int row = PandaCList.this.rowAtPoint(e.getPoint()); if (row == -1) { if (msDragged) { PandaCList.this.resizeAndRepaint(); PandaCList.this.fireChangeEvent(null); return; } else { return; } } if (mode == PandaCList.SELECTION_MODE_MULTI) { if (!msDragged) { PandaCList.this.toggleSelection(row); } } else { PandaCList.this.singleSelection(row); } PandaCList.this.resizeAndRepaint(); PandaCList.this.fireChangeEvent(null); } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } }); addMouseMotionListener(new MouseMotionListener() { @Override public void mouseDragged(MouseEvent e) { int prev; if (mode != PandaCList.SELECTION_MODE_MULTI) { return; } msDragged = true; int row = PandaCList.this.rowAtPoint(e.getPoint()); if (row == -1) { return; } if (row == msStartRow) { selection[row] = msValue; return; } if (row == msPrevRow) { return; } else { prev = msPrevRow; msPrevRow = row; } if (row > msStartRow) { if (row > prev) { selection[row] = msValue; } else { selection[prev] = !msValue; } } else { if (row < prev) { selection[row] = msValue; } else { selection[prev] = !msValue; } } PandaCList.this.resizeAndRepaint(); } @Override public void mouseMoved(MouseEvent e) { } }); } public void toggleSelection(int row) { selection[row] = !selection[row]; } public void singleSelection(int row) { for (int i = 0; i < selection.length; i++) { selection[i] = i == row; } } private void initActions() { ActionMap actions = getActionMap(); InputMap inputs = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); actions.put("doAction", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { int row = PandaCList.this.getSelectedRow(); if (mode == PandaCList.SELECTION_MODE_MULTI) { PandaCList.this.toggleSelection(row); } else { PandaCList.this.singleSelection(row); } PandaCList.this.resizeAndRepaint(); fireChangeEvent(new ChangeEvent(PandaCList.this)); } }); inputs.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "doAction"); inputs.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "doAction"); } protected void fireChangeEvent(ChangeEvent e) { ChangeListener[] listeners = (ChangeListener[]) listenerList.getListeners(ChangeListener.class); for (int i = 0, n = listeners.length; i < n; i++) { ChangeListener l = listeners[i]; l.stateChanged(e); } } @Override public Component prepareRenderer( TableCellRenderer renderer, int row, int column) { Component c = super.prepareRenderer(renderer, row, column); if (fgColors != null && row < fgColors.length && fgColors[row] != null) { c.setForeground(fgColors[row]); } else { c.setForeground(Color.BLACK); } if (selection[row]) { c.setBackground(this.selectionBGColor); c.setForeground(this.selectionFGColor); } else { if (bgColors != null && row < bgColors.length && bgColors[row] != null) { if (this.isRowSelected(row)) { int r = bgColors[row].getRed(); int g = bgColors[row].getGreen(); int b = bgColors[row].getBlue(); r = r - 0x30 < 0 ? 0 : r - 0x30; g = g - 0x30 < 0 ? 0 : g - 0x30; b = b - 0x30 < 0 ? 0 : b - 0x30; c.setBackground(new Color(r, g, b)); } else { c.setBackground(bgColors[row]); } } else { c.setBackground(Color.white); } } return c; } @Override public void createDefaultColumnsFromModel() { TableColumnModel model = getColumnModel(); int n = getColumnCount(); TableCellRenderer[] renderers = new TableCellRenderer[n]; int[] width = new int[n]; for (int i = 0; i < n; i++) { TableColumn column = model.getColumn(i); renderers[i] = column.getHeaderRenderer(); width[i] = column.getWidth(); } super.createDefaultColumnsFromModel(); for (int i = 0; i < n; i++) { TableColumn column = model.getColumn(i); column.setHeaderRenderer(renderers[i]); column.setPreferredWidth(width[i]); column.setWidth(width[i]); } } @Override public boolean isCellEditable(int row, int column) { return false; } public void registerHeaderComponent(int i, JComponent header) { TableCellRenderer renderer = new CListHeaderRenderer(header); TableColumn column = columnModel.getColumn(i); column.setHeaderRenderer(renderer); } public static void main(String[] args) { JFrame frame = new JFrame("PandaCList"); Container container = frame.getContentPane(); container.setLayout(new BorderLayout(10, 5)); final PandaCList clist = new PandaCList(); TableColumnModel columnModel = clist.getColumnModel(); columnModel.addColumn(new TableColumn()); columnModel.addColumn(new TableColumn()); columnModel.addColumn(new TableColumn()); DefaultTableModel tableModel = (DefaultTableModel) clist.getModel(); tableModel.setColumnCount(3); for (int i = 0; i < 50; i++) { Object[] rowData = new String[3]; rowData[0] = Integer.toString(i); rowData[1] = Integer.toString(i + 1); rowData[2] = Integer.toString(i + 2); tableModel.addRow(rowData); } clist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); JScrollPane scroll = new JScrollPane(clist); scroll.setPreferredSize(new Dimension(400, 300)); container.add(scroll, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new FlowLayout()); container.add(buttonPanel, BorderLayout.SOUTH); JButton button3 = new JButton(new AbstractAction("output") { @Override public void actionPerformed(ActionEvent ev) { } }); buttonPanel.add(button3); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.setLocationRelativeTo(null); frame.setSize(500, 500); frame.setVisible(true); } }