Moved table UI classes into their own package

This commit is contained in:
Vhati 2013-11-19 02:06:29 -05:00
parent ccff62d261
commit 6ca3fad77b
6 changed files with 161 additions and 98 deletions

View file

@ -0,0 +1,117 @@
package net.vhati.modmanager.ui.table;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import net.vhati.modmanager.core.ModInfo;
import net.vhati.modmanager.ui.table.Reorderable;
public class ChecklistTableModel<T> extends AbstractTableModel implements Reorderable {
private static final int COLUMN_CHECK = 0;
private static final int COLUMN_PAYLOAD = 1;
private static final int DATA_CHECK = 0;
private static final int DATA_PAYLOAD = 1;
private String[] columnNames = new String[] {"?", "Name"};
private Class[] columnTypes = new Class[] {Boolean.class, String.class};
private List<List<Object>> rowsList = new ArrayList<List<Object>>();
public void addItem( T o ) {
insertItem( rowsList.size(), false, o );
}
public void insertItem( int row, boolean selected, T o ) {
int newRowIndex = rowsList.size();
List<Object> rowData = new ArrayList<Object>();
rowData.add( new Boolean(selected) );
rowData.add( o );
rowsList.add( row, rowData );
fireTableRowsInserted( row, row );
}
public void removeItem( int row ) {
rowsList.remove( row );
fireTableRowsDeleted( row, row );
}
public void removeAllItems() {
rowsList.clear();
fireTableDataChanged();
}
@SuppressWarnings("unchecked")
public T getItem( int row ) {
return (T)rowsList.get(row).get(DATA_PAYLOAD);
}
@Override
public void reorder( int fromRow, int toRow ) {
if ( toRow > fromRow ) toRow--;
List<Object> rowData = rowsList.get( fromRow );
rowsList.remove( fromRow );
fireTableRowsDeleted( fromRow, fromRow );
rowsList.add( toRow, rowData );
fireTableRowsInserted( toRow, toRow );
}
public void setSelected( int row, boolean b ) {
rowsList.get(row).set( DATA_CHECK, new Boolean(b) );
fireTableRowsUpdated( row, row );
}
@SuppressWarnings("unchecked")
public boolean isSelected( int row ) {
return ((Boolean)rowsList.get(row).get(DATA_CHECK)).booleanValue();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public int getRowCount() {
return rowsList.size();
}
@Override
public Object getValueAt( int row, int column ) {
if ( column == COLUMN_CHECK ) {
return rowsList.get(row).get(DATA_CHECK);
}
else if ( column == COLUMN_PAYLOAD ) {
Object o = rowsList.get(row).get(DATA_PAYLOAD);
return o.toString();
}
throw new ArrayIndexOutOfBoundsException();
}
@Override
@SuppressWarnings("unchecked")
public void setValueAt( Object o, int row, int column ) {
if ( column == COLUMN_CHECK ) {
Boolean bool = (Boolean)o;
rowsList.get(row).set( DATA_CHECK, bool );
fireTableRowsUpdated( row, row );
}
}
@Override
public boolean isCellEditable( int row, int column ) {
if ( column == COLUMN_CHECK ) return true;
return false;
}
@Override
public Class getColumnClass( int column ) {
return columnTypes[column];
}
}

View file

@ -0,0 +1,134 @@
package net.vhati.modmanager.ui.table;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DropMode;
import javax.swing.ListSelectionModel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import net.vhati.modmanager.core.ModFileInfo;
import net.vhati.modmanager.ui.table.ChecklistTableModel;
import net.vhati.modmanager.ui.table.TableRowTransferHandler;
public class ChecklistTablePanel<T> extends JPanel {
protected ChecklistTableModel<T>tableModel;
protected JTable table;
public ChecklistTablePanel() {
super( new BorderLayout() );
tableModel = new ChecklistTableModel<T>();
table = new JTable( tableModel );
table.setFillsViewportHeight( true );
table.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
table.setTableHeader( null );
table.getColumnModel().getColumn(0).setMinWidth(30);
table.getColumnModel().getColumn(0).setMaxWidth(30);
table.getColumnModel().getColumn(0).setPreferredWidth(30);
JScrollPane scrollPane = new JScrollPane( null, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
scrollPane.setViewportView( table );
//scrollPane.setColumnHeaderView( null ); // Counterpart to setTableHeader().
scrollPane.setPreferredSize( new Dimension(Integer.MIN_VALUE, Integer.MIN_VALUE) );
this.add( scrollPane, BorderLayout.CENTER );
// Double-click toggles checkboxes.
table.addMouseListener(new MouseAdapter() {
int prevRow = -1;
int streak = 0;
@Override
public void mouseClicked( MouseEvent e ) {
if ( e.getSource() != table ) return;
int thisRow = table.rowAtPoint( e.getPoint() );
// Reset on first click and when no longer on that row.
if ( e.getClickCount() == 1 ) prevRow = -1;
if ( thisRow != prevRow || thisRow == -1 ) {
streak = 1;
prevRow = thisRow;
return;
} else {
streak++;
}
if ( streak % 2 != 0 ) return; // Respond only to click pairs.
// Don't further toggle a multi-clicked checkbox.
int viewCol = table.columnAtPoint( e.getPoint() );
int modelCol = table.getColumnModel().getColumn(viewCol).getModelIndex();
if ( modelCol == 0 ) return;
int selRow = table.getSelectedRow();
if ( selRow != -1 ) {
boolean selected = tableModel.isSelected( selRow );
tableModel.setSelected( selRow, !selected );
}
}
});
table.setTransferHandler( new TableRowTransferHandler( table ) );
table.setDropMode( DropMode.INSERT ); // Drop between rows, not on them.
table.setDragEnabled( true );
}
public void clear() {
tableModel.removeAllItems();
}
public List<T> getAllItems() {
List<T> results = new ArrayList<T>();
for ( int i=0; i < tableModel.getRowCount(); i++ ) {
results.add( tableModel.getItem(i) );
}
return results;
}
public List<T> getSelectedItems() {
List<T> results = new ArrayList<T>();
for ( int i=0; i < tableModel.getRowCount(); i++ ) {
if ( tableModel.isSelected(i) ) {
results.add( tableModel.getItem(i) );
}
}
return results;
}
public void toggleAllItemSelection() {
int selectedCount = 0;
for ( int i = tableModel.getRowCount()-1; i >= 0; i-- ) {
if ( tableModel.isSelected(i) ) selectedCount++;
}
boolean b = ( selectedCount != tableModel.getRowCount() );
for ( int i = tableModel.getRowCount()-1; i >= 0; i-- ) {
tableModel.setSelected( i, b );
}
}
public ChecklistTableModel<T> getTableModel() {
return tableModel;
}
public JTable getTable() {
return table;
}
}

View file

@ -0,0 +1,9 @@
package net.vhati.modmanager.ui.table;
public interface Reorderable {
/**
* Moves an element at fromIndex to toIndex.
*/
public void reorder( int fromIndex, int toIndex );
}

View file

@ -0,0 +1,131 @@
package net.vhati.modmanager.ui.table;
import java.awt.Cursor;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DragSource;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.TransferHandler;
import net.vhati.modmanager.ui.table.Reorderable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Allows drag and drop reordering of JTable rows.
*
* Its TableModel must implement the Reorderable interface.
*/
public class TableRowTransferHandler extends TransferHandler {
private static final Logger log = LogManager.getLogger(TableRowTransferHandler.class);
private DataFlavor localIntegerFlavor = null;
private JTable table = null;
public TableRowTransferHandler( JTable table ) {
super();
if ( table.getModel() instanceof Reorderable == false ) {
throw new IllegalArgumentException( "The tableModel doesn't implement Reorderable." );
}
this.table = table;
try {
localIntegerFlavor = new DataFlavor( DataFlavor.javaJVMLocalObjectMimeType + ";class=\""+ Integer.class.getName() +"\"" );
}
catch ( ClassNotFoundException e ) {
log.error( e );
}
}
@Override
protected Transferable createTransferable( JComponent c ) {
assert ( c == table );
int row = table.getSelectedRow();
return new IntegerTransferrable( new Integer(row) );
}
@Override
public boolean canImport( TransferHandler.TransferSupport ts ) {
boolean b = ( ts.getComponent() == table && ts.isDrop() && ts.isDataFlavorSupported(localIntegerFlavor) );
table.setCursor( b ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop );
return b;
}
@Override
public int getSourceActions( JComponent comp ) {
return TransferHandler.MOVE;
}
@Override
@SuppressWarnings("Unchecked")
public boolean importData( TransferHandler.TransferSupport ts ) {
if ( !canImport(ts) ) return false;
JTable target = (JTable)ts.getComponent();
JTable.DropLocation dl = (JTable.DropLocation)ts.getDropLocation();
int dropRow = dl.getRow();
int rowCount = table.getModel().getRowCount();
if ( dropRow < 0 || dropRow > rowCount ) dropRow = rowCount;
target.setCursor( Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR) );
try {
Integer draggedRow = (Integer)ts.getTransferable().getTransferData(localIntegerFlavor);
if ( draggedRow != -1 && draggedRow != dropRow ) {
((Reorderable)table.getModel()).reorder( draggedRow, dropRow );
if ( dropRow > draggedRow ) dropRow--;
target.getSelectionModel().addSelectionInterval( dropRow, dropRow );
return true;
}
}
catch ( Exception e ) {
log.error( e );
}
return false;
}
@Override
protected void exportDone( JComponent source, Transferable data, int action ) {
if ( action == TransferHandler.MOVE || action == TransferHandler.NONE ) {
table.setCursor( Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR) );
}
}
/**
* Drag and drop Integer data, constructed with a raw object
* from a drag source, to be transformed into a flavor
* suitable for the drop target.
*/
private class IntegerTransferrable implements Transferable {
private Integer data;
public IntegerTransferrable( Integer data ) {
this.data = data;
}
@Override
public Object getTransferData( DataFlavor flavor ) {
if ( flavor.equals( localIntegerFlavor ) ) {
return data;
}
return null;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] {localIntegerFlavor};
}
@Override
public boolean isDataFlavorSupported( DataFlavor flavor ) {
return flavor.equals( localIntegerFlavor );
}
}
}