package mage.client.table;
import mage.cards.decks.DeckCardLists;
import mage.cards.decks.importer.DeckImporter;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.chat.ChatPanelBasic;
import mage.client.components.MageComponents;
import mage.client.dialog.*;
import mage.client.util.GUISizeHelper;
import mage.client.util.IgnoreList;
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;
import mage.remote.MageRemoteException;
import mage.util.DeckUtil;
import mage.util.RandomUtil;
import mage.view.MatchView;
import mage.view.RoomUsersView;
import mage.view.TableView;
import mage.view.UserRequestMessage;
import org.apache.log4j.Logger;
import org.mage.card.arcane.CardRendererUtils;
import org.ocpsoft.prettytime.Duration;
import org.ocpsoft.prettytime.PrettyTime;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyVetoException;
import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import static mage.client.dialog.PreferencesDialog.*;
/**
* GUI: lobby's main component
*
* @author BetaSteward_at_googlemail.com
*/
public class TablesPanel extends javax.swing.JPanel {
private static final Logger LOGGER = Logger.getLogger(TablesPanel.class);
private static final int[] DEFAULT_COLUMNS_WIDTH = {35, 150, 100, 50, 120, 180, 80, 120, 80, 60, 40, 40, 60};
// ping timeout (warning, must be less than UserManagerImpl.USER_CONNECTION_TIMEOUTS_CHECK_SECS)
public static final int PING_SERVER_SECS = 20;
// refresh timeouts for data downloads from server
public static final int REFRESH_ACTIVE_TABLES_SECS = 5;
public static final int REFRESH_FINISHED_TABLES_SECS = 30;
public static final int REFRESH_PLAYERS_SECS = 10;
public static final double REFRESH_TIMEOUTS_INCREASE_FACTOR = 0.8; // can increase timeouts by 80% (0.8)
private final TablesTableModel tableModel;
private static final TableInfo tableInfo = new TableInfo() // currently only the hint texts are used from this object
.addColumn(0, 35, Icon.class, "M/T",
"Basic table type
"
+ "A symbol for match or a tournament table")
.addColumn(1, 150, String.class, "Deck Type", null)
.addColumn(2, 100, String.class, "Name",
"Table name
"
+ "A name for the table the table creator has set")
.addColumn(3, 50, String.class, "Seats",
"Seats of the table"
+ "
Occupied Seats / Total number of seats ")
.addColumn(4, 120, String.class, "Owner / Players",
"Joined players
"
+ "Owner = First name is the creator of the table
"
+ "Players = Names of the other players joint to the table")
.addColumn(5, 180, String.class, "Game Type",null)
.addColumn(6, 80, String.class, "Info",
"Match / Tournament settings"
+ "
Wins = Number of games you need to wins to win a match"
+ "
Time = Time limit per player"
+ "
Constr.: = Construction time for limited tournament formats"
+ "
RB = Rollbacks allowed"
+ "
SP = Spectators allowed"
+ "
Rng: Range of visibility for multiplayer matches"
+ "
Custom options: Nonstandard options, hover for details"
)
.addColumn(7, 120, String.class, "Status",
"Table status
"
+ "Information about the progress of the match or tournament")
.addColumn(8, 80, String.class, "Password",
"Password set
"
+ "Yes = You need the password of this table
"
+ "to join the table")
.addColumn(9, 60, Date.class, "Created / Started",
"Creation and starting time
"
+ "When was the table created
"
+ "when started the match or tournament")
.addColumn(10, 40, SkillLevel.class, "Skill Level",
"Defined skill level
"
+ "Expectations of the table creator
"
+ "on the level of experience of the joining players")
.addColumn(11, 40, String.class, "Rated",
"Rating status
"
+ "Yes = The matches of this table are rated")
.addColumn(12, 60, String.class, "Quit %",
"Needed maximal quit ratio
"
+ "Your calculated quit ratio of your past games"
+ "
needs to be below or equal to the given value"
+ "
to be able to join to the table")
.addColumn(13, 40, String.class, "Min Rating",
"Rating restriction
"
+ "You need at least this rating"
+ "
to be able to join the table")
.addColumn(14, 80, String.class, "Action",
"Actions related to this table
"
+ "Depending on the state of the table
"
+ "the possible actions you can take
"
+ "are shown here as buttons");
private final MatchesTableModel matchesModel;
private UUID roomId;
private UpdateTablesTask updateTablesTask;
private UpdatePlayersTask updatePlayersTask;
private UpdateMatchesTask updateMatchesTask;
// no needs in multiple create/join tables dialogs, it's a client side action
private JoinTableDialog joinTableDialog;
private NewTableDialog newTableDialog;
private NewTournamentDialog newTournamentDialog;
private final GameChooser gameChooser;
private java.util.List messages;
private int currentMessage;
private final MageTableRowSorter activeTablesSorter;
private final MageTableRowSorter completedTablesSorter;
private final TablesButtonColumn actionButton1;
private final TablesButtonColumn actionButton2;
private final Map tablesLastSelection = new HashMap<>();
final JToggleButton[] filterButtons;
// time formatter
private final PrettyTime timeFormatter = new PrettyTime(Locale.ENGLISH);
// duration renderer
TableCellRenderer durationCellRenderer = 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);
Long ms = (Long) value;
if (ms != 0) {
Duration dur = timeFormatter.approximateDuration(new Date(ms));
label.setText((timeFormatter.formatDuration(dur)));
} else {
label.setText("");
}
return label;
}
};
// datetime render
TableCellRenderer datetimeCellRenderer = new DefaultTableCellRenderer() {
final DateFormat datetimeFormater = new SimpleDateFormat("HH:mm:ss");
@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;
if (d != null) {
label.setText(datetimeFormater.format(d));
} else {
label.setText("");
}
return label;
}
};
// skill renderer
TableCellRenderer skillCellRenderer = new DefaultTableCellRenderer() {
// base panel to render
private final JPanel renderPanel = new JPanel();
private final ImageIcon skillIcon = new ImageIcon(this.getClass().getResource("/info/yellow_star_16.png"));
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
// get table text cell settings
DefaultTableCellRenderer baseRenderer = (DefaultTableCellRenderer) table.getDefaultRenderer(String.class);
JLabel baseComp = (JLabel) baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
String skillCode = baseComp.getText();
// apply settings to render panel from parent
renderPanel.setOpaque(baseComp.isOpaque());
renderPanel.setForeground(CardRendererUtils.copyColor(baseComp.getForeground()));
renderPanel.setBackground(CardRendererUtils.copyColor(baseComp.getBackground()));
renderPanel.setBorder(baseComp.getBorder());
// create each skill symbol as child label
renderPanel.removeAll();
renderPanel.setLayout(new BoxLayout(renderPanel, BoxLayout.X_AXIS));
for (char skillSymbol : skillCode.toCharArray()) {
JLabel symbolLabel = new JLabel();
symbolLabel.setBorder(new EmptyBorder(0, 3, 0, 0));
symbolLabel.setIcon(skillIcon);
renderPanel.add(symbolLabel);
}
return renderPanel;
}
};
// seats render
TableCellRenderer seatsCellRenderer = new DefaultTableCellRenderer() {
final JLabel greenLabel = new JLabel();
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel defaultLabel = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
defaultLabel.setHorizontalAlignment(JLabel.CENTER);
// colors
String val = (String) value;
int[] seats = parseSeatsInfo(val);
if (seats[0] != seats[1]) {
// green draw
Color defaultBack = defaultLabel.getBackground();
greenLabel.setText(val);
greenLabel.setHorizontalAlignment(JLabel.CENTER);
greenLabel.setFont(defaultLabel.getFont());
greenLabel.setForeground(Color.black);
greenLabel.setOpaque(true);
greenLabel.setBackground(new Color(156, 240, 146));
greenLabel.setBorder(new LineBorder(defaultBack, 1));
return greenLabel;
} else {
// default draw
return defaultLabel;
}
}
};
private int[] parseSeatsInfo(String info) {
String[] valsList = info.split("/");
int[] res = {0, 0};
if (valsList.length == 2) {
res[0] = Integer.parseInt(valsList[0]);
res[1] = Integer.parseInt(valsList[1]);
}
return res;
}
public static int randomizeTimout(int minTimout) {
// randomize timeouts to fix calls waves -- slow server can creates queue and moves all clients to same call window
int increase = (int) (minTimout * REFRESH_TIMEOUTS_INCREASE_FACTOR);
return minTimout + RandomUtil.nextInt(increase);
}
/**
* Creates new form TablesPanel
*/
public TablesPanel() {
tableModel = new TablesTableModel();
matchesModel = new MatchesTableModel();
gameChooser = new GameChooser();
initComponents();
// tableModel.setSession(session);
// formatter
MageTable.fixTimeFormatter(this.timeFormatter);
// 1. TABLE CURRENT
tableTables.createDefaultColumnsFromModel();
((MageTable)tableTables).setTableInfo(tableInfo);
activeTablesSorter = new MageTableRowSorter(tableModel) {
@Override
public void toggleSortOrder(int column) {
// special sort for created and seat column
if (column == TablesTableModel.COLUMN_CREATED || column == TablesTableModel.COLUMN_SEATS) {
List extends SortKey> sortKeys = getSortKeys();
if (sortKeys.size() == 2) {
// clear sort on second click
setSortKeys(null);
} else {
// setup sort on first click
List list = new ArrayList<>();
list.add(new RowSorter.SortKey(TablesTableModel.COLUMN_SEATS, SortOrder.ASCENDING));
list.add(new RowSorter.SortKey(TablesTableModel.COLUMN_CREATED, SortOrder.DESCENDING));
setSortKeys(list);
}
} else {
super.toggleSortOrder(column);
}
}
};
tableTables.setRowSorter(activeTablesSorter);
// time ago
tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_CREATED).setCellRenderer(TimeAgoTableCellRenderer.getInstance());
// skill level
tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_SKILL).setCellRenderer(skillCellRenderer);
// seats
tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_SEATS).setCellRenderer(seatsCellRenderer);
/* date sorter (not need, default is good - see getColumnClass)
activeTablesSorter.setComparator(TablesTableModel.COLUMN_CREATED, new Comparator() {
@Override
public int compare(Date v1, Date v2) {
return v1.compareTo(v2);
}
});*/
// seats sorter (free tables must be first)
activeTablesSorter.setComparator(TablesTableModel.COLUMN_SEATS, new Comparator() {
@Override
public int compare(String v1, String v2) {
int[] seats1 = parseSeatsInfo(v1);
int[] seats2 = parseSeatsInfo(v2);
boolean free1 = seats1[0] != seats1[1];
boolean free2 = seats2[0] != seats2[1];
// free seats go first
if (free1 || free2) {
return Boolean.compare(free2, free1);
}
// all other seats go without sorts
return 0;
}
});
// default sort by created date (last games from above)
ArrayList list = new ArrayList<>();
list.add(new RowSorter.SortKey(TablesTableModel.COLUMN_SEATS, SortOrder.ASCENDING));
list.add(new RowSorter.SortKey(TablesTableModel.COLUMN_CREATED, SortOrder.DESCENDING));
activeTablesSorter.setSortKeys(list);
TableUtil.setColumnWidthAndOrder(tableTables, DEFAULT_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_ORDER);
// 2. TABLE COMPLETED
completedTablesSorter = new MageTableRowSorter(matchesModel);
tableCompleted.setRowSorter(completedTablesSorter);
// duration
tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_DURATION).setCellRenderer(durationCellRenderer);
// start-end
tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_START).setCellRenderer(datetimeCellRenderer);
tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_END).setCellRenderer(datetimeCellRenderer);
// default sort by ended date (last games from above)
ArrayList list2 = new ArrayList<>();
list2.add(new RowSorter.SortKey(MatchesTableModel.COLUMN_END, SortOrder.DESCENDING));
completedTablesSorter.setSortKeys(list2);
// 3. CHAT
chatPanelMain.getUserChatPanel().useExtendedView(ChatPanelBasic.VIEW_MODE.NONE);
chatPanelMain.getUserChatPanel().setBorder(null);
chatPanelMain.getUserChatPanel().setChatType(ChatPanelBasic.ChatType.TABLES);
// 4. BUTTONS (add new buttons to the end of the list -- if not then users lost their filter settings)
filterButtons = new JToggleButton[]{btnStateWaiting, btnStateActive, btnStateFinished,
btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited,
btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatPremodern, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther,
btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword, btnFormatOathbreaker, btnFormatPioneer};
JComponent[] components = new JComponent[]{chatPanelMain, jSplitPane1, jScrollPaneTablesActive, jScrollPaneTablesFinished, jPanelTop, jPanelTables};
for (JComponent component : components) {
component.setOpaque(false);
}
jScrollPaneTablesActive.getViewport().setBackground(new Color(255, 255, 255, 50));
jScrollPaneTablesFinished.getViewport().setBackground(new Color(255, 255, 255, 50));
restoreFilters();
setGUISize();
Action openTableAction;
openTableAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
String searchID = e.getActionCommand();
int modelRow = TablesUtil.findTableRowFromSearchId(tableModel, searchID);
if (modelRow == -1) {
return;
}
UUID tableId = (UUID) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN + 3);
UUID gameId = (UUID) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN + 2);
String action = (String) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN);
String gameType = (String) tableModel.getValueAt(modelRow, TablesTableModel.COLUMN_GAME_TYPE);
boolean isTournament = (Boolean) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN + 1);
String owner = (String) tableModel.getValueAt(modelRow, TablesTableModel.COLUMN_OWNER);
String pwdColumn = (String) tableModel.getValueAt(modelRow, TablesTableModel.COLUMN_PASSWORD);
switch (action) {
case "Join":
if (owner.equals(SessionHandler.getUserName()) || owner.startsWith(SessionHandler.getUserName() + ',')) {
try {
JDesktopPane desktopPane = (JDesktopPane) MageFrame.getUI().getComponent(MageComponents.DESKTOP_PANE);
JInternalFrame[] windows = desktopPane.getAllFramesInLayer(javax.swing.JLayeredPane.DEFAULT_LAYER);
for (JInternalFrame frame : windows) {
if (frame.getTitle().equals("Waiting for players")) {
frame.toFront();
frame.setVisible(true);
try {
frame.setSelected(true);
} catch (PropertyVetoException ve) {
LOGGER.error(ve);
}
}
}
} catch (InterruptedException ex) {
LOGGER.error(ex);
}
return;
}
if (isTournament) {
LOGGER.info("Joining tournament " + tableId);
if (!gameType.startsWith("Constructed")) {
if (TablesTableModel.PASSWORD_VALUE_YES.equals(pwdColumn)) {
// need enter password
joinTableDialog.showDialog(roomId, tableId, true, !gameType.startsWith("Constructed"));
} else {
// direct join (no pass, no deck)
SessionHandler.joinTournamentTable(roomId, tableId, SessionHandler.getUserName(), PlayerType.HUMAN, 1, null, "");
}
} else {
// need choose deck
joinTableDialog.showDialog(roomId, tableId, true, !gameType.startsWith("Constructed"));
}
} else {
// need choose deck
LOGGER.info("Joining table " + tableId);
joinTableDialog.showDialog(roomId, tableId, false, false);
}
break;
case "Remove":
UserRequestMessage message = new UserRequestMessage("Removing table", "Are you sure you want to remove table?");
message.setButton1("No", null);
message.setButton2("Yes", PlayerAction.CLIENT_REMOVE_TABLE);
MageFrame.getInstance().showUserRequestDialog(message);
break;
case "Show":
if (isTournament) {
LOGGER.info("Showing tournament table " + tableId);
SessionHandler.watchTable(roomId, tableId);
}
break;
case "Watch":
if (!isTournament) {
LOGGER.info("Watching table " + tableId);
SessionHandler.watchTable(roomId, tableId);
}
break;
case "Replay":
LOGGER.info("Replaying game " + gameId);
SessionHandler.replayGame(gameId);
break;
}
}
};
Action closedTableAction;
closedTableAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
String searchID = e.getActionCommand();
int modelRow = TablesUtil.findTableRowFromSearchId(matchesModel, searchID);
if (modelRow == -1) {
return;
}
String action = (String) matchesModel.getValueAt(modelRow, MatchesTableModel.COLUMN_ACTION);
switch (action) {
case "Replay":
java.util.List gameList = matchesModel.getListofGames(modelRow);
if (gameList != null && !gameList.isEmpty()) {
if (gameList.size() == 1) {
SessionHandler.replayGame(gameList.get(0));
} else {
gameChooser.show(gameList, MageFrame.getDesktop().getMousePosition());
}
}
// MageFrame.getDesktop().showTournament(tournamentId);
break;
case "Show":
if (matchesModel.isTournament(modelRow)) {
LOGGER.info("Showing tournament table " + matchesModel.getTableId(modelRow));
SessionHandler.watchTable(roomId, matchesModel.getTableId(modelRow));
}
break;
}
}
};
// !!!! adds action buttons to the table panel (don't delete this)
actionButton1 = new TablesButtonColumn(tableTables, openTableAction, tableTables.convertColumnIndexToView(TablesTableModel.ACTION_COLUMN));
actionButton2 = new TablesButtonColumn(tableCompleted, closedTableAction, tableCompleted.convertColumnIndexToView(MatchesTableModel.COLUMN_ACTION));
// selection
tablesLastSelection.put(tableTables, "");
tablesLastSelection.put(tableCompleted, "");
addTableSelectListener(tableTables);
addTableSelectListener(tableCompleted);
// double click
addTableDoubleClickListener(tableTables, openTableAction);
addTableDoubleClickListener(tableCompleted, closedTableAction);
}
private void addTableSelectListener(JTable table) {
// https://stackoverflow.com/a/26142800/1276632
// save last selection
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
int modelRow = MageTable.getSelectedModelRow(table);
if (modelRow != -1) {
// needs only selected
String rowId = TablesUtil.getSearchIdFromTable(table, modelRow);
tablesLastSelection.put(table, rowId);
}
}
});
// restore selection
table.getModel().addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
String lastRowID = tablesLastSelection.get(table);
int needModelRow = TablesUtil.findTableRowFromSearchId(table.getModel(), lastRowID);
int needViewRow = MageTable.getViewRowFromModel(table, needModelRow);
if (needViewRow != -1) {
table.clearSelection();
table.addRowSelectionInterval(needViewRow, needViewRow);
}
}
});
}
});
}
private void addTableDoubleClickListener(JTable table, Action action) {
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (!SwingUtilities.isLeftMouseButton(e)) {
return;
}
int modelRow = MageTable.getSelectedModelRow(table);
if (e.getClickCount() == 2 && modelRow != -1) {
action.actionPerformed(new ActionEvent(table, ActionEvent.ACTION_PERFORMED, TablesUtil.getSearchIdFromTable(table, modelRow)));
}
}
});
}
public void cleanUp() {
saveGuiSettings();
chatPanelMain.cleanUp();
stopTasks();
}
public void changeGUISize() {
chatPanelMain.changeGUISize();
actionButton1.changeGUISize();
actionButton2.changeGUISize();
setGUISize();
}
private void setGUISize() {
tableTables.getTableHeader().setFont(GUISizeHelper.tableFont);
tableTables.setFont(GUISizeHelper.tableFont);
tableTables.setRowHeight(GUISizeHelper.tableRowHeight);
tableCompleted.getTableHeader().setFont(GUISizeHelper.tableFont);
tableCompleted.setFont(GUISizeHelper.tableFont);
tableCompleted.setRowHeight(GUISizeHelper.tableRowHeight);
jSplitPane1.setDividerSize(GUISizeHelper.dividerBarSize);
jSplitPaneTables.setDividerSize(GUISizeHelper.dividerBarSize);
jScrollPaneTablesActive.getVerticalScrollBar().setPreferredSize(new Dimension(GUISizeHelper.scrollBarSize, 0));
jScrollPaneTablesActive.getHorizontalScrollBar().setPreferredSize(new Dimension(0, GUISizeHelper.scrollBarSize));
ImageIcon icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/state_waiting.png"));
Image img = icon.getImage();
Image newimg = img.getScaledInstance(GUISizeHelper.dialogFont.getSize(), GUISizeHelper.dialogFont.getSize(), java.awt.Image.SCALE_SMOOTH);
btnStateWaiting.setIcon(new ImageIcon(newimg));
icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/state_active.png"));
img = icon.getImage();
newimg = img.getScaledInstance(GUISizeHelper.dialogFont.getSize(), GUISizeHelper.dialogFont.getSize(), java.awt.Image.SCALE_SMOOTH);
btnStateActive.setIcon(new ImageIcon(newimg));
icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/state_finished.png"));
img = icon.getImage();
newimg = img.getScaledInstance(GUISizeHelper.dialogFont.getSize(), GUISizeHelper.dialogFont.getSize(), java.awt.Image.SCALE_SMOOTH);
btnStateFinished.setIcon(new ImageIcon(newimg));
int iconSize = 48 + GUISizeHelper.dialogFont.getSize() * 2 - 15;
icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/match_new.png"));
img = icon.getImage();
newimg = img.getScaledInstance(iconSize, iconSize, java.awt.Image.SCALE_SMOOTH);
btnNewTable.setIcon(new ImageIcon(newimg));
icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/tourney_new.png"));
img = icon.getImage();
newimg = img.getScaledInstance(iconSize, iconSize, java.awt.Image.SCALE_SMOOTH);
btnNewTournament.setIcon(new ImageIcon(newimg));
for (JToggleButton component : filterButtons) {
component.setFont(GUISizeHelper.dialogFont);
}
Dimension newDimension = new Dimension((int) jPanelBottom.getPreferredSize().getWidth(), GUISizeHelper.dialogFont.getSize() + 28);
jPanelBottom.setMinimumSize(newDimension);
jPanelBottom.setPreferredSize(newDimension);
buttonWhatsNew.setFont(GUISizeHelper.dialogFont);
buttonNextMessage.setFont(GUISizeHelper.dialogFont);
labelMessageHeader.setFont(new Font(GUISizeHelper.dialogFont.getName(), Font.BOLD, GUISizeHelper.dialogFont.getSize()));
labelMessageText.setFont(GUISizeHelper.dialogFont);
btnQuickStart2Player.setFont(GUISizeHelper.dialogFont);
btnQuickStart4Player.setFont(GUISizeHelper.dialogFont);
btnQuickStartMCTS.setFont(GUISizeHelper.dialogFont);
}
private void restoreDividerLocations() {
Rectangle currentBounds = MageFrame.getDesktop().getBounds();
if (currentBounds != null) {
String firstDivider = PreferencesDialog.getCachedValue(KEY_TABLES_DIVIDER_LOCATION_1, null);
String tableDivider = PreferencesDialog.getCachedValue(KEY_TABLES_DIVIDER_LOCATION_2, null);
String chatDivider = PreferencesDialog.getCachedValue(KEY_TABLES_DIVIDER_LOCATION_3, null);
GuiDisplayUtil.restoreDividerLocations(currentBounds, firstDivider, jSplitPane1);
GuiDisplayUtil.restoreDividerLocations(currentBounds, tableDivider, jSplitPaneTables);
GuiDisplayUtil.restoreDividerLocations(currentBounds, chatDivider, chatPanelMain);
}
}
private void saveDividerLocations() {
// save divider locations
if (this.jSplitPane1.getDividerLocation() == -1) {
// server lobby hidden by default, so ignore that settings
return;
}
GuiDisplayUtil.saveCurrentBoundsToPrefs();
GuiDisplayUtil.saveDividerLocationToPrefs(KEY_TABLES_DIVIDER_LOCATION_1, this.jSplitPane1.getDividerLocation());
GuiDisplayUtil.saveDividerLocationToPrefs(KEY_TABLES_DIVIDER_LOCATION_2, this.jSplitPaneTables.getDividerLocation());
GuiDisplayUtil.saveDividerLocationToPrefs(KEY_TABLES_DIVIDER_LOCATION_3, chatPanelMain.getSplitDividerLocation());
}
private void restoreFilters() {
TableUtil.setActiveFilters(KEY_TABLES_FILTER_SETTINGS, filterButtons);
setTableFilter();
}
private void saveGuiSettings() {
TableUtil.saveActiveFiltersToPrefs(KEY_TABLES_FILTER_SETTINGS, filterButtons);
TableUtil.saveColumnWidthAndOrderToPrefs(tableTables, KEY_TABLES_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_ORDER);
}
public Map getUIComponents() {
Map components = new HashMap<>();
components.put("jScrollPane1", jScrollPaneTablesActive);
components.put("jScrollPane1ViewPort", jScrollPaneTablesActive.getViewport());
components.put("jPanel1", jPanelTop);
components.put("tablesPanel", this);
return components;
}
public void updateTables(Collection tables) {
try {
tableModel.loadData(tables);
this.tableTables.repaint();
} catch (MageRemoteException ex) {
hideTables();
}
}
public void updateMatches(Collection matches) {
try {
matchesModel.loadData(matches);
this.tableCompleted.repaint();
} catch (MageRemoteException ex) {
hideTables();
}
}
public void startUpdateTasks(boolean refreshImmediately) {
if (SessionHandler.getSession() != null) {
// active tables and server messages
if (updateTablesTask == null || updateTablesTask.isDone() || refreshImmediately) {
if (updateTablesTask != null) updateTablesTask.cancel(true);
updateTablesTask = new UpdateTablesTask(roomId, this);
updateTablesTask.execute();
}
// finished tables
if (this.btnStateFinished.isSelected()) {
if (updateMatchesTask == null || updateMatchesTask.isDone() || refreshImmediately) {
if (updateMatchesTask != null) updateMatchesTask.cancel(true);
updateMatchesTask = new UpdateMatchesTask(roomId, this);
updateMatchesTask.execute();
}
} else {
if (updateMatchesTask != null) updateMatchesTask.cancel(true);
}
// players list
if (updatePlayersTask == null || updatePlayersTask.isDone() || refreshImmediately) {
if (updatePlayersTask != null) updatePlayersTask.cancel(true);
updatePlayersTask = new UpdatePlayersTask(roomId, this.chatPanelMain);
updatePlayersTask.execute();
}
}
}
public void stopTasks() {
if (updateTablesTask != null) {
updateTablesTask.cancel(true);
}
if (updatePlayersTask != null) {
updatePlayersTask.cancel(true);
}
if (updateMatchesTask != null) {
updateMatchesTask.cancel(true);
}
}
public void showTables(UUID roomId) {
this.roomId = roomId;
UUID chatRoomId = null;
if (SessionHandler.getSession() != null) {
btnQuickStart2Player.setVisible(SessionHandler.isTestMode());
btnQuickStart4Player.setVisible(SessionHandler.isTestMode());
btnQuickStartMCTS.setVisible(SessionHandler.isTestMode());
gameChooser.init();
chatRoomId = SessionHandler.getRoomChatId(roomId).orElse(null);
}
if (newTableDialog == null) {
newTableDialog = new NewTableDialog();
MageFrame.getDesktop().add(newTableDialog, newTableDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
}
if (newTournamentDialog == null) {
newTournamentDialog = new NewTournamentDialog();
MageFrame.getDesktop().add(newTournamentDialog, newTournamentDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
}
if (joinTableDialog == null) {
joinTableDialog = new JoinTableDialog();
MageFrame.getDesktop().add(joinTableDialog, joinTableDialog.isModal() ? JLayeredPane.MODAL_LAYER : JLayeredPane.PALETTE_LAYER);
}
if (chatRoomId != null) {
this.chatPanelMain.getUserChatPanel().connect(chatRoomId);
startUpdateTasks(true);
this.setVisible(true);
this.repaint();
} else {
hideTables();
}
//tableModel.setSession(session);
reloadServerMessages();
MageFrame.getUI().addButton(MageComponents.NEW_GAME_BUTTON, btnNewTable);
restoreDividerLocations();
}
protected void reloadServerMessages() {
// reload server messages
java.util.List serverMessages = SessionHandler.getServerMessages();
synchronized (this) {
if (serverMessages != null) {
this.messages = serverMessages;
} else {
this.messages = new ArrayList<>();
}
this.currentMessage = 0;
}
if (this.messages.isEmpty()) {
this.jPanelBottom.setVisible(false);
} else {
this.jPanelBottom.setVisible(true);
URLHandler.RemoveMouseAdapter(labelMessageText);
URLHandler.handleMessage(this.messages.get(0), this.labelMessageText);
this.buttonNextMessage.setVisible(this.messages.size() > 1);
}
}
public void hideTables() {
this.saveDividerLocations();
for (Component component : MageFrame.getDesktop().getComponents()) {
if (component instanceof TableWaitingDialog) {
((TableWaitingDialog) component).doClose();
}
}
stopTasks();
this.chatPanelMain.cleanUp();;
Component c = this.getParent();
while (c != null && !(c instanceof TablesPane)) {
c = c.getParent();
}
if (c != null) {
((TablesPane) c).hideFrame();
}
}
public ChatPanelBasic getChatPanel() {
return chatPanelMain.getUserChatPanel();
}
public void setTableFilter() {
// state
java.util.List> stateFilterList = new ArrayList<>();
if (btnStateWaiting.isSelected()) {
stateFilterList.add(RowFilter.regexFilter("Waiting", TablesTableModel.COLUMN_STATUS));
}
if (btnStateActive.isSelected()) {
stateFilterList.add(RowFilter.regexFilter("Dueling|Constructing|Drafting|Sideboard", TablesTableModel.COLUMN_STATUS));
}
// type
java.util.List> typeFilterList = new ArrayList<>();
if (btnTypeMatch.isSelected()) {
typeFilterList.add(RowFilter.regexFilter("Two|Commander|Free|Tiny|Momir", TablesTableModel.COLUMN_GAME_TYPE));
}
if (btnTypeTourneyConstructed.isSelected()) {
typeFilterList.add(RowFilter.regexFilter("Constructed", TablesTableModel.COLUMN_GAME_TYPE));
}
if (btnTypeTourneyLimited.isSelected()) {
typeFilterList.add(RowFilter.regexFilter("Booster|Sealed|Jumpstart", TablesTableModel.COLUMN_GAME_TYPE));
}
// format
java.util.List> formatFilterList = new ArrayList<>();
if (btnFormatBlock.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed.*Block", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatStandard.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Standard", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatModern.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Modern", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatPioneer.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Pioneer", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatLegacy.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Legacy", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatVintage.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Vintage", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatPremodern.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Premodern", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatCommander.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Centurion Commander|^Penny Dreadful Commander|^Freeform Commander|^Freeform Unlimited Commander|^MTGO 1v1 Commander|^Duel Brawl|^Brawl", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatTinyLeader.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Tiny", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatOathbreaker.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Oathbreaker", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatLimited.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Limited", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatOther.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Constructed - Freeform Unlimited|^Australian Highlander|^European Highlander|^Canadian Highlander|^Constructed - Old|^Constructed - Historic", TablesTableModel.COLUMN_DECK_TYPE));
}
// skill
java.util.List> skillFilterList = new ArrayList<>();
if (btnSkillBeginner.isSelected()) {
skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.BEGINNER, true), TablesTableModel.COLUMN_SKILL));
}
if (btnSkillCasual.isSelected()) {
skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.CASUAL, true), TablesTableModel.COLUMN_SKILL));
}
if (btnSkillSerious.isSelected()) {
skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.SERIOUS, true), TablesTableModel.COLUMN_SKILL));
}
String ratedMark = TablesTableModel.RATED_VALUE_YES;
java.util.List> ratingFilterList = new ArrayList<>();
if (btnRated.isSelected()) {
// yes word
ratingFilterList.add(RowFilter.regexFilter("^" + ratedMark, TablesTableModel.COLUMN_RATING));
}
if (btnUnrated.isSelected()) {
// not yes word, see https://stackoverflow.com/a/406408/1276632
ratingFilterList.add(RowFilter.regexFilter("^((?!" + ratedMark + ").)*$", TablesTableModel.COLUMN_RATING));
}
// Password
String passwordMark = TablesTableModel.PASSWORD_VALUE_YES;
java.util.List> passwordFilterList = new ArrayList<>();
if (btnPassword.isSelected()) {
// yes
passwordFilterList.add(RowFilter.regexFilter("^" + passwordMark, TablesTableModel.COLUMN_PASSWORD));
}
if (btnOpen.isSelected()) {
// no
passwordFilterList.add(RowFilter.regexFilter("^((?!" + passwordMark + ").)*$", TablesTableModel.COLUMN_PASSWORD));
}
// Hide games of ignored players
java.util.List> ignoreListFilterList = new ArrayList<>();
String serverAddress = SessionHandler.getSession().getServerHost();
final Set ignoreListCopy = IgnoreList.getIgnoredUsers(serverAddress);
if (!ignoreListCopy.isEmpty()) {
ignoreListFilterList.add(new RowFilter