001/* 002 * Copyright (c) 2010-2012 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2012-05-09 11:05:40 -0700 (Wed, 09 May 2012) $' 007 * '$Revision: 29823 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.plotting; 031 032import java.awt.Color; 033import java.awt.Container; 034import java.awt.Dimension; 035import java.awt.datatransfer.DataFlavor; 036import java.awt.datatransfer.Transferable; 037import java.awt.datatransfer.UnsupportedFlavorException; 038import java.awt.event.ActionEvent; 039import java.awt.event.ActionListener; 040import java.io.IOException; 041import java.util.ArrayList; 042import java.util.List; 043 044import javax.swing.DefaultCellEditor; 045import javax.swing.JComboBox; 046import javax.swing.JComponent; 047import javax.swing.JMenuItem; 048import javax.swing.JPopupMenu; 049import javax.swing.JTable; 050import javax.swing.TransferHandler; 051import javax.swing.event.TableModelListener; 052import javax.swing.table.AbstractTableModel; 053import javax.swing.table.TableCellEditor; 054import javax.swing.table.TableCellRenderer; 055 056import org.jfree.data.general.Dataset; 057import org.kepler.gui.PlotsEditorPanel; 058import org.kepler.plotting.table.ColorTableCellEditor; 059import org.kepler.plotting.table.ColorTableCellRenderer; 060 061import ptolemy.actor.TypedIOPort; 062import ptolemy.data.type.ArrayType; 063import ptolemy.data.type.BaseType; 064import ptolemy.data.type.Type; 065import ptolemy.vergil.toolbox.PtolemyTransferable; 066 067/** 068 * Created by IntelliJ IDEA. 069 * User: sean 070 * Date: Jul 7, 2010 071 * Time: 12:31:50 PM 072 */ 073 074public class DataTable extends JTable implements ActionListener { 075 076 private DataTable() { 077 DataTable.Model model = new DataTable.Model(); 078 model.setTable(this); 079 this.setModel(model); 080 this.setTransferHandler(new MyTransferHandler()); 081 // insertDemoData(); 082 083 this.addMouseListener(new java.awt.event.MouseAdapter() { 084 // os X 085 public void mousePressed(java.awt.event.MouseEvent evt) { 086 jTableShowContextMenu(evt); 087 } 088 // Windows 089 public void mouseReleased(java.awt.event.MouseEvent evt) { 090 jTableShowContextMenu(evt); 091 } 092 }); 093 popupMenu.add(removeRowMenuItem); 094 removeRowMenuItem.addActionListener(this); 095 removeRowMenuItem.setActionCommand(REMOVE_ROW); 096 097 // adjust column widths 098 int numCols = getColumnCount(); 099 for (int i=0; i<numCols; i++){ 100 getColumnModel().getColumn(i).setPreferredWidth(Row.COLUMN_WIDTHS[i]); 101 } 102 } 103 104 private void jTableShowContextMenu(java.awt.event.MouseEvent mouseEvent) { 105 DataTable dataTable = getPlotEditor().getTable(); 106 int[] selectedRows = dataTable.getSelectedRows(); 107 int clickedRow = dataTable.rowAtPoint(mouseEvent.getPoint()); 108 109 boolean clickWasOnASelectedRow = false; 110 for (int i = 0; i < selectedRows.length; i++) { 111 if (clickedRow == selectedRows[i]) { 112 clickWasOnASelectedRow = true; 113 break; 114 } 115 } 116 117 if (selectedRows.length > 0 && clickWasOnASelectedRow && 118 (mouseEvent.isPopupTrigger() || mouseEvent.isControlDown())){ 119 popupMenu.show(mouseEvent.getComponent(), mouseEvent 120 .getX(), mouseEvent.getY()); 121 } 122 } 123 124 public DataTable(PlotEditor plotEditor) { 125 this(); 126 setPlotEditor(plotEditor); 127 } 128 129 public void add(Row row) { 130 ((Model) this.getModel()).addRow(row); 131 } 132 133 public void removeRow(Row row) { 134 ((Model) this.getModel()).removeRow(row); 135 } 136 137 public Row getRow(int index) { 138 return ((Model) this.getModel()).getRow(index); 139 } 140 141 public void update() { 142 ((Model) this.getModel()).fireTableDataChanged(); 143 } 144 145 @Override 146 public boolean getScrollableTracksViewportHeight() { 147 Container parent = getParent(); 148 if (parent != null) { 149 return parent.getHeight() > getPreferredSize().height; 150 } 151 else { 152 return false; 153 } 154 } 155 156 @Override 157 public TableCellRenderer getCellRenderer(int row, int column) { 158 if (this.getColumnClass(column) == Color.class) { 159 return new ColorTableCellRenderer(); 160 } 161 else { 162 return super.getCellRenderer(row, column); 163 } 164 } 165 166 @Override 167 public TableCellEditor getCellEditor(int row, int column) { 168 if (this.getColumnClass(column) == Color.class) { 169 return new ColorTableCellEditor(); 170 } 171 else if (this.getColumnClass(column) == PointType.class) { 172 if (pointTypeChoices == null) { 173 pointTypeChoices = new JComboBox(); 174 for (PointType pointType : PointType.values()) { 175 pointTypeChoices.addItem(pointType); 176 } 177 } 178 return new DefaultCellEditor(pointTypeChoices); 179 } 180 else { 181 return super.getCellEditor(row, column); 182 } 183 } 184 185 private JComboBox pointTypeChoices = null; 186 187 private void insertDemoData() { 188 Model model = (Model) this.getModel(); 189 model.addRow(new Row("sensor0", "time", "sensor0.data", PointType.CIRCLE, Color.BLACK, this.getPlotEditor())); 190 model.addRow(new Row("sensor1", "time", "sensor1.data", PointType.SQUARE, Color.BLUE, this.getPlotEditor())); 191 model.addRow(new Row("sensor2", "time", "sensor2.data", PointType.DIAMOND, Color.GREEN, this.getPlotEditor())); 192 } 193 194 public void setActive(boolean active) { 195 if (!active) { 196 // insertDemoData(); 197 } 198 } 199 200 public PlotEditor getPlotEditor() { 201 return plotEditor; 202 } 203 204 private void setPlotEditor(PlotEditor plotEditor) { 205 this.plotEditor = plotEditor; 206 } 207 208 public void setDataset(Dataset dataset) { 209 ((Model) this.getModel()).setDataset(dataset); 210 } 211 212 public PlottingControllerFactory getPlottingControllerFactory() { 213 return plottingControllerFactory; 214 } 215 216 public PlottingController getPlottingController() { 217 return plottingController; 218 } 219 220 public void actionPerformed(ActionEvent ae) { 221 222 DataTable table = getPlotEditor().getTable(); 223 int[] selectedRows = table.getSelectedRows(); 224 List<Row> rows = new ArrayList<Row>(); 225 for (int selectedRow : selectedRows) { 226 rows.add(table.getRow(selectedRow)); 227 } 228 229 for (Row row : rows) { 230 row.notifyDeletionListeners(); 231 table.removeRow(row); 232 } 233 table.update(); 234 } 235 236 private PlotEditor plotEditor = null; 237 private static PlottingControllerFactory plottingControllerFactory; 238 239 private class Model extends AbstractTableModel { 240 241 public void addRow(Row row) { 242 rows.add(row); 243 initializeController(); 244 getPlottingController().initialize(row, getPlotEditor().getPlot()); 245 this.getTable().setSize(new Dimension(2, 2)); 246 } 247 248// public void removeIndividualRow(Row row) { 249// removeRow(row); 250// SwingUtilities.invokeLater(new Runnable() { 251// public void run() { 252// fireTableDataChanged(); 253// } 254// }); 255// } 256 257 private void removeRow(Row row) { 258 rows.remove(row); 259 this.getTable().setSize(new Dimension(2, 2)); 260 } 261 262 public Row getRow(int index) { 263 return rows.get(index); 264 } 265 266 public int getRowCount() { 267 return rows.size(); 268 } 269 270 public int getColumnCount() { 271 return Row.getColumnCount(); 272 } 273 274 public String getColumnName(int columnIndex) { 275 return Row.getColumnName(columnIndex); 276 } 277 278 public Class<?> getColumnClass(int columnIndex) { 279 return Row.getColumnClass(columnIndex); 280 } 281 282 public boolean isCellEditable(int rowIndex, int columnIndex) { 283 return Row.isEditableColumns(columnIndex); 284 } 285 286 public Object getValueAt(int rowIndex, int columnIndex) { 287 return rows.get(rowIndex).getValueByIndex(columnIndex); 288 } 289 290 public void setValueAt(Object aValue, int rowIndex, int columnIndex) { 291 292 rows.get(rowIndex).setCandidateValue(columnIndex, aValue); 293 // rows.get(rowIndex).setValueByIndex(columnIndex, aValue); 294 295 UpdateType updateType = null; 296 if (columnIndex == 0) { 297 updateType = UpdateType.SENSOR_NAME; 298 } 299 else if (columnIndex == 1) { 300 updateType = UpdateType.X_AXIS; 301 } 302 else if (columnIndex == 2) { 303 updateType = UpdateType.Y_AXIS; 304 } 305 else if (columnIndex == 3) { 306 updateType = UpdateType.POINT_TYPE; 307 } 308 else if (columnIndex == 4) { 309 updateType = UpdateType.COLOR; 310 } 311 312 updateSensor(rows.get(rowIndex), updateType); 313 } 314 315 private void updateSensor(Row row, UpdateType updateType) { 316 initializeController(); 317 getPlottingController().register(row, updateType, getPlotEditor().getPlot()); 318 } 319 320 public void addTableModelListener(TableModelListener l) { 321 listeners.add(l); 322 } 323 324 public void removeTableModelListener(TableModelListener l) { 325 listeners.remove(l); 326 } 327 328 public void setDataset(Dataset dataset) { 329 this.dataset = dataset; 330 } 331 332 public void setTable(DataTable table) { 333 this.table = table; 334 } 335 336 public DataTable getTable() { 337 return table; 338 } 339 340 private List<Row> rows = new ArrayList<Row>(); 341 private List<TableModelListener> listeners = new ArrayList<TableModelListener>(); 342 private Dataset dataset = null; 343 private DataTable table; 344 } 345 346 private void initializeController() { 347 if (plottingController == null) { 348 plottingController = PlotsEditorPanel.getPlottingControllerFactory(). 349 getPlottingController(getPlotEditor().getEditorPanel().getParentFrame()); 350 } 351 } 352 353 private PlottingController plottingController = null; 354 355 private class MyTransferHandler extends TransferHandler { 356 357 public boolean canImport(JComponent component, DataFlavor[] flavors) { 358 for (DataFlavor flavor : flavors) { 359 if (PtolemyTransferable.namedObjFlavor.equals(flavor)) { 360 return true; 361 } 362 } 363 return false; 364 } 365 366 public boolean importData(JComponent component, Transferable tr) { 367 368 if (canImport(component, tr.getTransferDataFlavors())) { 369 try { 370 List droppedObjects = (List) tr.getTransferData(PtolemyTransferable.namedObjFlavor); 371 for (Object droppedObject : droppedObjects) { 372 TypedIOPort sensorDataPort = null; 373 if (droppedObject instanceof TypedIOPort) { 374 TypedIOPort port = (TypedIOPort) droppedObject; 375 if (isPlottablePort(port)) { 376 sensorDataPort = port; 377 } 378 } 379 380 if (sensorDataPort != null) { 381 // This is a plottable item 382 String sensorName = sensorDataPort.getFullName(); 383 Row row = new Row(sensorName, "time", sensorName, 384 PlottingConstants.DEFAULT_PLOT_ITEM_SHAPE, 385 PlottingConstants.DEFAULT_PLOT_ITEM_COLOR, getPlotEditor()); 386 row.setDataPort(sensorDataPort); 387 add(row); 388 getPlottingController().updatePlotManually(row); 389 } 390 } 391 return true; 392 } 393 catch(UnsupportedFlavorException e) { 394 e.printStackTrace(); 395 } 396 catch(IOException e) { 397 e.printStackTrace(); 398 } 399 } 400 return false; 401 } 402 403 public int getSourceActions(JComponent component) { 404 return COPY; 405 } 406 407 protected void exportDone(JComponent component, Transferable tr, int action) { 408 // System.out.println("Export done!: " + component); 409 } 410 } 411 412 private static boolean isPlottablePort(TypedIOPort port) { 413 Type type = port.getType(); 414 return type.isCompatible(PLOTTABLE_TYPE); 415 } 416 417 private static final Type PLOTTABLE_TYPE = new ArrayType(BaseType.INT, 2); 418 419 private JPopupMenu popupMenu = new JPopupMenu(); 420 private static final String REMOVE_ROW = "Delete"; 421 private JMenuItem removeRowMenuItem = new JMenuItem(REMOVE_ROW); 422 423 424}