package teamcomm.gui; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import teamcomm.TeamCommunicationMonitor; import teamcomm.data.GameState; import teamcomm.data.RobotState; import teamcomm.data.event.TeamEvent; import teamcomm.data.event.TeamEventListener; import teamcomm.net.logging.LogReplayer; /** * Class for the main window of the application. * * @author Felix Thielke */ public class MainWindow extends JFrame implements TeamEventListener { private static final long serialVersionUID = 6549981924840180076L; private static final Map<Integer, ImageIcon> logos = new HashMap<>(); private final View3D fieldView = new View3D(); private final JPanel[] teamPanels = new JPanel[]{new JPanel(), new JPanel(), new JPanel()}; private final JLabel[] teamLogos = new JLabel[]{new JLabel((Icon) null, SwingConstants.CENTER), new JLabel((Icon) null, SwingConstants.CENTER)}; private final Map<String, RobotPanel> robotPanels = new HashMap<>(); @SuppressWarnings("unused") private final LogReplayFrame logReplayFrame = new LogReplayFrame(this); /** * Constructor. */ public MainWindow() { super("TeamCommunicationMonitor"); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // Initialize initialize(); } }); } private void initialize() { // Setup window setLocationByPlatform(true); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { TeamCommunicationMonitor.shutdown(); } }); // Setup team panels final Box left = new Box(BoxLayout.Y_AXIS); teamPanels[0].setLayout(new GridLayout(10, 1, 0, 5)); left.add(teamPanels[0]); left.add(new Box.Filler(new Dimension(RobotPanel.PANEL_WIDTH, RobotPanel.PANEL_HEIGHT), new Dimension(RobotPanel.PANEL_WIDTH, RobotPanel.PANEL_HEIGHT), new Dimension(RobotPanel.PANEL_WIDTH, 1000))); final Box right = new Box(BoxLayout.Y_AXIS); teamPanels[1].setLayout(new GridLayout(10, 1, 0, 5)); right.add(teamPanels[1]); right.add(new Box.Filler(new Dimension(RobotPanel.PANEL_WIDTH, RobotPanel.PANEL_HEIGHT), new Dimension(RobotPanel.PANEL_WIDTH, RobotPanel.PANEL_HEIGHT), new Dimension(RobotPanel.PANEL_WIDTH, 1000))); final Box bottom = new Box(BoxLayout.X_AXIS); bottom.setBorder(new EmptyBorder(0, RobotPanel.PANEL_WIDTH, 0, RobotPanel.PANEL_WIDTH)); teamPanels[2].setLayout(new BoxLayout(teamPanels[2], BoxLayout.LINE_AXIS)); bottom.add(teamPanels[2]); // Setup team logos teamPanels[0].add(teamLogos[0]); teamPanels[1].add(teamLogos[1]); // Setup content pane final JPanel contentPane = new JPanel(new BorderLayout()); contentPane.add(left, BorderLayout.WEST); contentPane.add(right, BorderLayout.EAST); contentPane.add(bottom, BorderLayout.SOUTH); contentPane.add(fieldView.getCanvas(), BorderLayout.CENTER); setContentPane(contentPane); // Add menu bar final JMenuBar mb = new JMenuBar(); mb.add(createFileMenu()); mb.add(createViewMenu()); setJMenuBar(mb); // Display window setPreferredSize(new Dimension(1442, 720)); pack(); setVisible(true); // Listen for robot events GameState.getInstance().addListener(this); } private JMenu createFileMenu() { final JMenu fileMenu = new JMenu("File"); final JMenuItem resetItem = new JMenuItem("Reset"); resetItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { GameState.getInstance().reset(); } }); resetItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0)); fileMenu.add(resetItem); final JMenuItem replayItem = new JMenuItem("Replay log file"); fileMenu.add(replayItem); replayItem.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { final JFileChooser fc = new JFileChooser(new File(new File(".").getAbsoluteFile(), "logs_teamcomm")); if (fc.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) { try { LogReplayer.getInstance().open(fc.getSelectedFile()); } catch (IOException ex) { JOptionPane.showMessageDialog(null, "Error opening log file.", ex.getClass().getSimpleName(), JOptionPane.ERROR_MESSAGE); } } } }); replayItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK)); final JMenuItem exitItem = new JMenuItem("Exit"); exitItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { TeamCommunicationMonitor.shutdown(); setVisible(false); } }); fileMenu.add(exitItem); return fileMenu; } private JMenu createViewMenu() { final JMenu viewMenu = new JMenu("View"); // Mirroring final JCheckBoxMenuItem mirrorOption = new JCheckBoxMenuItem("Mirror", GameState.getInstance().isMirrored()); mirrorOption.addItemListener(new ItemListener() { @Override public void itemStateChanged(final ItemEvent e) { GameState.getInstance().setMirrored(e.getStateChange() == ItemEvent.SELECTED); } }); viewMenu.add(mirrorOption); // Drawings viewMenu.add(fieldView.getDrawingsMenu()); return viewMenu; } /** * Terminates the view. */ public void terminate() { fieldView.terminate(); } @Override public void teamChanged(final TeamEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (e.side != GameState.TEAM_OTHER) { teamLogos[e.side].setIcon(TeamLogoLoader.getInstance().getTeamLogoPanelIcon(e.teamNumber)); } int i = 0; for (final RobotState r : e.players) { RobotPanel panel = robotPanels.get(r.getAddress()); if (panel == null) { panel = new RobotPanel(r); robotPanels.put(r.getAddress(), panel); } if (teamPanels[e.side].getComponentCount() <= i + (e.side < 2 ? 1 : 0)) { teamPanels[e.side].add(panel); panel.revalidate(); } else if (panel != teamPanels[e.side].getComponent(i + (e.side < 2 ? 1 : 0))) { teamPanels[e.side].remove(panel); teamPanels[e.side].add(panel, i + (e.side < 2 ? 1 : 0)); panel.revalidate(); } panel.setTeamLogoVisible(e.side == GameState.TEAM_OTHER); i++; } boolean teamPanelChanged = false; while (e.players.size() < teamPanels[e.side].getComponentCount() - (e.side < 2 ? 1 : 0)) { teamPanelChanged = true; final RobotPanel panel = (RobotPanel) teamPanels[e.side].getComponent(teamPanels[e.side].getComponentCount() - 1); teamPanels[e.side].remove(teamPanels[e.side].getComponentCount() - 1); robotPanels.remove(panel.getRobotAddress()); panel.dispose(); } if (teamPanelChanged) { teamPanels[e.side].repaint(); } } }); } }