From fef37cdc7376ad0c3f428a59348d44c4c686adb7 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Fri, 22 Mar 2024 16:48:34 +0400 Subject: [PATCH] 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; --- Mage.Client/pom.xml | 7 -- .../mage/client/table/PlayersChatPanel.java | 2 + .../java/mage/client/table/TablesPanel.java | 39 ++++------- .../mage/client/table/TablesTableModel.java | 1 + .../java/mage/client/table/TablesUtil.java | 20 +----- .../java/mage/client/util/GUISizeHelper.java | 7 -- Mage.Common/pom.xml | 7 ++ .../mage/components}/table/ColumnInfo.java | 2 +- .../mage/components}/table/MageTable.java | 51 +++++++++++++-- .../mage/components}/table/TableInfo.java | 2 +- .../table/TableModelWithTooltip.java | 4 +- .../table/TimeAgoTableCellRenderer.java | 41 ++++++++++++ .../mage/server/console/ConsolePanel.form | 6 ++ .../mage/server/console/ConsolePanel.java | 65 ++++++++++++++----- 14 files changed, 170 insertions(+), 84 deletions(-) rename {Mage.Client/src/main/java/mage/client => Mage.Common/src/main/java/mage/components}/table/ColumnInfo.java (96%) rename {Mage.Client/src/main/java/mage/client => Mage.Common/src/main/java/mage/components}/table/MageTable.java (57%) rename {Mage.Client/src/main/java/mage/client => Mage.Common/src/main/java/mage/components}/table/TableInfo.java (97%) rename {Mage.Client/src/main/java/mage/client => Mage.Common/src/main/java/mage/components}/table/TableModelWithTooltip.java (65%) create mode 100644 Mage.Common/src/main/java/mage/components/table/TimeAgoTableCellRenderer.java diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index 1fe29e95f4e..d702cf1ac96 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -151,13 +151,6 @@ 1.17 - - - - org.ocpsoft.prettytime - prettytime - 4.0.6.Final - diff --git a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java index c93d929366d..1d0bb9e69cc 100644 --- a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java @@ -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; diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index b61b6569cb2..74e7ea765ae 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -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))); } diff --git a/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java b/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java index 6fa3fb65690..3d78e2fa2e4 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java @@ -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; diff --git a/Mage.Client/src/main/java/mage/client/table/TablesUtil.java b/Mage.Client/src/main/java/mage/client/table/TablesUtil.java index 6fd2b8445ee..c8923a623f7 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesUtil.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesUtil.java @@ -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; - } } diff --git a/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java b/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java index c01006ee9d1..48472f77fb5 100644 --- a/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java +++ b/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java @@ -186,13 +186,6 @@ public final class GUISizeHelper { } } - public static String textToHtmlWithSize(String text, Font font) { - if (text != null && !text.toLowerCase(Locale.ENGLISH).startsWith("")) { - return "

" + text + "

"; - } - return text; - } - /** * Return scrollbar settings, so user can scroll it more faster for bigger cards * diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml index dfa8dea5840..d7f33c9c06a 100644 --- a/Mage.Common/pom.xml +++ b/Mage.Common/pom.xml @@ -43,6 +43,13 @@ 4.2.2.GA + + + org.ocpsoft.prettytime + prettytime + 4.0.6.Final + + concurrent diff --git a/Mage.Client/src/main/java/mage/client/table/ColumnInfo.java b/Mage.Common/src/main/java/mage/components/table/ColumnInfo.java similarity index 96% rename from Mage.Client/src/main/java/mage/client/table/ColumnInfo.java rename to Mage.Common/src/main/java/mage/components/table/ColumnInfo.java index fcd9aed3155..6ca06c2b186 100644 --- a/Mage.Client/src/main/java/mage/client/table/ColumnInfo.java +++ b/Mage.Common/src/main/java/mage/components/table/ColumnInfo.java @@ -1,4 +1,4 @@ -package mage.client.table; +package mage.components.table; /** * @author JayDi85 diff --git a/Mage.Client/src/main/java/mage/client/table/MageTable.java b/Mage.Common/src/main/java/mage/components/table/MageTable.java similarity index 57% rename from Mage.Client/src/main/java/mage/client/table/MageTable.java rename to Mage.Common/src/main/java/mage/components/table/MageTable.java index f2ed79e19f1..c137ed35105 100644 --- a/Mage.Client/src/main/java/mage/client/table/MageTable.java +++ b/Mage.Common/src/main/java/mage/components/table/MageTable.java @@ -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 @@ -26,7 +30,7 @@ public class MageTable extends JTable { public MageTable(TableInfo tableInfo) { this.tableInfo = tableInfo; } - + public void setTableInfo(TableInfo tableInfo) { this.tableInfo = tableInfo; } @@ -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("")) { + return "

" + text + "

"; + } + 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); + } } diff --git a/Mage.Client/src/main/java/mage/client/table/TableInfo.java b/Mage.Common/src/main/java/mage/components/table/TableInfo.java similarity index 97% rename from Mage.Client/src/main/java/mage/client/table/TableInfo.java rename to Mage.Common/src/main/java/mage/components/table/TableInfo.java index d1ad44cd78e..65ed23215aa 100644 --- a/Mage.Client/src/main/java/mage/client/table/TableInfo.java +++ b/Mage.Common/src/main/java/mage/components/table/TableInfo.java @@ -1,4 +1,4 @@ -package mage.client.table; +package mage.components.table; import java.util.ArrayList; import java.util.List; diff --git a/Mage.Client/src/main/java/mage/client/table/TableModelWithTooltip.java b/Mage.Common/src/main/java/mage/components/table/TableModelWithTooltip.java similarity index 65% rename from Mage.Client/src/main/java/mage/client/table/TableModelWithTooltip.java rename to Mage.Common/src/main/java/mage/components/table/TableModelWithTooltip.java index 6d1de4b060b..4f111a117b3 100644 --- a/Mage.Client/src/main/java/mage/client/table/TableModelWithTooltip.java +++ b/Mage.Common/src/main/java/mage/components/table/TableModelWithTooltip.java @@ -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) + *

+ * Make sure form and java files uses new MageTable(), not new JTable() code * * @author JayDi85 */ diff --git a/Mage.Common/src/main/java/mage/components/table/TimeAgoTableCellRenderer.java b/Mage.Common/src/main/java/mage/components/table/TimeAgoTableCellRenderer.java new file mode 100644 index 00000000000..2d712b589ed --- /dev/null +++ b/Mage.Common/src/main/java/mage/components/table/TimeAgoTableCellRenderer.java @@ -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 + *

+ * 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; + } +} diff --git a/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.form b/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.form index 6830ef137b6..b430478292b 100644 --- a/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.form +++ b/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.form @@ -88,6 +88,9 @@ + + + @@ -262,6 +265,9 @@ + + + diff --git a/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.java b/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.java index 63c9e2e72e6..4e92d78f3b2 100644 --- a/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.java +++ b/Mage.Server.Console/src/main/java/mage/server/console/ConsolePanel.java @@ -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 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 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()) + + "
" + tables[arg0].getGames().stream().map(UUID::toString).collect(Collectors.joining("
")); } - return null; - case 7: - return tables[arg0].getTableId(); + } } return ""; } @@ -543,14 +557,31 @@ @Override public Class getColumnClass(int columnIndex) { - return String.class; + 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> {