admin tools improves (#5388):

* added game ids and created time to tables list;
* added popup hints support to tables list;
* fixed wrong sorting and columns resizing in tables list;
* refactored some modules to share table related code between client and admin console;
This commit is contained in:
Oleg Agafonov 2024-03-22 16:48:34 +04:00
parent 50c75f05bd
commit fef37cdc73
14 changed files with 170 additions and 84 deletions

View file

@ -151,13 +151,6 @@
<version>1.17</version>
</dependency>
<!-- svg support END -->
<dependency>
<!-- time lib for GUI time info -->
<groupId>org.ocpsoft.prettytime</groupId>
<artifactId>prettytime</artifactId>
<version>4.0.6.Final</version>
</dependency>
</dependencies>
<!-- to get the reference to local repository with com\googlecode\jspf\jspf-core\0.9.1\ -->

View file

@ -6,6 +6,8 @@ import mage.client.util.GUISizeHelper;
import mage.client.util.MageTableRowSorter;
import mage.client.util.gui.TableUtil;
import mage.client.util.gui.countryBox.CountryCellRenderer;
import mage.components.table.MageTable;
import mage.components.table.TableInfo;
import mage.remote.MageRemoteException;
import mage.view.RoomUsersView;
import mage.view.UsersView;

View file

@ -13,6 +13,9 @@ import mage.client.util.MageTableRowSorter;
import mage.client.util.URLHandler;
import mage.client.util.gui.GuiDisplayUtil;
import mage.client.util.gui.TableUtil;
import mage.components.table.MageTable;
import mage.components.table.TableInfo;
import mage.components.table.TimeAgoTableCellRenderer;
import mage.constants.*;
import mage.game.match.MatchOptions;
import mage.players.PlayerType;
@ -155,19 +158,8 @@ public class TablesPanel extends javax.swing.JPanel {
final JToggleButton[] filterButtons;
// time formater
private final PrettyTime timeFormater = new PrettyTime(Locale.ENGLISH);
// time ago renderer
TableCellRenderer timeAgoCellRenderer = new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Date d = (Date) value;
label.setText(timeFormater.format(d));
return label;
}
};
// time formatter
private final PrettyTime timeFormatter = new PrettyTime(Locale.ENGLISH);
// duration renderer
TableCellRenderer durationCellRenderer = new DefaultTableCellRenderer() {
@ -177,8 +169,8 @@ public class TablesPanel extends javax.swing.JPanel {
Long ms = (Long) value;
if (ms != 0) {
Duration dur = timeFormater.approximateDuration(new Date(ms));
label.setText((timeFormater.formatDuration(dur)));
Duration dur = timeFormatter.approximateDuration(new Date(ms));
label.setText((timeFormatter.formatDuration(dur)));
} else {
label.setText("");
}
@ -298,13 +290,8 @@ public class TablesPanel extends javax.swing.JPanel {
initComponents();
// tableModel.setSession(session);
// formater
// change default just now from 60 to 30 secs
// see workaround for 4.0 versions: https://github.com/ocpsoft/prettytime/issues/152
TimeFormat timeFormat = timeFormater.removeUnit(JustNow.class);
JustNow newJustNow = new JustNow();
newJustNow.setMaxQuantity(1000L * 30L); // 30 seconds gap (show "just now" from 0 to 30 secs)
timeFormater.registerUnit(newJustNow, timeFormat);
// formatter
MageTable.fixTimeFormatter(this.timeFormatter);
// 1. TABLE CURRENT
tableTables.createDefaultColumnsFromModel();
@ -334,7 +321,7 @@ public class TablesPanel extends javax.swing.JPanel {
tableTables.setRowSorter(activeTablesSorter);
// time ago
tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_CREATED).setCellRenderer(timeAgoCellRenderer);
tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_CREATED).setCellRenderer(TimeAgoTableCellRenderer.getInstance());
// skill level
tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_SKILL).setCellRenderer(skillCellRenderer);
// seats
@ -545,7 +532,7 @@ public class TablesPanel extends javax.swing.JPanel {
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
int modelRow = TablesUtil.getSelectedModelRow(table);
int modelRow = MageTable.getSelectedModelRow(table);
if (modelRow != -1) {
// needs only selected
String rowId = TablesUtil.getSearchIdFromTable(table, modelRow);
@ -563,7 +550,7 @@ public class TablesPanel extends javax.swing.JPanel {
public void run() {
String lastRowID = tablesLastSelection.get(table);
int needModelRow = TablesUtil.findTableRowFromSearchId(table.getModel(), lastRowID);
int needViewRow = TablesUtil.getViewRowFromModel(table, needModelRow);
int needViewRow = MageTable.getViewRowFromModel(table, needModelRow);
if (needViewRow != -1) {
table.clearSelection();
table.addRowSelectionInterval(needViewRow, needViewRow);
@ -581,7 +568,7 @@ public class TablesPanel extends javax.swing.JPanel {
if (!SwingUtilities.isLeftMouseButton(e)) {
return;
}
int modelRow = TablesUtil.getSelectedModelRow(table);
int modelRow = MageTable.getSelectedModelRow(table);
if (e.getClickCount() == 2 && modelRow != -1) {
action.actionPerformed(new ActionEvent(table, ActionEvent.ACTION_PERFORMED, TablesUtil.getSearchIdFromTable(table, modelRow)));
}

View file

@ -1,6 +1,7 @@
package mage.client.table;
import mage.client.SessionHandler;
import mage.components.table.TableModelWithTooltip;
import mage.constants.SkillLevel;
import mage.remote.MageRemoteException;
import mage.view.TableView;

View file

@ -5,6 +5,8 @@ import org.apache.log4j.Logger;
import javax.swing.*;
/**
* GUI related
*
* @author JayDi85
*/
public class TablesUtil {
@ -42,22 +44,4 @@ public class TablesUtil {
}
return row;
}
public static int getSelectedModelRow(JTable table) {
return getModelRowFromView(table, table.getSelectedRow());
}
public static int getModelRowFromView(JTable table, int viewRow) {
if (viewRow != -1 && viewRow < table.getModel().getRowCount()) {
return table.convertRowIndexToModel(viewRow);
}
return -1;
}
public static int getViewRowFromModel(JTable table, int modelRow) {
if (modelRow != -1 && modelRow < table.getModel().getRowCount()) {
return table.convertRowIndexToView(modelRow);
}
return -1;
}
}

View file

@ -186,13 +186,6 @@ public final class GUISizeHelper {
}
}
public static String textToHtmlWithSize(String text, Font font) {
if (text != null && !text.toLowerCase(Locale.ENGLISH).startsWith("<html>")) {
return "<html><p style=\"font-size: " + font.getSize() + ";\">" + text + "</p>";
}
return text;
}
/**
* Return scrollbar settings, so user can scroll it more faster for bigger cards
*

View file

@ -43,6 +43,13 @@
<version>4.2.2.GA</version>
</dependency>
<dependency>
<!-- time lib for GUI time info -->
<groupId>org.ocpsoft.prettytime</groupId>
<artifactId>prettytime</artifactId>
<version>4.0.6.Final</version>
</dependency>
<dependency>
<!-- A dependency of jboss.remoting -->
<groupId>concurrent</groupId>

View file

@ -1,4 +1,4 @@
package mage.client.table;
package mage.components.table;
/**
* @author JayDi85

View file

@ -1,13 +1,17 @@
package mage.client.table;
package mage.components.table;
import mage.client.util.GUISizeHelper;
import org.apache.log4j.Logger;
import org.ocpsoft.prettytime.PrettyTime;
import org.ocpsoft.prettytime.TimeFormat;
import org.ocpsoft.prettytime.units.JustNow;
import javax.swing.*;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.Locale;
/**
* GUI: basic mage table for any data like game tables list, players list, etc
@ -37,7 +41,7 @@ public class MageTable extends JTable {
java.awt.Point p = e.getPoint();
int viewRow = rowAtPoint(p);
int viewCol = columnAtPoint(p);
int modelRow = TablesUtil.getModelRowFromView(this, viewRow);
int modelRow = getModelRowFromView(this, viewRow);
int modelCol = this.convertColumnIndexToModel(viewCol);
String tip = null;
if (modelRow != -1 && modelCol != -1) {
@ -48,7 +52,7 @@ public class MageTable extends JTable {
tip = model.getValueAt(modelRow, modelCol).toString();
}
}
return GUISizeHelper.textToHtmlWithSize(tip, GUISizeHelper.tableFont);
return textToHtmlWithSize(tip, this.getFont());
}
@Override
@ -78,8 +82,43 @@ public class MageTable extends JTable {
tip = col.getHeaderValue().toString();
}
return GUISizeHelper.textToHtmlWithSize(tip, GUISizeHelper.tableFont);
return textToHtmlWithSize(tip, MageTable.this.getFont());
}
};
}
public static int getSelectedModelRow(JTable table) {
return getModelRowFromView(table, table.getSelectedRow());
}
public static int getModelRowFromView(JTable table, int viewRow) {
if (viewRow != -1 && viewRow < table.getModel().getRowCount()) {
return table.convertRowIndexToModel(viewRow);
}
return -1;
}
public static int getViewRowFromModel(JTable table, int modelRow) {
if (modelRow != -1 && modelRow < table.getModel().getRowCount()) {
return table.convertRowIndexToView(modelRow);
}
return -1;
}
public static String textToHtmlWithSize(String text, Font font) {
if (text != null && !text.toLowerCase(Locale.ENGLISH).startsWith("<html>")) {
return "<html><p style=\"font-size: " + font.getSize() + ";\">" + text + "</p>";
}
return text;
}
public static void fixTimeFormatter(PrettyTime timeFormatter) {
// TODO: remove after PrettyTime lib upgrade to v5
// change default just now from 60 to 30 secs
// see workaround for 4.0 versions: https://github.com/ocpsoft/prettytime/issues/152
TimeFormat timeFormat = timeFormatter.removeUnit(JustNow.class);
JustNow newJustNow = new JustNow();
newJustNow.setMaxQuantity(1000L * 30L); // 30 seconds gap (show "just now" from 0 to 30 secs)
timeFormatter.registerUnit(newJustNow, timeFormat);
}
}

View file

@ -1,4 +1,4 @@
package mage.client.table;
package mage.components.table;
import java.util.ArrayList;
import java.util.List;

View file

@ -1,7 +1,9 @@
package mage.client.table;
package mage.components.table;
/**
* GUI: add support of tooltip/hint for table's cells on mouse move (used by MageTable)
* <p>
* Make sure form and java files uses new MageTable(), not new JTable() code
*
* @author JayDi85
*/

View file

@ -0,0 +1,41 @@
package mage.components.table;
import org.ocpsoft.prettytime.PrettyTime;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
import java.util.Date;
import java.util.Locale;
/**
* GUI: create time ago cell renderer for date values in the table's cell
* <p>
* Usage example:
* tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_CREATED).setCellRenderer(TimeAgoTableCellRenderer.getInstance());
*
* @author JayDi85
*/
public class TimeAgoTableCellRenderer extends DefaultTableCellRenderer {
static final PrettyTime timeFormatter;
static {
timeFormatter = new PrettyTime(Locale.ENGLISH);
MageTable.fixTimeFormatter(timeFormatter);
}
private static final TimeAgoTableCellRenderer instance = new TimeAgoTableCellRenderer();
public static TimeAgoTableCellRenderer getInstance() {
return instance;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Date d = (Date) value;
label.setText(timeFormatter.format(d));
return label;
}
}

View file

@ -88,6 +88,9 @@
<Connection code="tableUserModel" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MageTable()"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
@ -262,6 +265,9 @@
<Connection code="tableTableModel" type="code"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MageTable()"/>
</AuxValues>
</Component>
</SubComponents>
</Container>

View file

@ -1,5 +1,8 @@
package mage.server.console;
import mage.components.table.MageTable;
import mage.components.table.TableModelWithTooltip;
import mage.components.table.TimeAgoTableCellRenderer;
import mage.remote.Session;
import mage.view.TableView;
import mage.view.UserView;
@ -13,6 +16,7 @@
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN;
import static javax.swing.JTable.AUTO_RESIZE_OFF;
@ -36,6 +40,7 @@
this.tableUserModel = new TableUserModel();
this.tableTableModel = new TableTableModel();
initComponents();
spinnerMuteDurationMinutes.setValue(60);
this.tblUsers.createDefaultColumnsFromModel();
this.tblUsers.setRowSorter(new TableRowSorter(tableUserModel));
@ -43,7 +48,8 @@
this.tblTables.createDefaultColumnsFromModel();
this.tblTables.setRowSorter(new TableRowSorter(tableTableModel));
this.tblUsers.setAutoResizeMode(AUTO_RESIZE_NEXT_COLUMN);
this.tblTables.setAutoResizeMode(AUTO_RESIZE_NEXT_COLUMN);
this.tblTables.getColumnModel().getColumn(TableTableModel.COLUMN_CREATED).setCellRenderer(TimeAgoTableCellRenderer.getInstance());
}
public void update(List<UserView> users) {
@ -93,7 +99,7 @@
jPanel1 = new javax.swing.JPanel();
jPanel3 = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
tblUsers = new javax.swing.JTable();
tblUsers = new MageTable();
jPanel4 = new javax.swing.JPanel();
btnDisconnect = new javax.swing.JButton();
btnEndSession = new javax.swing.JButton();
@ -105,7 +111,7 @@
jPanel2 = new javax.swing.JPanel();
jPanel5 = new javax.swing.JPanel();
jScrollPane2 = new javax.swing.JScrollPane();
tblTables = new javax.swing.JTable();
tblTables = new MageTable();
jPanel6 = new javax.swing.JPanel();
btnRemoveTable = new javax.swing.JButton();
jUserName = new javax.swing.JTextField();
@ -373,7 +379,10 @@
private void btnRemoveTableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRemoveTableActionPerformed
int row = this.tblTables.convertRowIndexToModel(tblTables.getSelectedRow());
ConsoleFrame.getSession().removeTable((UUID) tableTableModel.getValueAt(row, 7));
if (row >= 0) {
TableView tableView = this.tableTableModel.getTableView(row);
ConsoleFrame.getSession().removeTable(tableView.getTableId());
}
}//GEN-LAST:event_btnRemoveTableActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
@ -484,9 +493,11 @@
}
class TableTableModel extends AbstractTableModel {
class TableTableModel extends AbstractTableModel implements TableModelWithTooltip {
private final String[] columnNames = new String[]{"Table Name", "Owner", "Game Type", "Deck Type", "Status"};
protected static final int COLUMN_CREATED = 4;
private final String[] columnNames = new String[]{"Table name", "Players", "Game type", "Deck type", "Created", "Status", "Games"};
private TableView[] tables = new TableView[0];
public void loadData(Collection<TableView> tables) {
@ -515,17 +526,20 @@
return tables[arg0].getGameType();
case 3:
return tables[arg0].getDeckType();
case 4:
return tables[arg0].getTableState().toString();
case COLUMN_CREATED:
return tables[arg0].getCreateTime();
case 5:
return tables[arg0].isTournament();
case 6:
if (!tables[arg0].getGames().isEmpty()) {
return tables[arg0].getGames().get(0);
return tables[arg0].getTableStateText();
case 6:{
if (tables[arg0].getGames().isEmpty()) {
return "NO GAMES";
} else if (tables[arg0].getGames().size() == 0) {
return tables[arg0].getGames().get(0).toString();
} else {
return String.format("%d games:", tables[arg0].getGames().size())
+ "<br>" + tables[arg0].getGames().stream().map(UUID::toString).collect(Collectors.joining("<br>"));
}
}
return null;
case 7:
return tables[arg0].getTableId();
}
return "";
}
@ -543,14 +557,31 @@
@Override
public Class getColumnClass(int columnIndex) {
if (columnIndex == COLUMN_CREATED) {
return Date.class;
} else {
return String.class;
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 5;
return false;
}
public TableView getTableView(int row) {
if (row >= 0 && row <= this.tables.length - 1) {
return this.tables[row];
} else {
throw new IllegalArgumentException("Unknown table row: " + row);
}
}
@Override
public String getTooltipAt(int rowIndex, int columnIndex) {
Object res = this.getValueAt(rowIndex, columnIndex);
return res == null ? null : res.toString();
}
}
class UpdateUsersTask extends SwingWorker<Void, List<UserView>> {