package de.unisiegen.gtitool.ui.swing;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import de.unisiegen.gtitool.core.util.Theme;
import de.unisiegen.gtitool.ui.swing.dnd.JGTITableModelRows;
import de.unisiegen.gtitool.ui.swing.dnd.JGTITableModelRowsTransferable;
/**
* Special {@link JTable}.
*
* @author Christian Fehler
* @version $Id$
*/
public final class JGTITable extends JTable implements DropTargetListener
{
/**
* The serial version uid.
*/
private static final long serialVersionUID = 6702446627778010971L;
/**
* The between drag and drop mode.
*
* @see #getDndMode()
* @see #setDndMode(int)
*/
public static final int DROP_BETWEEN = 0;
/**
* The into drag and drop mode.
*
* @see #getDndMode()
* @see #setDndMode(int)
*/
public static final int DROP_INTO = 1;
/**
* The drop mode used for this {@link JGTITable}.
*
* @see #getDndMode()
* @see #setDndMode(int)
*/
private int dndMode = DROP_BETWEEN;
/**
* The current drop point or null if not dragging to this {@link JGTITable} at
* the moment.
*/
private Point dropPoint = null;
/**
* The allowed drag and drop sources.
*/
private ArrayList < JComponent > allowedDndSources;
/**
* Flag that indicates that the drag and drop is allowed.
*/
protected boolean dragAndDropAllowed = true;
/**
* Allocates a new {@link JGTITable}.
*/
public JGTITable ()
{
super ();
init ();
}
/**
* Allocates a new {@link JGTITable}.
*
* @param numRows The row number.
* @param numColumns The column number.
*/
public JGTITable ( int numRows, int numColumns )
{
super ( numRows, numColumns );
init ();
}
/**
* Allocates a new {@link JGTITable}.
*
* @param rowData The row data.
* @param columnNames The column names.
*/
public JGTITable ( final Object [][] rowData, final Object [] columnNames )
{
super ( rowData, columnNames );
init ();
}
/**
* Allocates a new {@link JGTITable}.
*
* @param dm The {@link TableModel}.
*/
public JGTITable ( TableModel dm )
{
super ( dm );
init ();
}
/**
* Allocates a new {@link JGTITable}.
*
* @param dm The {@link TableModel}.
* @param cm The {@link TableColumnModel}.
*/
public JGTITable ( TableModel dm, TableColumnModel cm )
{
super ( dm, cm );
init ();
}
/**
* Allocates a new {@link JGTITable}.
*
* @param dm The {@link TableModel}.
* @param cm The {@link TableColumnModel}.
* @param sm The {@link ListSelectionModel}.
*/
public JGTITable ( TableModel dm, TableColumnModel cm, ListSelectionModel sm )
{
super ( dm, cm, sm );
init ();
}
/**
* Allocates a new {@link JGTITable}.
*
* @param rowData The row data.
* @param columnNames The column names.
*/
public JGTITable ( Vector < ? > rowData, Vector < ? > columnNames )
{
super ( rowData, columnNames );
init ();
}
/**
* Adds the given {@link JComponent} to the allowed drag and drop sources.
*
* @param jComponent The {@link JComponent} to add.
*/
public final void addAllowedDndSource ( JComponent jComponent )
{
if ( !this.allowedDndSources.contains ( jComponent ) )
{
this.allowedDndSources.add ( jComponent );
}
}
/**
* Clears the allowed drag and drop sources.
*/
public final void clearAllowedDndSources ()
{
this.allowedDndSources.clear ();
}
/**
* {@inheritDoc}
*
* @see DropTargetListener#dragEnter(DropTargetDragEvent)
*/
public final void dragEnter ( DropTargetDragEvent dtde )
{
dragOver ( dtde );
}
/**
* {@inheritDoc}
*
* @see DropTargetListener#dragExit(DropTargetEvent)
*/
public final void dragExit (
@SuppressWarnings ( "unused" ) DropTargetEvent dte )
{
this.dropPoint = null;
repaint ();
}
/**
* {@inheritDoc}
*
* @see DropTargetListener#dragOver(DropTargetDragEvent)
*/
public final void dragOver ( DropTargetDragEvent event )
{
try
{
JGTITableModelRows rows = ( JGTITableModelRows ) event.getTransferable ()
.getTransferData ( JGTITableModelRowsTransferable.dataFlavor );
if ( !this.allowedDndSources.contains ( rows.getSource () ) )
{
event.rejectDrag ();
this.dropPoint = null;
repaint ();
return;
}
}
catch ( UnsupportedFlavorException exc )
{
event.rejectDrag ();
this.dropPoint = null;
repaint ();
return;
}
catch ( IOException exc )
{
event.rejectDrag ();
this.dropPoint = null;
repaint ();
return;
}
event.acceptDrag ( event.getDropAction () );
this.dropPoint = event.getLocation ();
repaint ();
}
/**
* {@inheritDoc}
*
* @see DropTargetListener#drop(DropTargetDropEvent)
*/
public final void drop ( DropTargetDropEvent event )
{
Point point = event.getLocation ();
this.dropPoint = point;
event.acceptDrop ( event.getDropAction () );
try
{
Transferable transferable = event.getTransferable ();
event.dropComplete ( getTransferHandler ().importData ( this,
transferable ) );
}
catch ( RuntimeException re )
{
event.dropComplete ( false );
}
this.dropPoint = null;
repaint ();
}
/**
* {@inheritDoc}
*
* @see DropTargetListener#dropActionChanged(DropTargetDragEvent)
*/
public final void dropActionChanged ( DropTargetDragEvent event )
{
dragOver ( event );
}
/**
* Returns the drag and drop mode of this {@link JGTIList}.
*
* @return The drag and drop mode of this {@link JGTIList}.
* @see #setDndMode(int)
*/
public final int getDndMode ()
{
return this.dndMode;
}
/**
* Returns the drop point.
*
* @return the drop point.
*/
public final Point getDropPoint ()
{
return this.dropPoint;
}
/**
* {@inheritDoc}
*
* @see JComponent#getPreferredSize()
*/
@Override
public final Dimension getPreferredSize ()
{
Dimension size = super.getPreferredSize ();
Container parent = getParent ();
if ( parent instanceof JViewport )
{
parent = parent.getParent ();
if ( parent instanceof JScrollPane )
{
JScrollPane scrollPane = ( JScrollPane ) parent;
int height = scrollPane.getViewportBorderBounds ().height;
if ( size.height < height )
{
size.height = height;
}
}
}
return size;
}
/**
* Initializes this {@link JComponent}.
*/
private final void init ()
{
this.allowedDndSources = new ArrayList < JComponent > ();
// must be removed because of problems with the drag and drop
for ( MouseMotionListener current : getMouseMotionListeners () )
{
removeMouseMotionListener ( current );
}
// store the drag and drop allowed state
addMouseListener ( new MouseAdapter ()
{
@Override
public void mousePressed ( MouseEvent event )
{
JGTITable.this.dragAndDropAllowed = rowAtPoint ( event.getPoint () ) != -1;
}
} );
// swing bugfix
addMouseMotionListener ( new MouseMotionAdapter ()
{
/**
* {@inheritDoc}
*
* @see MouseMotionAdapter#mouseDragged(MouseEvent)
*/
@Override
public void mouseDragged ( MouseEvent event )
{
if ( getDragEnabled ()
&& ( ( event.getModifiers () & InputEvent.BUTTON1_MASK ) != 0 )
&& JGTITable.this.dragAndDropAllowed )
{
TransferHandler transferHandler = getTransferHandler ();
transferHandler.exportAsDrag ( JGTITable.this, event, transferHandler
.getSourceActions ( JGTITable.this ) );
event.consume ();
}
}
} );
setDropTarget ( new DropTarget ( this, this ) );
// disable cut, copy and paste
getActionMap ().put ( "cut", new AbstractAction () { //$NON-NLS-1$
/**
* The serial version uid.
*/
private static final long serialVersionUID = 2442639750331718901L;
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent e )
{
// do nothing
}
} );
getActionMap ().put ( "copy", new AbstractAction () { //$NON-NLS-1$
/**
* The serial version uid.
*/
private static final long serialVersionUID = 4781268710775959195L;
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent e )
{
// do nothing
}
} );
getActionMap ().put ( "paste", new AbstractAction () { //$NON-NLS-1$
/**
* The serial version uid.
*/
private static final long serialVersionUID = 8934656186755813050L;
public void actionPerformed (
@SuppressWarnings ( "unused" ) ActionEvent e )
{
// do nothing
}
} );
}
/**
* {@inheritDoc}
*
* @see Component#isEnabled()
*/
@Override
public final boolean isEnabled ()
{
return super.isEnabled ();
}
/**
* {@inheritDoc}
*
* @see JComponent#paintComponent(Graphics)
*/
@Override
protected final void paintComponent ( Graphics graphics )
{
super.paintComponent ( graphics );
if ( this.dropPoint != null )
{
int rowIndex = rowAtPoint ( this.dropPoint );
if ( this.dndMode == DROP_BETWEEN )
{
int y = 0;
if ( rowIndex < 0 )
{
rowIndex = getRowCount ();
}
while ( --rowIndex >= 0 )
{
y += getRowHeight ( rowIndex );
}
if ( y > 0 )
{
y -= 1;
}
int width = getWidth () - 1;
int size = 3;
// Color
graphics.setColor ( Color.BLACK );
// Line
graphics.drawLine ( size, y, width - size, y );
graphics.drawLine ( size, y + 1, width - size, y + 1 );
// Left upper
graphics.drawLine ( size, y, 0, y - size );
graphics.drawLine ( size, y + 1, 0, y - size + 1 );
// Left lower
graphics.drawLine ( size, y, 0, y + size );
graphics.drawLine ( size, y + 1, 0, y + size + 1 );
// Right upper
graphics.drawLine ( width - size, y, width, y - size );
graphics.drawLine ( width - size, y + 1, width, y - size + 1 );
// Right lower
graphics.drawLine ( width - size, y, width, y + size );
graphics.drawLine ( width - size, y + 1, width, y + size + 1 );
}
else if ( this.dndMode == DROP_INTO )
{
Rectangle r = getVisibleRect ();
graphics.setColor ( Color.BLACK );
graphics.drawRect ( 0, r.y, r.width - 1, r.height - 1 );
}
else
{
throw new RuntimeException ( "dnd mode is invalid" ); //$NON-NLS-1$
}
}
}
/**
* Removes the given {@link JComponent} from the allowed drag and drop
* sources.
*
* @param jComponent The {@link JComponent} to remove.
*/
public final void removeAllowedDndSource ( JComponent jComponent )
{
this.allowedDndSources.remove ( jComponent );
}
/**
* Sets the drag and drop mode of this {@link JGTITable}.
*
* @param dndMode The new drag and drop mode.
*/
public final void setDndMode ( int dndMode )
{
if ( ( dndMode != DROP_BETWEEN ) && ( dndMode != DROP_INTO ) )
{
throw new IllegalArgumentException ( "dnd mode is invalid" ); //$NON-NLS-1$
}
this.dndMode = dndMode;
}
/**
* {@inheritDoc}
*
* @see JComponent#setEnabled(boolean)
*/
@Override
public final void setEnabled ( boolean enabled )
{
super.setEnabled ( enabled );
getTableHeader ().setEnabled ( enabled );
getTableHeader ().setResizingAllowed ( enabled );
if ( enabled )
{
setBackground ( Color.WHITE );
}
else
{
setBackground ( Theme.DISABLED_COMPONENT_COLOR );
}
}
}