/* * RapidMiner * * Copyright (C) 2001-2008 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.gui.look.fc; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.Enumeration; import java.util.Vector; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.JViewport; import javax.swing.ListSelectionModel; import javax.swing.UIManager; import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import com.rapidminer.gui.look.RapidLookTools; /** * A table for the file details. * * @author Ingo Mierswa * @version $Id: FileTable.java,v 1.3 2008/07/01 14:16:13 ingomierswa Exp $ */ public class FileTable extends JTable implements MouseListener, MouseMotionListener { private static final long serialVersionUID = -8700859510439797254L; private static class LabelRenderer extends FileTableLabel implements TableCellRenderer { private static final long serialVersionUID = 8972168539366862236L; public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (value == null) { return null; } FileTableLabel label = (FileTableLabel) value; label.setOpaque(false); label.setSelected(isSelected); if (isSelected) { label.setForeground(UIManager.getColor("textHighlightText")); } else { label.setForeground(UIManager.getColor("textText")); } return label; } } private class HeaderActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { headerMenuChanged(e.getActionCommand(), ((JCheckBoxMenuItem) e.getSource())); captureColumnsWidth(); } } private class TableHeaderMouseListener extends MouseAdapter implements MouseMotionListener { @Override public void mouseClicked(MouseEvent e) { if (!e.isPopupTrigger()) { JTableHeader h = (JTableHeader) e.getSource(); TableColumnModel columnModel = h.getColumnModel(); int viewColumn = columnModel.getColumnIndexAtX(e.getX()); int column = columnModel.getColumn(viewColumn).getModelIndex(); if (column != -1) { if (columnModel.getColumn(viewColumn).getHeaderValue().equals("File Name")) { FileTable.this.fileList.orderBy(FileList.ORDER_BY_FILE_NAME, false); FileTable.this.fileList.updateTableData(); } else if (columnModel.getColumn(viewColumn).getHeaderValue().equals("Type")) { FileTable.this.fileList.orderBy(FileList.ORDER_BY_FILE_TYPE, false); FileTable.this.fileList.updateTableData(); } else if (columnModel.getColumn(viewColumn).getHeaderValue().equals("Last modified")) { FileTable.this.fileList.orderBy(FileList.ORDER_BY_FILE_MODIFIED, false); FileTable.this.fileList.updateTableData(); } else if (columnModel.getColumn(viewColumn).getHeaderValue().equals("Size")) { FileTable.this.fileList.orderBy(FileList.ORDER_BY_FILE_SIZE, false); FileTable.this.fileList.updateTableData(); } } } } @Override public void mousePressed(MouseEvent e) { evaluateClick(e); } @Override public void mouseReleased(MouseEvent e) { evaluateClick(e); } public void mouseDragged(MouseEvent e) { updateMainColumnIndex(); captureColumnsWidth(); } public void mouseMoved(MouseEvent e) { } } private class TableKeyListener extends KeyAdapter { private FileTable table; private int tempNum = 0; @Override public void keyPressed(KeyEvent e) { if (this.table == null) { this.table = ((FileTable) e.getSource()); } if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { FileTable.this.fileList.filechooserUI.getCancelSelectionAction().actionPerformed(null); } else if (e.getKeyCode() == KeyEvent.VK_SPACE) { updateLastSelected(); } else if (e.getKeyCode() == KeyEvent.VK_UP) { this.tempNum = FileTable.this.fileList.visibleItemsList.indexOf(FileTable.this.fileList.lastSelected); if ((this.tempNum < FileTable.this.fileList.visibleItemsList.size()) && (this.tempNum > 0)) { FileTable.this.fileList.lastSelected = FileTable.this.fileList.visibleItemsList.elementAt(this.tempNum - 1); updateLastSelected(); } } else if (e.getKeyCode() == KeyEvent.VK_DOWN) { this.tempNum = FileTable.this.fileList.visibleItemsList.indexOf(FileTable.this.fileList.lastSelected); if (this.tempNum < FileTable.this.fileList.visibleItemsList.size() - 1) { FileTable.this.fileList.lastSelected = FileTable.this.fileList.visibleItemsList.elementAt(this.tempNum + 1); updateLastSelected(); } } else if (e.getKeyCode() == KeyEvent.VK_HOME) { FileTable.this.fileList.lastSelected = FileTable.this.fileList.visibleItemsList.elementAt(0); updateLastSelected(); } else if (e.getKeyCode() == KeyEvent.VK_END) { FileTable.this.fileList.lastSelected = FileTable.this.fileList.visibleItemsList.elementAt(FileTable.this.fileList.visibleItemsList.size() - 1); updateLastSelected(); } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { doActionPerformed(); } else if (e.getKeyCode() == KeyEvent.VK_PAGE_UP) { this.tempNum = FileTable.this.fileList.visibleItemsList.indexOf(FileTable.this.fileList.lastSelected); int diff = (int) (((JViewport) this.table.getParent()).getViewRect().getHeight() / this.table.getCellRect(this.tempNum, 0, true).getHeight()) - 1; if (this.tempNum - diff < 0) { FileTable.this.fileList.lastSelected = FileTable.this.fileList.visibleItemsList.elementAt(0); updateLastSelected(); } else { FileTable.this.fileList.lastSelected = FileTable.this.fileList.visibleItemsList.elementAt(this.tempNum - diff); updateLastSelected(); } } else if (e.getKeyCode() == KeyEvent.VK_PAGE_DOWN) { this.tempNum = FileTable.this.fileList.visibleItemsList.indexOf(FileTable.this.fileList.lastSelected); int diff = (int) (((JViewport) this.table.getParent()).getViewRect().getHeight() / this.table.getCellRect(this.tempNum, 0, true).getHeight()) - 1; if (this.tempNum + diff >= FileTable.this.fileList.visibleItemsList.size()) { FileTable.this.fileList.lastSelected = FileTable.this.fileList.visibleItemsList.elementAt(FileTable.this.fileList.visibleItemsList.size() - 1); updateLastSelected(); } else { FileTable.this.fileList.lastSelected = FileTable.this.fileList.visibleItemsList.elementAt(this.tempNum + diff); updateLastSelected(); } } else { if (KeyEvent.getKeyText(e.getKeyCode()).toLowerCase().equals("a") && (e.getModifiersEx() == InputEvent.CTRL_DOWN_MASK)) { this.table.selectAll(); } if (e.getModifiersEx() == 0) { this.table.forwardToNearestFor(String.valueOf(e.getKeyChar()).toLowerCase()); } } } } private boolean mouseDownFlag = false; private boolean pointChanged = false; private int mpx, mpy, mpcx, mpcy; private int tx, ty; private Rectangle selectionRect, scrollRect; private JPopupMenu panePopup, headerPopup; private JMenuItem menuItem = new JMenuItem(); private int row; private int column; private int counter; private FileList fileList; private DefaultTableModel model; private Vector<Comparable> columnNames = new Vector<Comparable>(); private Vector<Integer> originalColumsWidth = new Vector<Integer>(); private TableHeaderMouseListener tableHeaderListener = new TableHeaderMouseListener(); private TableKeyListener tablekeylistener = new TableKeyListener(); private Item tempItem; private int mainColumnIndex; private Enumeration en; private HeaderActionListener hal = new HeaderActionListener(); private boolean mouseDragging = false; protected int[] columnsWidth; public FileTable(FileList chooser) { this.fileList = chooser; init(); } public int getHeaderHeight() { return ((int) this.tableHeader.getHeaderRect(0).getHeight()); } @Override public String getToolTipText(MouseEvent event) { this.row = this.rowAtPoint(event.getPoint()); this.column = this.columnAtPoint(event.getPoint()); if ((this.column == this.mainColumnIndex) && (this.row > -1)) { this.fileList.visibleItemsList.elementAt(this.row).getAdditionalFileData(); return String.valueOf(this.fileList.visibleItemsList.elementAt(this.row).getToolTipText()); } else { return null; } } @Override public boolean isCellEditable(int r, int c) { return false; } private void init() { this.model = ((DefaultTableModel) this.getModel()); this.columnNames.removeAllElements(); this.columnNames.add("File Name"); this.columnNames.add("Size"); this.columnNames.add("Type"); this.columnNames.add("Last modified"); this.originalColumsWidth.add(new Integer(0)); this.originalColumsWidth.add(new Integer(0)); this.originalColumsWidth.add(new Integer(0)); this.originalColumsWidth.add(new Integer(0)); this.setBackground(Color.white); this.setShowGrid(false); this.setRowMargin(0); this.setSelectionBackground(Color.white); this.setFont(Item.menuFont); this.setRowHeight(Math.max(getFont().getSize(), 18) + 2); this.getTableHeader().setPreferredSize(new Dimension(20, 20)); this.getTableHeader().setSize(new Dimension(20, 20)); createPopupMenu(); this.getTableHeader().addMouseListener(this.tableHeaderListener); this.getTableHeader().addMouseMotionListener(this.tableHeaderListener); this.addMouseMotionListener(this); this.addMouseListener(this); this.addKeyListener(this.tablekeylistener); this.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); this.setCellSelectionEnabled(true); clearSelection(); } @Override public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { //do nothing } private void createPopupMenu() { this.panePopup = this.fileList.getPanePopup(); this.headerPopup = new JPopupMenu(); String col = ""; this.en = this.columnNames.elements(); while (this.en.hasMoreElements()) { col = this.en.nextElement().toString(); this.menuItem = new JCheckBoxMenuItem(col); this.menuItem.setSelected(true); this.menuItem.addActionListener(this.hal); this.headerPopup.add(this.menuItem); } } private void synchFilechooser() { this.fileList.selectedFilesVector.removeAllElements(); for (int i = 0; i < this.getRowCount(); i++) { this.tempItem = this.fileList.visibleItemsList.elementAt(i); if (this.getSelectionModel().isSelectedIndex(i)) { this.tempItem.updateSelectionMode(true); this.fileList.selectedFilesVector.add(this.tempItem); } else { this.tempItem.updateSelectionMode(false); if (this.fileList.selectedFilesVector.contains(this.tempItem)) { this.fileList.selectedFilesVector.remove(this.tempItem); } } } this.fileList.synchFilechoserSelection(); } @Override public void paint(Graphics g) { super.paint(g); if (this.fileList.fc.isMultiSelectionEnabled()) { if (this.pointChanged) { if (this.mpcx < 0) { this.tx = this.mpcx + this.mpx; this.mpcx *= -1; } else { this.tx = this.mpx; } if (this.mpcy < 0) { this.ty = this.mpcy + this.mpy; this.mpcy *= -1; } else { this.ty = this.mpy; } this.selectionRect = new Rectangle(this.tx, this.ty, this.mpcx, this.mpcy); testFor(this.selectionRect); this.pointChanged = false; } if (this.mouseDownFlag) { g.setColor(new Color(RapidLookTools.getColors().getFileChooserColors()[0].getRed(), RapidLookTools.getColors().getFileChooserColors()[0].getGreen(), RapidLookTools.getColors().getFileChooserColors()[0].getBlue(), 40)); g.fillRect(this.tx, this.ty, this.mpcx, this.mpcy); g.setColor(RapidLookTools.getColors().getFileChooserColors()[0]); g.drawRect(this.tx, this.ty, this.mpcx, this.mpcy); } } } private void testFor(Rectangle rect) { clearSelection(); int x = (int) this.tableHeader.getHeaderRect(this.mainColumnIndex).getX(); int y = 0; this.counter++; for (int i = 0; i < this.getRowCount(); i++) { y = (i - 1) * this.getRowHeight() + this.getHeaderHeight(); Dimension d = ((FileTableLabel) this.getValueAt(i, this.mainColumnIndex)).getPreferredSize(); Rectangle r = new Rectangle(x, y, Math.min((int) d.getWidth(), this.getColumnModel().getColumn(this.mainColumnIndex).getWidth()), this.getRowHeight(i)); if (r.intersects(rect)) { if (!this.getSelectionModel().isSelectedIndex(i)) { updateSelectionInterval(i, true); } } else { if (!this.getSelectionModel().isSelectedIndex(i)) { getSelectionModel().removeIndexInterval(i, i); } } } synchFilechooser(); } public void mouseDragged(MouseEvent e) { this.mpcx = e.getX() - this.mpx; this.mpcy = e.getY() - this.mpy; this.pointChanged = true; this.mouseDragging = true; this.scrollRect = new Rectangle(e.getX(), e.getY(), 1, 1); this.scrollRectToVisible(this.scrollRect); repaint(); } public void mouseMoved(MouseEvent e) {} private void resetPane() { this.mouseDownFlag = false; this.mpcx = 0; this.mpcy = 0; this.mpx = 0; this.mpy = 0; this.tx = 0; this.ty = 0; repaint(); } public void mouseClicked(MouseEvent e) { synchFilechooser(); if ((e.getClickCount() == 2) && !(e.getSource() instanceof JTableHeader)) { this.row = ((JTable) e.getComponent()).rowAtPoint(e.getPoint()); this.column = ((JTable) e.getComponent()).columnAtPoint(e.getPoint()); if (getColumnName(this.column).equals(getColumnName(this.mainColumnIndex)) && (this.row > -1)) { this.tempItem = this.fileList.visibleItemsList.elementAt(this.row); if (this.tempItem.isDirectory()) { this.fileList.filechooserUI.setCurrentDirectoryOfFileChooser(this.tempItem.getFile()); } else { this.fileList.fc.setSelectedFile(this.tempItem.getFile()); this.fileList.filechooserUI.getApproveSelectionAction().actionPerformed(null); } } } } private void doActionPerformed() { if (this.fileList.selectedFilesVector.contains(this.fileList.lastSelected)) { this.tempItem = this.fileList.lastSelected; if (this.tempItem.isDirectory()) { this.fileList.filechooserUI.setCurrentDirectoryOfFileChooser(this.tempItem.getFile()); } else { this.fileList.fc.setSelectedFile(this.tempItem.getFile()); this.fileList.filechooserUI.getApproveSelectionAction().actionPerformed(null); } } } public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) { this.mpx = e.getX(); this.mpy = e.getY(); this.mouseDownFlag = true; evaluateClick(e); if ((e.getSource() instanceof JTable) && !this.mouseDragging) { this.row = ((JTable) e.getComponent()).rowAtPoint(e.getPoint()); this.column = ((JTable) e.getComponent()).columnAtPoint(e.getPoint()); if (this.row < 0) { return; } int x = (int) this.tableHeader.getHeaderRect(this.mainColumnIndex).getX(); int y = 0; this.counter++; y = (this.row - 1) * this.getRowHeight() + this.getHeaderHeight(); Dimension d = ((FileTableLabel) this.getValueAt(this.row, this.mainColumnIndex)).getPreferredSize(); Rectangle r = new Rectangle(x, y, Math.min((int) d.getWidth(), this.getColumnModel().getColumn(this.mainColumnIndex).getWidth()), this.getRowHeight(this.row)); if (r.contains(e.getPoint())) { if (e.isControlDown()) { if (this.isCellSelected(this.row, this.mainColumnIndex)) { if (!e.isPopupTrigger()) { this.getSelectionModel().removeSelectionInterval(this.row, this.row); } } else { updateSelectionInterval(this.row, true); } } else { if (this.isCellSelected(this.row, this.mainColumnIndex)) { //do nothing } else { updateSelectionInterval(this.row, false); } } } else { clearSelection(); } } synchFilechooser(); } public void mouseReleased(MouseEvent e) { this.mouseDownFlag = false; this.mouseDragging = false; resetPane(); evaluateClick(e); repaint(); } @Override public void clearSelection() { super.clearSelection(); this.getColumnModel().getSelectionModel().setSelectionInterval(this.mainColumnIndex, this.mainColumnIndex); } private void evaluateClick(MouseEvent e) { if (e.isPopupTrigger()) { if (e.getComponent() instanceof JTableHeader) { this.headerPopup.show(e.getComponent(), e.getX(), e.getY()); } else { this.row = ((JTable) e.getComponent()).rowAtPoint(e.getPoint()); this.column = ((JTable) e.getComponent()).columnAtPoint(e.getPoint()); if (this.row < 0) { this.panePopup.show(e.getComponent(), e.getX(), e.getY()); return; } int x = (int) this.tableHeader.getHeaderRect(this.mainColumnIndex).getX(); int y = (this.row - 1) * this.getRowHeight() + this.getHeaderHeight(); Dimension d = ((FileTableLabel) this.getValueAt(this.row, this.mainColumnIndex)).getPreferredSize(); Rectangle r = new Rectangle(x, y, Math.min((int) d.getWidth(), this.getColumnModel().getColumn(this.mainColumnIndex).getWidth()), this.getRowHeight(this.row)); if (r.contains(e.getPoint())) { this.tempItem = this.fileList.visibleItemsList.elementAt(this.row); this.tempItem.getPopupMenu().show(e.getComponent(), e.getX(), e.getY()); this.fileList.lastSelected = this.tempItem; } else { this.panePopup.show(e.getComponent(), e.getX(), e.getY()); } } } } public void updateData(Object[][] vals) { this.en = this.getColumnModel().getColumns(); Vector<String> vec = new Vector<String>(); while (this.en.hasMoreElements()) { vec.add(((TableColumn) this.en.nextElement()).getHeaderValue().toString()); } if (vec.size() <= 0) { this.model.setDataVector(vals, this.columnNames.toArray()); } else { this.model.setDataVector(vals, vec.toArray()); } if (shouldRecalculateColumnSize()) { this.columnsWidth = new int[] { (int) (this.getWidth() * (0.50)), (int) (this.getWidth() * (0.10)), (int) (this.getWidth() * (0.21)), (int) (this.getWidth() * (0.19)) }; } this.en = this.getColumnModel().getColumns(); int i = 0; TableColumn tempColumn; while (this.en.hasMoreElements()) { tempColumn = (TableColumn) this.en.nextElement(); int cw = this.columnsWidth[i]; if (cw == 0) { tempColumn.setMinWidth(cw); } tempColumn.setPreferredWidth(cw); tempColumn.setWidth(cw); i++; } this.mainColumnIndex = this.getColumnModel().getColumnIndex("File Name"); this.getColumnModel().getColumn(this.mainColumnIndex).setCellRenderer(new LabelRenderer()); this.setSize(getPreferredSize()); clearSelection(); } private void captureColumnsWidth() { this.columnsWidth = new int[] { this.getColumnModel().getColumn(0).getWidth(), this.getColumnModel().getColumn(1).getWidth(), this.getColumnModel().getColumn(2).getWidth(), this.getColumnModel().getColumn(3).getWidth() }; } private boolean shouldRecalculateColumnSize() { if ((this.columnsWidth == null) || (this.columnsWidth.length < 4)) { return true; } else { if ((this.columnsWidth[0] == 0) && (this.columnsWidth[1] == 0) && (this.columnsWidth[2] == 0) && (this.columnsWidth[3] == 0)) { return true; } } return false; } public int getInitialHeight() { int height = 0; int rowCount = this.getRowCount(); if ((rowCount > 0) && (this.getColumnCount() > 0)) { Rectangle r = this.getCellRect(rowCount - 1, 0, true); height = r.y + r.height; } return height + this.getTableHeader().getHeight(); } private void updateLastSelected() { int tempNum = this.fileList.visibleItemsList.indexOf(this.fileList.lastSelected); updateSelectionInterval(tempNum, false); synchFilechooser(); } @Override public void selectAll() { if (this.fileList.fc.isMultiSelectionEnabled()) { clearSelection(); getSelectionModel().addSelectionInterval(0, this.getRowCount() - 1); synchFilechooser(); } } private void updateMainColumnIndex() { this.mainColumnIndex = this.getColumnModel().getColumnIndex(this.columnNames.elementAt(0)); } protected void updateSelectionInterval(int row, boolean add) { if (add && this.fileList.fc.isMultiSelectionEnabled()) { this.getSelectionModel().addSelectionInterval(row, row); } else { clearSelection(); this.getSelectionModel().addSelectionInterval(row, row); } this.fileList.lastSelected = this.fileList.visibleItemsList.elementAt(row); if (!this.mouseDownFlag) { this.scrollRectToVisible(this.getCellRect(row, this.mainColumnIndex, false)); } } private void headerMenuChanged(String col, JCheckBoxMenuItem source) { int index = this.getColumnModel().getColumnIndex(col); //real index if (!source.isSelected()) { int tv = 0; for (int i = 0; i < this.getColumnCount(); i++) { tv += this.getColumnModel().getColumn(i).getWidth(); } if (tv == this.getColumn(col).getWidth()) { source.setSelected(true); return; } this.originalColumsWidth.set(this.columnNames.indexOf(col), new Integer(this.getColumnModel().getColumn(index).getWidth())); this.getColumnModel().getColumn(index).setMaxWidth(0); this.getColumnModel().getColumn(index).setMinWidth(0); this.getColumnModel().getColumn(index).setWidth(0); this.getColumnModel().getColumn(index).setPreferredWidth(0); this.getTableHeader().resizeAndRepaint(); } else { this.getColumnModel().getColumn(index).setMaxWidth(2147483647); this.getColumnModel().getColumn(index).setPreferredWidth(this.originalColumsWidth.get(this.columnNames.indexOf(col)).intValue()); this.getColumnModel().getColumn(index).setWidth(this.originalColumsWidth.get(this.columnNames.indexOf(col)).intValue()); this.originalColumsWidth.set(this.columnNames.indexOf(col), new Integer(0)); this.getTableHeader().resizeAndRepaint(); } } private void forwardToNearestFor(String pre) { int index = this.fileList.visibleItemsList.indexOf(this.fileList.lastSelected) + 1; for (int i = 0; i < this.fileList.visibleItemsList.size(); i++) { if (index == this.fileList.visibleItemsList.size()) { index = 0; } if (this.fileList.visibleItemsList.elementAt(index).getFileName().toLowerCase().startsWith(pre)) { updateSelectionInterval(index, false); this.scrollRectToVisible(this.getCellRect(index, this.mainColumnIndex, false)); updateLastSelected(); return; } index++; } } }