package chatty.gui.components.admin;
import chatty.gui.components.settings.ListTableModel;
import chatty.util.DateTime;
import java.awt.Color;
import java.awt.Component;
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.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableRowSorter;
/**
*
* @author tduva
*/
public class StatusHistoryTable extends JTable {
private final Model data = new Model(new String[]{"Fav","Title","Game","Community","Last Activity","Usage"});
private final TableRowSorter sorter;
private final JPopupMenu contextMenu;
public StatusHistoryTable(JPopupMenu contextMenu) {
setModel(data);
// Disable because some stuff depends on the column id (although it
// is probably possible to do it differently)
getTableHeader().setReorderingAllowed(false);
setFillsViewportHeight(true);
sorter = new TableRowSorter(data);
this.contextMenu = contextMenu;
setRowSorter(sorter);
TableColumn tc = getColumnModel().getColumn(1);
tc.setCellRenderer(new LineWrapCellRenderer());
setGridColor(new Color(200,200,200));
getColumnModel().getColumn(4).setCellRenderer(new LastActivityRenderer());
getColumnModel().getColumn(0).setCellRenderer(new FavoriteRenderer());
setColumnWidth(0, 30, 30, 30);
setColumnWidth(1, 200, 0, 0);
setColumnWidth(2, 120, 0, 0);
setColumnWidth(3, 100, 0, 0);
setColumnWidth(4, 100, 100, 100);
setColumnWidth(5, 50, 50, 50);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
List<RowSorter.SortKey> sortKeys = new ArrayList<>();
sortKeys.add(new RowSorter.SortKey(3, SortOrder.DESCENDING));
sorter.setSortKeys(sortKeys);
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
int row = rowAtPoint(e.getPoint());
if (row != -1) {
setRowSelected(row);
} else if (getRowCount() > 0) {
setRowSelected(getRowCount() - 1);
}
popupMenu(e);
}
@Override
public void mouseReleased(MouseEvent e) {
popupMenu(e);
}
});
}
private void popupMenu(MouseEvent e) {
if (e.isPopupTrigger() && contextMenu != null) {
contextMenu.show(this, e.getX(), e.getY());
}
}
private void setColumnWidth(int column, int width, int minwidth, int maxwidth) {
TableColumn tc = getColumnModel().getColumn(column);
tc.setPreferredWidth(width);
if (maxwidth > 0) {
tc.setMaxWidth(maxwidth);
}
if (minwidth > 0) {
tc.setMinWidth(minwidth);
}
}
public void resetFilter() {
sorter.setRowFilter(null);
}
public void filter(final String game, final boolean favorites) {
if (game == null && !favorites) {
resetFilter();
} else {
sorter.setRowFilter(new RowFilter<Model, Integer>() {
@Override
public boolean include(RowFilter.Entry<? extends Model, ? extends Integer> entry) {
Model model = entry.getModel();
StatusHistoryEntry e = model.get(entry.getIdentifier());
if (game != null && !game.equals(e.game)) {
return false;
}
if (favorites && !e.favorite) {
return false;
}
return true;
}
});
}
}
public void setData(List<StatusHistoryEntry> newData) {
data.setData(newData);
}
/**
* Returns the selected {@code StatusHistoryEntry}.
*
* @return The selected {@code StatusHistoryEntry} or {@code null} if no
* entry is selected
*/
public StatusHistoryEntry getSelectedEntry() {
int modelIndex = indexToModel(getSelectedRow());
if (modelIndex == -1) {
return null;
}
return data.get(modelIndex);
}
/**
* Removes the given entry, if present in the table, and selects the next
* appropriate entry.
*
* @param entry
*/
public void removeEntry(StatusHistoryEntry entry) {
int indexToRemove = data.indexOf(entry);
if (indexToRemove != -1) {
int viewIndex = indexToView(indexToRemove);
data.remove(indexToRemove);
// Select appropriate row after removing
if (getRowCount() > viewIndex) {
setRowSelected(viewIndex);
} else if (viewIndex - 1 >= 0 && getRowCount() > viewIndex - 1) {
setRowSelected(viewIndex - 1);
}
}
}
/**
* Sets the given row as selected and scrolls to it if necessary.
*
* @param viewIndex
*/
private void setRowSelected(int viewIndex) {
getSelectionModel().setSelectionInterval(viewIndex, viewIndex);
scrollToRow(viewIndex);
}
/**
* Scrolls to the given row.
*
* @param index The view row index to scroll to
*/
private void scrollToRow(int index) {
if (index != -1) {
scrollRectToVisible(getCellRect(index, 0, true));
}
}
/**
* Updates the given entry if already present in the table.
*
* @param entry
*/
public void updateEntry(StatusHistoryEntry entry) {
data.update(entry);
}
/**
* Convert a view index to model index.
*
* @param index The index to convert
* @return The converted index, or {@code -1} if {@code index} was
* {@code -1}
*/
private int indexToModel(int index) {
if (index == -1) {
return -1;
}
return convertRowIndexToModel(index);
}
/**
* Convert a model index to view index.
*
* @param index The index to convert
* @return The corresponding index of the viliteralor {@code -1} if the row
* isn't visible
*/
private int indexToView(int index) {
return convertRowIndexToView(index);
}
private static class LineWrapCellRenderer extends JTextArea implements TableCellRenderer {
LineWrapCellRenderer() {
setWrapStyleWord(true);
setLineWrap(true);
}
@Override
public Component getTableCellRendererComponent(final JTable table, Object value, boolean isSelected, boolean hasFocus, final int row, int column) {
setText((String)value);
int cWidth = table.getTableHeader().getColumnModel().getColumn(column).getWidth();
setSize(new Dimension(cWidth, 1000));
final int height = getPreferredSize().height;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (table.getRowCount() > row) {
table.setRowHeight(row, height);
}
}
});
if (isSelected) {
setBackground(table.getSelectionBackground());
setForeground(table.getSelectionForeground());
} else {
setBackground(table.getBackground());
setForeground(table.getForeground());
}
return this;
}
}
private static class LastActivityRenderer extends DefaultTableCellRenderer {
@Override
public void setValue(Object value) {
if (value == null) {
return;
}
Long lastActivity = (Long)value;
setText(DateTime.agoText(lastActivity));
JLabel label = (JLabel)this;
label.setHorizontalAlignment(JLabel.CENTER);
}
}
private static class FavoriteRenderer extends DefaultTableCellRenderer {
ImageIcon icon = new ImageIcon(getClass().getResource("/chatty/gui/star.png"));
@Override
public void setValue(Object value) {
if (value instanceof Boolean) {
if ((Boolean)value) {
this.setIcon(icon);
}
else {
this.setIcon(null);
}
JLabel label = (JLabel)this;
label.setHorizontalAlignment(JLabel.CENTER);
}
}
}
private static class Model extends ListTableModel<StatusHistoryEntry> {
Model(String[] columns) {
super(columns);
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
StatusHistoryEntry entry = get(rowIndex);
if (columnIndex == 0) {
return entry.favorite;
} else if (columnIndex == 1) {
return entry.title;
} else if (columnIndex == 2) {
return entry.game;
} else if (columnIndex == 3) {
return entry.community.getName();
} else if (columnIndex == 4) {
return entry.lastActivity;
} else if (columnIndex == 5) {
return entry.timesUsed;
}
return null;
}
/**
* Return classes so the table does the correct sorting etc.
*
* @param columnIndex
* @return
*/
@Override
public Class getColumnClass(int columnIndex) {
if (columnIndex == 0) {
return Boolean.class;
}
if (columnIndex == 4) {
return Long.class;
}
if (columnIndex == 5) {
return Integer.class;
}
return String.class;
}
}
}