/* * Aphelion * Copyright (c) 2013 Joris van der Wel * * This file is part of Aphelion * * Aphelion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, version 3 of the License. * * Aphelion 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 Affero General Public License * along with Aphelion. If not, see <http://www.gnu.org/licenses/>. * * In addition, the following supplemental terms apply, based on section 7 of * the GNU Affero General Public License (version 3): * a) Preservation of all legal notices and author attributions * b) Prohibition of misrepresentation of the origin of this material, and * modified versions are required to be marked in reasonable ways as * different from the original version (for example by appending a copyright notice). * * Linking this library statically or dynamically with other modules is making a * combined work based on this library. Thus, the terms and conditions of the * GNU Affero General Public License cover the whole combination. * * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent modules, * and to copy and distribute the resulting executable under terms of your * choice, provided that you also meet, for each linked independent module, * the terms and conditions of the license of that module. An independent * module is a module which is not derived from or based on this library. */ package aphelion.launcher; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.logging.Logger; import javax.swing.*; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; /** * * @author Joris */ public class ZoneList extends JPanel { private static final Logger log = Logger.getLogger("aphelion.launcher"); private final ArrayList<ZoneEntry> entries; private JScrollPane scroll; private MyTableModel modal; private MyTable table; public ZoneList(final ArrayList<ZoneEntry> entries) { table = new MyTable(modal = new MyTableModel(entries), entries); scroll = new JScrollPane(table); add(scroll); this.entries = entries; scroll.setBorder(BorderFactory.createEmptyBorder()); table.setShowGrid(false); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); table.setColumnSelectionAllowed(false); table.setRowSelectionAllowed(true); table.getColumnModel().getColumn(0).setMinWidth(20); table.getColumnModel().getColumn(1).setMinWidth(30); table.getColumnModel().getColumn(3).setMinWidth(30); table.getColumnModel().getColumn(4).setMinWidth(30); table.getColumnModel().getColumn(0).setMaxWidth(60); table.getColumnModel().getColumn(1).setMaxWidth(60); table.getColumnModel().getColumn(3).setMaxWidth(60); table.getColumnModel().getColumn(4).setMaxWidth(60); addComponentListener(new ComponentAdapter() { @Override public void componentResized(final ComponentEvent e) { Dimension size = new Dimension(); getSize(size); size.height -= 4; // TODO: ??? scroll.setMaximumSize(size); scroll.setPreferredSize(size); } }); table.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { Point p = e.getPoint(); int rowIndex = table.convertRowIndexToModel(table.rowAtPoint(p)); int realColumnIndex = table.convertColumnIndexToModel(table.columnAtPoint(p)); if (realColumnIndex == 0) // favorite { ZoneEntry entry = getEntryByRow(rowIndex); if (entry != null) { entry.favorite = !entry.favorite; updatedEntries(); } } } }); } private ZoneEntry getEntryByRow(int row) { if (row >= 0 && row < entries.size()) { return entries.get(row); } return null; } public void updatedEntries() { int r = table.getSelectedRow(); modal.fireTableDataChanged(); if (r >= 0 &&r < entries.size()) { table.getSelectionModel().setSelectionInterval(r, r); } } public ZoneEntry getSelectedZoneEntry() { return getEntryByRow(table.getSelectedRow()); } public void addSelectionListener(ListSelectionListener e) { table.getSelectionModel().addListSelectionListener(e); } private static class MyTable extends JTable { private ArrayList<ZoneEntry> entries; MyTable(MyTableModel modal, ArrayList<ZoneEntry> entries) { super(modal); this.entries = entries; setAutoResizeMode(JTable.AUTO_RESIZE_OFF); } @Override public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { Component c = super.prepareRenderer(renderer, row, column); ZoneEntry entry = null; try { entry = entries.get(convertRowIndexToModel(row)); } catch (IndexOutOfBoundsException ex) { } if (!(c instanceof JLabel)) { return c; } JLabel label = (JLabel) c; label.setBorder(BorderFactory.createEmptyBorder()); // Hide the cell selection border final Color star = new Color(0x958800); final Color serverDown = new Color(0x990000); if (column == 0) { label.setForeground(star); label.setHorizontalAlignment(SwingConstants.CENTER); } else { boolean isServerDown = entry != null && entry.url != null && entry.ping < 0; label.setForeground(isServerDown ? serverDown : Color.BLACK); } return c; } @Override public boolean getScrollableTracksViewportWidth() { // if this table is smaller than the viewport, increase the size, // otherwise use scrollbars return getPreferredSize().width < getParent().getWidth(); } @Override public String getToolTipText(MouseEvent e) { java.awt.Point p = e.getPoint(); int rowIndex = convertRowIndexToModel(rowAtPoint(p)); //int colIndex = columnAtPoint(p); //int realColumnIndex = convertColumnIndexToModel(colIndex); try { ZoneEntry entry = entries.get(rowIndex); return entry.url == null ? null : entry.url.toString(); } catch (IndexOutOfBoundsException ex) { return null; } } } private static class MyTableModel extends AbstractTableModel { private ArrayList<ZoneEntry> entries; public MyTableModel(ArrayList<ZoneEntry> entries) { this.entries = entries; } @Override public String getColumnName(int column) { switch (column) { case 0: return "Favorite"; case 1: return "Ping"; case 2: return "Zone name"; case 3: return "Players"; case 4: return "Playing"; } return "???"; } @Override public int getColumnCount() { return 5; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } @Override public int getRowCount() { return entries.size(); } @Override public Object getValueAt(int rowIndex, int columnIndex) { if (rowIndex >= entries.size()) { return ""; // todo other types } ZoneEntry entry = entries.get(rowIndex); switch (columnIndex) { case 0: return entry.favorite ? "\u2605" : "\u2606"; case 1: return entry.ping < 0 ? "" : entry.ping; case 2: return entry.name; case 3: return entry.players < 0 ? "" : entry.players; case 4: return entry.playing < 0 ? "" : entry.playing; } return "???"; } } }