/*
* Copyright (C) Lennart Martens
*
* Contact: lennart.martens AT UGent.be (' AT ' to be replaced with '@')
*/
/*
* Created by IntelliJ IDEA.
* User: Lennart
* Date: 17-feb-03
* Time: 13:26:33
*/
package com.compomics.util.gui;
import org.apache.log4j.Logger;
import com.compomics.util.sun.TableSorter;
import com.compomics.util.gui.renderers.ByteArrayRenderer;
import com.compomics.util.gui.renderers.TimestampRenderer;
import com.compomics.util.AlternateRowColoursJTable;
import javax.swing.*;
import javax.swing.table.*;
import java.util.Vector;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.Transferable;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
/*
* CVS information:
*
* $Revision: 1.6 $
* $Date: 2009/08/02 13:23:46 $
*/
/**
* This class extends a JTable with specific cellrenderers for fields,
* retrieved from DB.
*
* @author Lennart Martens
*/
public class JTableForDB extends AlternateRowColoursJTable {
// Class specific log4j logger for JTableForDB instances.
Logger logger = Logger.getLogger(JTableForDB.class);
/**
* This String contains the date and time format.
*/
private String iDateTimeFormat = "dd-MM-yyyy HH:mm:ss";
/**
* This Vector holds the references to all the tables that have been created
* during the life cycle.
*/
private Vector iFrames = new Vector(5, 2);
/**
* Constructs a default <code>JTable</code> that is initialized with a default
* data model, a default column model, and a default selection
* model.
*
* @see #createDefaultDataModel
* @see #createDefaultColumnModel
* @see #createDefaultSelectionModel
*/
public JTableForDB() {
super();
this.setRenderers();
}
/**
* Constructs a <code>JTable</code> with <code>numRows</code>
* and <code>numColumns</code> of empty cells using
* <code>DefaultTableModel</code>. The columns will have
* names of the form "A", "B", "C", etc.
*
* @param numRows the number of rows the table holds
* @param numColumns the number of columns the table holds
* @see javax.swing.table.DefaultTableModel
*/
public JTableForDB(int numRows, int numColumns) {
super(numRows, numColumns);
this.setRenderers();
}
/**
* Constructs a <code>JTable</code> that is initialized with
* <code>dm</code> as the data model, <code>cm</code>
* as the column model, and a default selection model.
*
* @param dm the data model for the table
* @param cm the column model for the table
* @see #createDefaultSelectionModel
*/
public JTableForDB(TableModel dm, TableColumnModel cm) {
super(dm, cm);
this.setRenderers();
}
/**
* Constructs a <code>JTable</code> that is initialized with
* <code>dm</code> as the data model, a default column model,
* and a default selection model.
*
* @param dm the data model for the table
* @see #createDefaultColumnModel
* @see #createDefaultSelectionModel
*/
public JTableForDB(TableModel dm) {
super(dm);
this.setRenderers();
}
/**
* Constructs a <code>JTable</code> that is initialized with
* <code>dm</code> as the data model, <code>cm</code> as the
* column model, and <code>sm</code> as the selection model.
* If any of the parameters are <code>null</code> this method
* will initialize the table with the corresponding default model.
* The <code>autoCreateColumnsFromModel</code> flag is set to false
* if <code>cm</code> is non-null, otherwise it is set to true
* and the column model is populated with suitable
* <code>TableColumns</code> for the columns in <code>dm</code>.
*
* @param dm the data model for the table
* @param cm the column model for the table
* @param sm the row selection model for the table
* @see #createDefaultDataModel
* @see #createDefaultColumnModel
* @see #createDefaultSelectionModel
*/
public JTableForDB(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
super(dm, cm, sm);
this.setRenderers();
}
/**
* Constructs a <code>JTable</code> to display the values in the
* <code>Vector</code> of <code>Vectors</code>, <code>rowData</code>,
* with column names, <code>columnNames</code>. The
* <code>Vectors</code> contained in <code>rowData</code>
* should contain the values for that row. In other words,
* the value of the cell at row 1, column 5 can be obtained
* with the following code:
* <br><br>
* <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
* <br><br>
* Each row must contain a value for each column or an exception
* will be raised.
*
* @param rowData the data for the new table
* @param columnNames names of each column
*/
public JTableForDB(Vector rowData, Vector columnNames) {
super(rowData, columnNames);
this.setRenderers();
}
/**
* Constructs a <code>JTable</code> to display the values in the two dimensional array,
* <code>rowData</code>, with column names, <code>columnNames</code>.
* <code>rowData</code> is an array of rows, so the value of the cell at row 1,
* column 5 can be obtained with the following code:
* <br><br>
* <pre> rowData[1][5]; </pre>
* <br><br>
* All rows must be of the same length as <code>columnNames</code>.
*
* @param rowData the data for the new table
* @param columnNames names of each column
*/
public JTableForDB(Object[][] rowData, Object[] columnNames) {
super(rowData, columnNames);
this.setRenderers();
}
/**
* This method allows the setting of the date /time format.
*
* @param aFormat String with the datetimeformat.
*/
public void setDateTimeFormat(String aFormat) {
this.iDateTimeFormat = aFormat;
}
/**
* This method allows you to specify a tablemodel and a boolean
* which indicates whether or not the table should be sortable by
* clicking the column headers.
*
* @param aModel TableModel with the data.
* @param aSortable boolean that indicates whether the table should be sortable.
*/
public void setModel(TableModel aModel, boolean aSortable) {
TableModel tempModel = aModel;
if(aSortable) {
TableModel oldModel = super.getModel();
TableSorter sorter = new TableSorter(aModel);
if(sorter != null) {
if( (oldModel != null) && (oldModel instanceof TableSorter)) {
((TableSorter)oldModel).removeMouseListenerToHeaderInTable(this);
}
sorter.addMouseListenerToHeaderInTable(this);
}
tempModel = sorter;
}
super.setModel(tempModel);
}
/**
* Sets a TableModel for the table and defaults it to being sortable.
*
* @param aModel TableModel with the data for this table.
*/
public void setModel(TableModel aModel) {
if(aModel != null) {
this.setModel(aModel, true);
} else {
this.setModel(aModel, false);
}
}
/**
* This method will set some specific cell renderers for
* a table that is mostly used for displaying data from RDBMS systems.
*/
private void setRenderers() {
// Renderer for timestamps (displays date and time; default: "dd-MM-yyyy HH:mm:ss");
// The date/time format can be set using the setDateTimeFormat method.
this.setDefaultRenderer(java.sql.Timestamp.class, new TimestampRenderer());
// Renderer for byte[] (simple displays the sipmle fact that it contians a byte[]).
this.setDefaultRenderer(byte[].class, new ByteArrayRenderer());
// Now to detect doubleclicks on a cell.
// If the doubleclick is on a byte[], show it.
this.addMouseListener(new MouseAdapter() {
/**
* Invoked when the mouse has been clicked on a component.
*/
public void mouseClicked(MouseEvent e) {
// Transform clickpoint to row and column indices +
// retrieve the renderer at that location.
Point compLoc = e.getPoint();
int col = columnAtPoint(compLoc);
int row = rowAtPoint(compLoc);
TableCellRenderer comp = getCellRenderer(row, col);
// Right-click means: goto formatted results for datfile or server.
if(e.getModifiers() == MouseEvent.BUTTON3_MASK || e.getModifiers() == MouseEvent.BUTTON2_MASK) {
if(JTableForDB.this.rowSelectionAllowed) {
JTableForDB.this.setRowSelectionInterval(row, row);
} else {
JTableForDB.this.setColumnSelectionInterval(row, row);
}
} else if(e.getClickCount() >= 2) {
if(comp instanceof ByteArrayRenderer) {
// Creating the frame with the data from the model.
int modelCol = convertColumnIndexToModel(col);
JFrame frame = new JFrameForBytes("Display for byte[]", (byte[])getModel().getValueAt(row, modelCol));
// Add the frame to the cache.
iFrames.add(frame);
// Display and location stuff.
frame.setLocation(JTableForDB.this.getLocation().x + 50, JTableForDB.this.getLocation().x + 50);
frame.setVisible(true);
} else if((getColumnName(col) != null) && (getColumnName(col).toLowerCase().trim().equalsIgnoreCase("accession"))) {
// Get the data.
String accession = ((String)getValueAt(row, col)).trim();
// The URL will be stored here.
String url = null;
// Find out if it is SP or NCBI.
String upper = accession.toUpperCase();
if(upper.startsWith("Q") || upper.startsWith("O") || upper.startsWith("P")) {
// SwissProt.
url = "http://us.expasy.org/cgi-bin/niceprot.pl?" + accession;
} else if(Character.isDigit(accession.charAt(0))) {
url = "\"http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=protein&cmd=search&term=" + accession + "\"";
} else if(accession.toLowerCase().startsWith("ipi")) {
// Isoform '.x' annotation needs to be removed.
String tempAccession = accession;
url = "http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-e+[IPI:'" + tempAccession + "']";
}
// The process.
try {
Runtime.getRuntime().exec("startIexplore.cmd " + url);
} catch(Exception exc) {
logger.error(exc.getMessage(), exc);
JOptionPane.showMessageDialog((Component) comp, "Unable to open internet view of selected entry: " + exc.getMessage()
+ ".", "Unable to open browser window", JOptionPane.ERROR_MESSAGE);
}
}
}
super.mouseClicked(e);
}
});
// Now to detect <ctrl>+<c> combinations.
this.addKeyListener(new KeyAdapter() {
/**
* Invoked when a key has been pressed.
*/
public void keyPressed(KeyEvent e) {
if((e.isShiftDown()) && (e.getKeyCode() == KeyEvent.VK_C)) {
int col = JTableForDB.this.getSelectedColumn();
int row = JTableForDB.this.getSelectedRow();
if((col >= 0) && (row >= 0)) {
String value = JTableForDB.this.getValueAt(row, col).toString();
Object temp = new StringSelection(value);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents((Transferable)temp, (ClipboardOwner)temp);
}
} else {
super.keyPressed(e);
}
}
});
}
/**
* Called by the garbage collector on an object when garbage collection
* determines that there are no more references to the object.
* A subclass overrides the <code>finalize</code> method to dispose of
* system resources or to perform other cleanup.
* <p>
* The general contract of <tt>finalize</tt> is that it is invoked
* if and when the Java virtual
* machine has determined that there is no longer any
* means by which this object can be accessed by any thread that has
* not yet died, except as a result of an action taken by the
* finalization of some other object or class which is ready to be
* finalized. The <tt>finalize</tt> method may take any action, including
* making this object available again to other threads; the usual purpose
* of <tt>finalize</tt>, however, is to perform cleanup actions before
* the object is irrevocably discarded. For example, the finalize method
* for an object that represents an input/output connection might perform
* explicit I/O transactions to break the connection before the object is
* permanently discarded.
* <p>
* The <tt>finalize</tt> method of class <tt>Object</tt> performs no
* special action; it simply returns normally. Subclasses of
* <tt>Object</tt> may override this definition.
* <p>
* The Java programming language does not guarantee which thread will
* invoke the <tt>finalize</tt> method for any given object. It is
* guaranteed, however, that the thread that invokes finalize will not
* be holding any user-visible synchronization locks when finalize is
* invoked. If an uncaught exception is thrown by the finalize method,
* the exception is ignored and finalization of that object terminates.
* <p>
* After the <tt>finalize</tt> method has been invoked for an object, no
* further action is taken until the Java virtual machine has again
* determined that there is no longer any means by which this object can
* be accessed by any thread that has not yet died, including possible
* actions by other objects or classes which are ready to be finalized,
* at which point the object may be discarded.
* <p>
* The <tt>finalize</tt> method is never invoked more than once by a Java
* virtual machine for any given object.
* <p>
* Any exception thrown by the <code>finalize</code> method causes
* the finalization of this object to be halted, but is otherwise
* ignored.
*
* @throws Throwable the <code>Exception</code> raised by this method
*/
protected void finalize() throws Throwable {
int liSize = iFrames.size();
for(int i = 0; i < liSize; i++) {
JFrame lFrame = (JFrame)iFrames.elementAt(i);
if(lFrame != null) {
lFrame.setVisible(false);
lFrame.dispose();
}
}
super.finalize();
}
}