package games.strategy.engine.lobby.client.ui; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; import games.strategy.engine.lobby.server.GameDescription; import games.strategy.engine.lobby.server.ILobbyGameBroadcaster; import games.strategy.engine.lobby.server.ILobbyGameController; import games.strategy.engine.message.IChannelMessenger; import games.strategy.engine.message.IRemoteMessenger; import games.strategy.engine.message.MessageContext; import games.strategy.net.GUID; import games.strategy.net.IMessenger; import games.strategy.util.Tuple; public class LobbyGameTableModel extends AbstractTableModel { private static final long serialVersionUID = 6399458368730633993L; enum Column { Host, Name, GV, Round, Players, P, B, EV, Started, Status, Comments, GUID } private final IMessenger m_messenger; // these must only be accessed in the swing event thread private final List<Tuple<GUID, GameDescription>> gameList; private final ILobbyGameBroadcaster lobbyGameBroadcaster; public LobbyGameTableModel(final IMessenger messenger, final IChannelMessenger channelMessenger, final IRemoteMessenger remoteMessenger) { gameList = new ArrayList<>(); m_messenger = messenger; final IChannelMessenger m_channelMessenger = channelMessenger; final IRemoteMessenger m_remoteMessenger = remoteMessenger; lobbyGameBroadcaster = new ILobbyGameBroadcaster() { @Override public void gameUpdated(final GUID gameId, final GameDescription description) { assertSentFromServer(); updateGame(gameId, description); } @Override public void gameRemoved(final GUID gameId) { assertSentFromServer(); removeGame(gameId); } }; m_channelMessenger.registerChannelSubscriber(lobbyGameBroadcaster, ILobbyGameBroadcaster.GAME_BROADCASTER_CHANNEL); final Map<GUID, GameDescription> games = ((ILobbyGameController) m_remoteMessenger.getRemote(ILobbyGameController.GAME_CONTROLLER_REMOTE)).listGames(); for (final GUID id : games.keySet()) { updateGame(id, games.get(id)); } } private void removeGame(final GUID gameId) { SwingUtilities.invokeLater(() -> { if (gameId == null) { return; } final Tuple<GUID, GameDescription> gameToRemove = findGame(gameId); if (gameToRemove != null) { final int index = gameList.indexOf(gameToRemove); gameList.remove(gameToRemove); fireTableRowsDeleted(index, index); } }); } private Tuple<GUID, GameDescription> findGame(final GUID gameId) { for (final Tuple<GUID, GameDescription> game : gameList) { if (game.getFirst().equals(gameId)) { return game; } } return null; } protected ILobbyGameBroadcaster getLobbyGameBroadcaster() { return lobbyGameBroadcaster; } public GameDescription get(final int i) { return gameList.get(i).getSecond(); } @Override public Class<?> getColumnClass(final int columnIndex) { if (columnIndex == getColumnIndex(Column.Started)) { return Date.class; } return Object.class; } private void assertSentFromServer() { if (!MessageContext.getSender().equals(m_messenger.getServerNode())) { throw new IllegalStateException("Invalid sender"); } } private void updateGame(final GUID gameId, final GameDescription description) { SwingUtilities.invokeLater(() -> { if (gameId == null) { return; } final Tuple<GUID, GameDescription> toReplace = findGame(gameId); if (toReplace == null) { gameList.add(Tuple.of(gameId, description)); } else { final int replaceIndex = gameList.indexOf(toReplace); gameList.set(replaceIndex, Tuple.of(gameId, description)); fireTableRowsUpdated(replaceIndex, replaceIndex); } }); } @Override public String getColumnName(final int column) { return Column.values()[column].toString(); } public int getColumnIndex(final Column column) { return column.ordinal(); } @Override public int getColumnCount() { // -1 so we don't display the guid return Column.values().length - 1; } @Override public int getRowCount() { return gameList.size(); } @Override public Object getValueAt(final int rowIndex, final int columnIndex) { final Column column = Column.values()[columnIndex]; final GameDescription description = gameList.get(rowIndex).getSecond(); switch (column) { case Host: return description.getHostName(); case Round: return description.getRound(); case Name: return description.getGameName(); case Players: return description.getPlayerCount(); case P: return (description.getPassworded() ? "*" : ""); case B: return (description.getBotSupportEmail() != null && description.getBotSupportEmail().length() > 0 ? "-" : ""); case GV: return description.getGameVersion(); case EV: return description.getEngineVersion(); case Status: return description.getStatus(); case Comments: return description.getComment(); case Started: return description.getStartDateTime(); case GUID: return gameList.get(rowIndex).getFirst(); default: throw new IllegalStateException("Unknown column:" + column); } } }