package DisplayProject.controls;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.awt.event.MouseListener;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableModelEvent;
import DisplayProject.DisplayNode;
import DisplayProject.PsuedoDoubleClickAction;
import DisplayProject.TableSorter;
/**
* If the list view is in details mode (Constants.LT_DETAIL), then it will use this class.
*
* @author Craig Mitchell
* @since 10/04/2008
*/
@SuppressWarnings("serial")
public class ListViewTable extends JTable {
private ListView parent;
private DisplayNode selectedNode = null;
public ListViewTable(ListView pParent, Font font) {
this.parent = pParent;
this.setName( "InnerTable" );
this.setDoubleBuffered(true);
this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
this.getTableHeader().setReorderingAllowed(false);
this.setShowGrid(false);
this.setColumnSelectionAllowed(false);
this.setCellSelectionEnabled(false);
this.setRowSelectionAllowed(true);
this.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), PsuedoDoubleClickAction.PSUED0_DOUBLE_CLICK);
this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.SHIFT_MASK),PsuedoDoubleClickAction.PSUED0_DOUBLE_CLICK);
this.getActionMap().put(PsuedoDoubleClickAction.PSUED0_DOUBLE_CLICK, new PsuedoDoubleClickAction());
this.setBackground(java.awt.Color.WHITE); // Set the rest of the JTable to have a white background to mirror the Forte one
this.setInheritsPopupMenu(true); //PM:9/10/07 ensure the popup is available in table mode
if (font != null) {
this.setFont(font);
// JCT-496 In Forte the Header and the Data have the same font
this.getTableHeader().setFont(font);
}
FontMetrics fm = this.getFontMetrics(this.getFont());
this.setRowHeight(fm.getHeight());
// TF:21/11/07: Workaround for sun bug 4473075. If the preferred size of the
// table is set, if there are too many columns in the list view to be displayed
// on the screen without scrolling, scrolling the resulting viewport may result
// in corruption of the table header. This only occurs if the preferred size is
// set, so do not set the preferred size. See:
//
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4473075
//
// JTableHeader h = this.getTableHeader();
//h.setPreferredSize(new Dimension(h.getWidth(), (int)(fm.getHeight() * 1.25)));
this.setBackground(java.awt.Color.WHITE); // Set the rest of the JTable to have a white background to mirror the Forte one
this.setDoubleBuffered(true);
// Disable the auto-scroll on JTable
this.setAutoscrolls(false);
// CraigM:07/07/2008 - Set a new UI that allows multiple selection for drag and drop.
this.setUI(new ListViewTableUI());
}
/*
* Override processKeyEvent() so the tab key moves focus to the next/previous
* component in the form rather than move within the table.
*/
@Override
protected void processKeyEvent( KeyEvent ke ) {
if (ke.getKeyChar() == KeyEvent.VK_TAB) {
if (ke.getID() == KeyEvent.KEY_TYPED) {
KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
if (ke.isShiftDown()) {
focusManager.focusPreviousComponent();
} else {
focusManager.focusNextComponent();
}
}
ke.consume();
} else if (ke.getKeyCode() == KeyEvent.VK_DOWN
|| ke.getKeyCode() == KeyEvent.VK_UP
|| ke.getKeyCode() == KeyEvent.VK_RIGHT
|| ke.getKeyCode() == KeyEvent.VK_LEFT
|| ke.getKeyCode() == KeyEvent.VK_PAGE_DOWN
|| ke.getKeyCode() == KeyEvent.VK_PAGE_UP) {
this.setAutoscrolls(true);
super.processKeyEvent(ke);
this.setAutoscrolls(false);
} else {
super.processKeyEvent(ke);
this.parent.doKeyScroller(ke);
}
}
// After sorting, re-select the previously selected entry in the table.
@Override
public void tableChanged(TableModelEvent e) {
super.tableChanged(e);
// -----------------------------------------------------------------------------------------
// the Sorting list model we put in for lists is a delegating list in that all of the method
// calls delegate through to the underlying ArrayListModel. However, it doesn't seem to
// re-fire the events through to this model which needs them. So we explicitly do it here.
// -----------------------------------------------------------------------------------------
// Yes, we do need the check of this if called whilst in the constructor
if (this.parent != null && this.parent.getListViewTableModel() != null) {
this.parent.getListViewTableModel().tableChanged(e);
}
if (getSelectionModel().getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) {
if (selectedNode != null) {
if (getModel() instanceof TableSorter) {
((TableSorter)getModel()).selectRow(selectedNode);
}
}
}
}
// Record the selected row when in single selection mode.
//This is so the row can be selected again after sorting.
public void setRowSelectionInterval(int index0, int index1) {
super.setRowSelectionInterval(index0, index1);
if (getSelectionModel().getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) {
if (parent.getListViewTableModel() != null) {
selectedNode = parent.getListViewTableModel().getCurrentRow();
}
}
}
// Record row selections so as to keep track of the selected row after sorting
public void valueChanged(ListSelectionEvent e) {
super.valueChanged(e);
if (getSelectionModel().getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) {
if (getSelectedRow() > -1) {
if (getSelectedRow() < parent.getListViewTableModel().getRowCount()) {
selectedNode = parent.getListViewTableModel().getCurrentRow();
}
else {
// The table has changed under the selection, remove the selection
clearSelection();
}
}
}
}
// Prevent the deselection of the selected row (CTRL + mouse click) when in
//single selection mode.
public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
// TF:05/05/2009:Simplified
if (getSelectionModel().getSelectionMode() == ListSelectionModel.SINGLE_SELECTION && rowIndex >= 0) {
super.changeSelection(rowIndex, columnIndex, false, extend);
}
else {
super.changeSelection(rowIndex, columnIndex, toggle, extend);
}
}
/* (non-Javadoc)
* @see java.awt.Component#addMouseListener(java.awt.event.MouseListener)
*/
@Override
public synchronized void addMouseListener(MouseListener l) {
// AGD 7/3/08
// Make sure that the drag mouse listner is always last registered
// this ensures that the other events get processed before the Drag
// happens. This is the same sequence as Forte.
MouseListener[] mlList = this.getMouseListeners();
// Check if the Drag mouse listener is there
MouseListener foundDragListener = null;
for (int i = 0; i < mlList.length; i++) {
// instanceof does not work with a static inner class so using the name instead
if (mlList[i].getClass().getName().equals("javax.swing.plaf.basic.BasicTableUI$TableDragGestureRecognizer")) {
foundDragListener = mlList[i];
// remove the found Drag Listener to be added later
this.removeMouseListener(foundDragListener);
//assume there is only one and break
break;
};
}
// Add the Listener
super.addMouseListener(l);
// Add the found Drag listener at the end if it exists
if (foundDragListener != null) {
super.addMouseListener(foundDragListener);
}
}
public boolean getIsDropHighlightEnabled() {
return this.parent.getIsDropHighlightEnabled();
}
public boolean getHasRowHighlights() {
return this.parent.getHasRowHighlights();
}
}