/*
* Get Organized - Organize your schedule, course assignments, and grades
* Copyright © 2012 Alex Laird
* getorganized@alexlaird.com
* alexlaird.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package adl.go.gui;
import adl.go.resource.Utility;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
/**
* An extended JTable with additional functionality, including stripped rows.
*
* @author Alex Laird
*/
public class ExtendedJTable extends JTable
{
/**
* The alternating row colors.
*/
private Color rowColors[] = new Color[2];
/**
* The reference to the utility.
*/
private Utility utility;
/**
* True when the selection interval is being removed, false otherwise.
*/
protected boolean removingSelectionInterval = false;
/**
* True if stripes should be drawn, false otherwise.
*/
private boolean drawStripes = false;
/**
* Sets the utility pointer.
*
* @param utility The utility reference.
*/
public void setUtility(Utility utility)
{
this.utility = utility;
}
/**
* Call this when the data or attributes within the table have changed to
* update the interface display.
*/
public void refreshTable()
{
invalidate ();
repaint ();
getTableHeader ().resizeAndRepaint ();
}
/**
* Retrieves the index relative to the model of this table from finding the
* element attached to the absolute index (relative to the database) passed
* in to this method.
*
* @param index The absolute index relative to the database structure.
* @return The index relative to the table.
*/
public int getSelectableRowFromVectorIndex(int index)
{
int newIndex = -1;
if (index != -1)
{
long uniqueID = utility.assignmentsAndEvents.get (index).getUniqueID ();
for (int i = 0; i < getRowCount (); ++i)
{
if (Long.parseLong (getModel ().getValueAt (i, 6).toString ()) == uniqueID)
{
newIndex = i;
break;
}
}
}
return newIndex;
}
/**
* Sets the selected row in the assignments table from a vector index.
*
* @param index The vector index.
*/
public void setSelectedRowFromVectorIndex(int index)
{
setSelectedRow (getSelectableRowFromVectorIndex (index));
}
/**
* Retrieves the vector index for the selected row.
*
* @param row The row to be used to find.
* @return The index of the assignment or event in the vector.
*/
public int getVectorIndexFromSelectedRow(int row)
{
if (row != -1)
{
return utility.getAssignmentOrEventIndexByID (Long.parseLong (getModel ().getValueAt (row, 6).toString ()));
}
else
{
return -1;
}
}
/**
* Retrieves the vector index for the selected row.
*
* @return The index of the assignment or event in the vector.
*/
public int getVectorIndexFromSelectedRow() throws NullPointerException
{
if (getSelectedRow () != -1)
{
return utility.getAssignmentOrEventIndexByID (Long.parseLong (getModel ().getValueAt (getSelectedRow (), 6).toString ()));
}
else
{
return -1;
}
}
/**
* Sets the selected row in the table based on an index.
*
* @param index The index of the row to be set.
*/
public void setSelectedRow(int index)
{
if (index != -1)
{
getSelectionModel ().setSelectionInterval (index, index);
}
else
{
removingSelectionInterval = true;
getSelectionModel ().removeSelectionInterval (getSelectedRow (), getSelectedRow ());
removingSelectionInterval = false;
}
invalidate ();
}
/**
* Sets the selected row in the table based upon a unique ID. The column
* holding the unique ID is passed in.
*
* @param id The id to be selected.
* @param column The index of the column where the unique ID is stored.
*/
public void setSelectedRow(long id, int column)
{
for (int i = 0; i < getRowCount (); ++i)
{
if (Long.parseLong (getModel ().getValueAt (i, column).toString ()) == id)
{
setSelectedRow (i);
break;
}
}
}
/**
* Add stripes between cells and behind non-opaque cells.
*/
@Override
public void paintComponent(Graphics g)
{
if (!(drawStripes = isOpaque ()))
{
super.paintComponent (g);
return;
}
// paint background stripes
updateColors ();
final Insets insets = getInsets ();
final int w = getWidth () - insets.left - insets.right;
final int h = getHeight () - insets.top - insets.bottom;
final int x = insets.left;
int y = insets.top;
int localRowHeight = 16;
final int nItems = getRowCount ();
for (int i = 0; i < nItems; i++, y += localRowHeight)
{
localRowHeight = getRowHeight (i);
g.setColor (rowColors[i & 1]);
g.fillRect (x, y, w, localRowHeight);
}
final int nRows = nItems + (insets.top + h - y) / localRowHeight;
for (int i = nItems; i < nRows; i++, y += localRowHeight)
{
g.setColor (rowColors[i & 1]);
g.fillRect (x, y, w, localRowHeight);
}
final int remainder = insets.top + h - y;
if (remainder > 0)
{
g.setColor (rowColors[nRows & 1]);
g.fillRect (x, y, w, remainder);
}
// paint compoent
setOpaque (false);
super.paintComponent (g);
setOpaque (true);
}
/**
* Add background stripes behind rendered cells.
*/
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int col)
{
Component c = null;
if (getValueAt (row, col) != null)
{
c = super.prepareRenderer (renderer, row, col);
}
else
{
c = super.prepareRenderer (new DefaultTableCellRenderer (), row, col);
}
if (drawStripes && !isCellSelected (row, col))
{
c.setBackground (rowColors[row & 1]);
}
return c;
}
/**
* Add background stripes behind edited cells.
*/
@Override
public Component prepareEditor(TableCellEditor editor, int row, int col)
{
final Component c = super.prepareEditor (editor, row, col);
if (drawStripes && !isCellSelected (row, col))
{
c.setBackground (rowColors[row & 1]);
}
return c;
}
/**
* Retrieves the cell renderer for the specific cell.
*
* @param row The row to retrieve the renderer for.
* @param column The column to retrieve the renderer for.
* @return The cell renderer for the specific cell.
*/
@Override
public TableCellRenderer getCellRenderer(int row, int column)
{
Object value = getValueAt (row, column);
if (value != null)
{
return getDefaultRenderer (value.getClass ());
}
return super.getCellRenderer (row, column);
}
/**
* Force the table to fill the viewport's height.
*/
@Override
public boolean getScrollableTracksViewportHeight()
{
final Component c = getParent ();
if (!(c instanceof JViewport))
{
return false;
}
return ((JViewport) c).getHeight () > getPreferredSize ().height;
}
/**
* Updates the colors accordingly for the cell for odd and even.
*/
private void updateColors()
{
try
{
rowColors[0] = utility.currentTheme.colorOdd;
rowColors[1] = utility.currentTheme.colorEven;
}
catch (NullPointerException ex)
{
rowColors[0] = Color.WHITE;
rowColors[1] = new Color (237, 240, 242);
}
}
}