package jrummikub.view.impl; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLayeredPane; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.border.CompoundBorder; import javax.swing.border.MatteBorder; import javax.swing.filechooser.FileNameExtensionFilter; import jrummikub.model.Position; import jrummikub.model.Stone; import jrummikub.model.StoneColor; import jrummikub.model.StoneSet; import jrummikub.util.Event; import jrummikub.util.Event1; import jrummikub.util.IEvent; import jrummikub.util.IEvent1; import jrummikub.util.IListener; import jrummikub.util.Pair; import jrummikub.view.IConnectPanel; import jrummikub.view.IGameListPanel; import jrummikub.view.IHandPanel; import jrummikub.view.ILoginPanel; import jrummikub.view.IPlayerPanel; import jrummikub.view.IQuitWarningPanel; import jrummikub.view.IScorePanel; import jrummikub.view.ISettingsPanel; import jrummikub.view.ISidePanel; import jrummikub.view.ITablePanel; import jrummikub.view.IView; /** * Implementation of the top-level view interface */ @SuppressWarnings("serial") public class View extends JFrame implements IView { private final static float PLAYER_PANEL_RATIO = 0.14f; private final static int PLAYER_PANEL_MAX_HEIGHT = 180; private final static int TABLE_BORDER_WIDTH = 1; private JLayeredPane layeredPane; private JPanel mainLayer; private JMenuBar menuBar; private JMenuItem saveItem; private TablePanel table; private PlayerPanel playerPanel; private StartTurnPanel startTurnPanel; private PausePanel pausePanel; private RoundEndPanel roundEndPanel; private SettingsPanel settingsPanel; private LoginPanel loginPanel; private ScorePanel scorePanel; private GameListPanel gameListPanel; private SidePanel sidePanel; private QuitWarningPanel quitWarningPanel; private ConnectPanel connectPanel; private BottomPanelType bottomPanelType; private JFileChooser chooser; private Event menuNewGameEvent = new Event(); private Event networkGameEvent = new Event(); private Event loadEvent = new Event(); private Event1 loadFileEvent = new Event1(); private Event1 saveEvent = new Event1(); private Event quitEvent = new Event(); private JFrame quitWarningFrame; private static int even(double d) { return 2 * (int) (d / 2); } @Override public ISettingsPanel getSettingsPanel() { return settingsPanel; } @Override public ILoginPanel getLoginPanel() { return loginPanel; } @Override public IScorePanel getScorePanel() { return scorePanel; } @Override public ITablePanel getTablePanel() { return table; } @Override public ISidePanel getSidePanel() { return sidePanel; } @Override public IHandPanel getHandPanel() { return playerPanel.getHandPanel(); } @Override public IPlayerPanel getPlayerPanel() { return playerPanel; } @Override public IQuitWarningPanel getQuitWarningPanel() { return quitWarningPanel; } @Override public IConnectPanel getConnectPanel() { return connectPanel; } @Override public IGameListPanel getGameListPanel() { return gameListPanel; } @Override public IEvent getMenuNewGameEvent() { return menuNewGameEvent; } @Override public IEvent1 getLoadFileEvent() { return loadFileEvent; } @Override public IEvent getLoadEvent() { return loadEvent; } @Override public IEvent1 getSaveEvent() { return saveEvent; } @Override public IEvent getPauseEvent() { return playerPanel.getPauseEvent(); } @Override public IEvent getEndPauseEvent() { return pausePanel.getEndPauseEvent(); } @Override public IEvent getNetworkGameEvent() { return networkGameEvent; } @Override public IEvent getQuitEvent() { return quitEvent; } @Override public void clearView() { showScorePanel(false); showSettingsPanel(false); showLoginPanel(false); showGameListPanel(false); getHandPanel().setStones(Collections.> emptyList()); getTablePanel().setStoneSets( Collections.> emptyList()); setSelectedStones(Collections. emptyList()); } @Override public void showLoadingError() { JOptionPane.showMessageDialog(this, "Kein g\u00fcltiger Spielstand", "Fehler", JOptionPane.ERROR_MESSAGE); } @Override public void showServerStartupError(boolean alreadyRunning) { JOptionPane .showMessageDialog( this, alreadyRunning ? "Ein XMPP-Server l\u00e4ft bereits auf diesem Computer" : "Der Server konnte nicht gestartet werden", "Fehler", JOptionPane.ERROR_MESSAGE); } private void createFileChooser() { chooser = new JFileChooser(); FileNameExtensionFilter filter = new FileNameExtensionFilter( "JRummikub-Spiele", "rum"); chooser.setFileFilter(filter); String defaultFile = "spiel.rum"; chooser.setSelectedFile(new File(defaultFile)); } private void createMenuBar() { menuBar = new JMenuBar(); JMenu gameMenu = new JMenu("Spiel"); menuBar.add(gameMenu); gameMenu.add(createMenuItem("Neu", menuNewGameEvent)); gameMenu.add(createMenuItem("Netzwerkspiel...", networkGameEvent)); gameMenu.addSeparator(); JMenuItem loadItem = new JMenuItem("Laden..."); loadItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { loadEvent.emit(); } }); gameMenu.add(loadItem); saveItem = new JMenuItem("Speichern..."); saveItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { save(); } }); gameMenu.add(saveItem); gameMenu.addSeparator(); gameMenu.add(createMenuItem("Beenden", quitEvent)); setJMenuBar(menuBar); } private JMenuItem createMenuItem(String text, final Event event) { JMenuItem item = new JMenuItem(text); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { event.emit(); } }); return item; } @Override public void enableSave(boolean enable) { saveItem.setEnabled(enable); } @Override public void load() { int returnVal = chooser.showOpenDialog(View.this); if (returnVal == JFileChooser.APPROVE_OPTION) { loadFileEvent.emit(chooser.getSelectedFile()); } } private void save() { int returnVal = chooser.showSaveDialog(View.this); if (returnVal == JFileChooser.APPROVE_OPTION) { saveEvent.emit(chooser.getSelectedFile()); } } /** * Create a new instance of the view */ public View() { super("JRummikub"); setLayout(null); setSize(1000, 700); setMinimumSize(new Dimension(750, 550)); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { if (isEnabled()) { quitEvent.emit(); } } }); createFileChooser(); createMenuBar(); layeredPane = new JLayeredPane(); layeredPane.setLayout(null); add(layeredPane); createMainLayer(); createSettingsPanel(); createLayeredPane(); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { rescale(); } @Override public void componentMoved(ComponentEvent e) { quitWarningFrame.setLocationRelativeTo(View.this); } }); setVisible(true); } private void createLayeredPane() { layeredPane.setLayer(settingsPanel, JLayeredPane.POPUP_LAYER); layeredPane.add(settingsPanel); loginPanel = new LoginPanel(); loginPanel.setVisible(false); layeredPane.setLayer(loginPanel, JLayeredPane.POPUP_LAYER); layeredPane.add(loginPanel); gameListPanel = new GameListPanel(); gameListPanel.setVisible(false); layeredPane.setLayer(gameListPanel, JLayeredPane.POPUP_LAYER); layeredPane.add(gameListPanel); connectPanel = new ConnectPanel(); connectPanel.setVisible(false); layeredPane.setLayer(connectPanel, JLayeredPane.POPUP_LAYER); layeredPane.add(connectPanel); quitWarningPanel = new QuitWarningPanel(); quitWarningFrame = new JFrame(); quitWarningFrame.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); quitWarningFrame.add(quitWarningPanel); quitWarningFrame.setAlwaysOnTop(true); quitWarningFrame.setUndecorated(true); // layeredPane.setLayer(quitWarningPanel, JLayeredPane.POPUP_LAYER); // layeredPane.add(quitWarningPanel); // quitWarningPanel.setVisible(true); scorePanel = new ScorePanel(); scorePanel.setVisible(false); layeredPane.setLayer(scorePanel, JLayeredPane.POPUP_LAYER); layeredPane.add(scorePanel); } private void createSettingsPanel() { settingsPanel = new SettingsPanel(); settingsPanel.setVisible(false); settingsPanel.getNetworkGameEvent().add(new IListener() { @Override public void handle() { networkGameEvent.emit(); } }); settingsPanel.getLoadGameEvent().add(new IListener() { @Override public void handle() { load(); } }); } private void createMainLayer() { mainLayer = new JPanel(); mainLayer.setLayout(null); layeredPane.add(mainLayer); table = new TablePanel(); mainLayer.add(table); table.setBorder(new MatteBorder(0, 0, TABLE_BORDER_WIDTH, 0, Color.BLACK)); playerPanel = new PlayerPanel(); mainLayer.add(playerPanel); startTurnPanel = new StartTurnPanel(); startTurnPanel.setVisible(false); mainLayer.add(startTurnPanel); pausePanel = new PausePanel(); pausePanel.setVisible(false); mainLayer.add(pausePanel); roundEndPanel = new RoundEndPanel(); roundEndPanel.setVisible(false); mainLayer.add(roundEndPanel); sidePanel = new SidePanel(); sidePanel.setVisible(false); mainLayer.add(sidePanel); sidePanel .setBorder(new CompoundBorder(new MatteBorder(0, 0, 0, 1, Color.BLACK), new MatteBorder(0, 0, TABLE_BORDER_WIDTH, 0, Color.GRAY))); } @Override public void setMayPause(boolean mayPause) { playerPanel.setMayPause(mayPause); } @Override public void enablePauseMode(boolean enable) { table.enablePauseMode(enable); doSetBottomPanel(enable ? null : bottomPanelType); pausePanel.setVisible(enable); } private void rescale() { int width = getContentPane().getWidth(), height = getContentPane() .getHeight(); layeredPane.setBounds(0, 0, width, height); mainLayer.setBounds(0, 0, width, height); int playerPanelHeight = even(Math.pow((double) width * width * height, 1 / 3.0) * PLAYER_PANEL_RATIO); if (playerPanelHeight > PLAYER_PANEL_MAX_HEIGHT) playerPanelHeight = PLAYER_PANEL_MAX_HEIGHT; int tableHeight = height - playerPanelHeight; playerPanel.setBounds(0, tableHeight, width, playerPanelHeight); playerPanel.rescale(); int sideWidth = sidePanel.isVisible() ? playerPanel.getLeftPanelWidth() + 1 : 0; table.setBounds(sideWidth, 0, width - sideWidth, tableHeight); table.validate(); if (sidePanel.isVisible()) { sidePanel.setBounds(0, 0, sideWidth, tableHeight); } startTurnPanel.setBounds(0, tableHeight, width, playerPanelHeight); pausePanel.setBounds(0, tableHeight, width, playerPanelHeight); roundEndPanel.setBounds(0, tableHeight, width, playerPanelHeight); rescaleSubpanel(settingsPanel, 1 / 2.0, 1 / 2.0, 475, 300); rescaleSubpanel(scorePanel, 3 / 4.0, 1 / 2.0, 450, 300); rescaleSubpanel(loginPanel, 1 / 3.0, 1 / 3.0, 350, 200); rescaleSubpanel(gameListPanel, 1 / 2.0, 1 / 2.0, 475, 300); rescaleSubpanel(quitWarningPanel, 1 / 2.0, 1 / 6.0, 400, 150); quitWarningPanel.setLocation(0, 0); quitWarningFrame.setSize(quitWarningPanel.getSize()); quitWarningFrame.setLocationRelativeTo(this); rescaleSubpanel(connectPanel, 1 / 2.0, 1 / 6.0, 400, 150); } private void rescaleSubpanel(JPanel sub, double widthFactor, double heightFactor, int minWidth, int minHeight) { int width = getContentPane().getWidth(), height = getContentPane() .getHeight(); int panelWidth = Math.max(minWidth, (int) (width * widthFactor)); int panelHeight = Math.max(minHeight, (int) (height * heightFactor)); int x = (width - panelWidth) / 2; int y = (height - panelHeight) / 2; sub.setBounds(x, y, panelWidth, panelHeight); } @Override public void setSelectedStones(Collection stones) { table.setSelectedStones(stones); playerPanel.getHandPanel().setSelectedStones(stones); } @Override public void setInvalidStoneSets(Collection sets) { table.setInvalidStoneSets(sets); } @Override public void showSettingsPanel(boolean show) { if (show) { settingsPanel.resetTabbedPane(); } settingsPanel.setVisible(show); } @Override public void showLoginPanel(boolean show) { loginPanel.setVisible(show); } @Override public void resetLoginPanel() { loginPanel.resetLoginPanel(); } @Override public void showGameListPanel(boolean show) { if (show) { gameListPanel.reset(); } gameListPanel.setVisible(show); } @Override public void showScorePanel(boolean show) { scorePanel.setVisible(show); } @Override public void showSidePanel(boolean show) { sidePanel.setVisible(show); rescale(); } @Override public void showQuitWarningPanel(boolean show) { quitWarningFrame.setLocationRelativeTo(this); quitWarningFrame.setVisible(show); if (System.getProperty("os.name").startsWith("Windows")) { // disabling is broken under windows layeredPane.setVisible(!show); menuBar.setVisible(!show); } else { setEnabled(!show); } } @Override public void showConnectPanel(boolean show) { connectPanel.setVisible(show); } @Override public void setCurrentPlayerName(String playerName) { playerPanel.setCurrentPlayerName(playerName); startTurnPanel.setCurrentPlayerName(playerName); pausePanel.setCurrentPlayerName(playerName); } @Override public void setInitialMeldError(int points) { startTurnPanel.setInitialMeldError(points); } @Override public void setInitialMeldFirstError() { startTurnPanel.setInitialMeldFirstError(); } @Override public void setCurrentPlayerColor(Color color) { playerPanel.setCurrentPlayerColor(color); startTurnPanel.setCurrentPlayerColor(color); pausePanel.setCurrentPlayerColor(color); } @Override public void setRedealedPlayerName(String name) { startTurnPanel.setRedealedPlayerName(name); } @Override public void setLastStonePlayerName(String name) { startTurnPanel.setLastStonePlayerName(name); } @Override public void setCurrentPlayerHasLaidOut(boolean hasLaidOut) { playerPanel.setHasLaidOut(hasLaidOut); } @Override public IEvent getStartTurnEvent() { return startTurnPanel.getStartTurnEvent(); } @Override public IEvent getAcknowledgeInvalidEvent() { return startTurnPanel.getAcknowledgeInvalidEvent(); } @Override public IEvent getAcknowledgeConnectionLostEvent() { return startTurnPanel.getAcknowledgeConnectionLostEvent(); } @Override public IEvent getNewRoundEvent() { return roundEndPanel.getNewRoundEvent(); } @Override public IEvent getNewGameEvent() { return roundEndPanel.getNewGameEvent(); } @Override public IEvent getEndProgramEvent() { return roundEndPanel.getEndProgramEvent(); } @SuppressWarnings("unchecked") private List> createDecorationStones() { Pair stoneJ = new Pair(new Stone(-'J', StoneColor.BLACK), new Position(2.5f, 0)); Pair stoneR = new Pair(new Stone(-'R', StoneColor.ORANGE), new Position(3.5f, 0)); Pair stoneu1 = new Pair(new Stone(-'u', StoneColor.BLUE), new Position(4.5f, 0)); Pair stonem1 = new Pair(new Stone(-'m', StoneColor.RED), new Position(5.5f, 0)); Pair stonem2 = new Pair(new Stone(-'m', StoneColor.GREEN), new Position(6.5f, 0)); Pair stonei = new Pair(new Stone(-'i', StoneColor.VIOLET), new Position(7.5f, 0)); Pair stonek = new Pair(new Stone(-'k', StoneColor.AQUA), new Position(8.5f, 0)); Pair stoneu2 = new Pair(new Stone(-'u', StoneColor.GRAY), new Position(9.5f, 0)); Pair stoneb = new Pair(new Stone(-'b', StoneColor.BLACK), new Position(10.5f, 0)); Pair stone1 = new Pair(new Stone( StoneColor.RED), new Position(2, 1)); Pair stone2 = new Pair(new Stone(13, StoneColor.BLACK), new Position(5, 1)); Pair stone3 = new Pair(new Stone(13, StoneColor.ORANGE), new Position(6, 1)); Pair stone4 = new Pair(new Stone(13, StoneColor.BLUE), new Position(7, 1)); Pair stone5 = new Pair(new Stone(13, StoneColor.RED), new Position(8, 1)); Pair stone6 = new Pair(new Stone( StoneColor.BLACK), new Position(11, 1)); return Arrays .asList(stoneJ, stoneR, stoneu1, stonem1, stonem2, stonei, stonek, stoneu2, stoneb, stone1, stone2, stone3, stone4, stone5, stone6); } @Override public void setBottomPanel(BottomPanelType type) { bottomPanelType = type; doSetBottomPanel(type); } private void doSetBottomPanel(BottomPanelType type) { boolean showStartTurnPanel = (type == BottomPanelType.START_TURN_PANEL || type == BottomPanelType.START_REDEAL_TURN_PANEL || type == BottomPanelType.START_LAST_TURN_PANEL || type == BottomPanelType.INVALID_TURN_PANEL || type == BottomPanelType.NETWORK_SERVER_CONNECTION_LOST_PANEL); startTurnPanel.setType(type); startTurnPanel.setVisible(showStartTurnPanel); boolean showWinPanel = (type == BottomPanelType.WIN_PANEL || type == BottomPanelType.NETWORK_WIN_PANEL || type == BottomPanelType.NETWORK_CONNECTION_LOST_PANEL); roundEndPanel.setType(type); roundEndPanel.setVisible(showWinPanel); playerPanel.setVisible((!showStartTurnPanel) && (!showWinPanel) && type != null); if (type == BottomPanelType.START_GAME_PANEL) { table.setStoneSets(Collections.> emptyList()); playerPanel.getHandPanel().setStones(createDecorationStones()); } playerPanel.showButtons(type != BottomPanelType.START_GAME_PANEL); playerPanel.enableButtons(type != BottomPanelType.NONHUMAN_HAND_PANEL); } @Override public void setStoneCollectionHidden(boolean enable) { table.getStoneCollectionPanel().setHidden(enable); } }