package net.knarcraft.minecraftserverlauncher.userinterface; import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController; import javax.imageio.ImageIO; import javax.naming.ConfigurationException; import javax.swing.*; import javax.swing.plaf.basic.BasicButtonUI; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Scanner; import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream; /** * Generates a ServerLauncherGUI. * * @author Kristian Knarvik <kristian.knarvik@knett.no> * @version 1.0.0 * @since 1.0.0 */ public class ServerLauncherGUI extends MessageHandler implements ActionListener, GUI { private final ServerLauncherController controller; private Map<String, String> textStrings; private Tray applicationTray; private JFrame frame; private JTabbedPane mainTabbedPane; private JTabbedPane serversPane; private ServerControlTab serverControlTab; private ControlPanelTab controlPanelTab; private ServerLauncherMenu serverLauncherMenu; private JButton addServerTabButton; private JButton addServerPaneButton; /** * Creates the application window */ public ServerLauncherGUI() throws IOException { super(false); initialize(440, 170); loadMessages(); this.controller = Main.getController(); } /** * Creates the application window * * @param silent <p>Whether to make the GUI silent (hidden, for testing)</p> */ public ServerLauncherGUI(boolean silent) throws IOException { super(silent); if (!silent) { initialize(440, 170); } loadMessages(); this.controller = Main.getController(); } /** * Creates the application window with a preferred width and height * * @param width <p>The preferred width</p> * @param height <p>The preferred height</p> */ public ServerLauncherGUI(int width, int height) throws IOException { super(false); initialize(width, height); loadMessages(); this.controller = Main.getController(); } /** * Gets the pane used for server configurations * * @return <p>The pane used for server configurations</p> */ public JTabbedPane getPane() { return this.serversPane; } /** * Gets this GUI's control panel tab * @return <p>The control panel tab for this GUI</p> */ public ControlPanelTab getControlPanelTab() { return this.controlPanelTab; } @Override public void setStatus(String text) { controlPanelTab.setStatusText(text); this.logMessage(text); } @Override public File askForDirectory(String prompt) { JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(new java.io.File(".")); chooser.setDialogTitle(prompt); chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setAcceptAllFileFilterUsed(false); if (chooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) { setStatus("Choice aborted by user"); return null; } return chooser.getSelectedFile(); } /** * Gets the server control tab used by this GUI * * @return <p>The server control tab used by this GUI</p> */ public ServerControlTab getServerControlTab() { return this.serverControlTab; } /** * Gets the size of the main JFrame * * @return <p>The Dimension of the main JFrame</p> */ public Dimension getSize() { return frame.getContentPane().getSize(); } /** * Updates ServerLauncherGUI according to current profile settings */ public void updateWithSavedProfileData() { ServerLauncherController controller = Main.getController(); serversPane.removeAll(); serverLauncherMenu.update(); serverControlTab.update(); for (Collection collection : controller.getCurrentProfile().getCollections()) { serversPane.addTab(collection.getName(), collection.getServerTab().getPanel()); addCloseButtonToServerTab(collection.getName()); } addAddButtonToServerTab(); } /** * Adds an add button to the servers tab's tabs */ private void addAddButtonToServerTab() { JPanel tabPanel = new JPanel(); tabPanel.setLayout(new GridLayout()); tabPanel.setOpaque(false); JPanel tabContentsPanel = new JPanel(new SpringLayout()); serversPane.addTab("Add tab", tabContentsPanel); addServerTabButton = getAddServerButton(true); addServerTabButton.addActionListener(this); addServerPaneButton = getAddServerButton(false); addServerPaneButton.addActionListener(this); tabContentsPanel.add(addServerTabButton); tabPanel.add(addServerPaneButton); serversPane.setTabComponentAt(serversPane.getTabCount() - 1, tabPanel); } /** * Gets a button for adding a new server * @param displayButtonStyle <p>Whether to show or hide the button's style</p> * @return <p>A new add server button</p> */ private JButton getAddServerButton(boolean displayButtonStyle) { JButton addButton = new JButton("+ Add server"); if (!displayButtonStyle) { addButton.setBorder(BorderFactory.createEtchedBorder()); addButton.setFocusable(false); addButton.setBorderPainted(false); addButton.setContentAreaFilled(false); addButton.setRolloverEnabled(true); addButton.setUI(new BasicButtonUI()); } return addButton; } /** * * @param serverName <p>The name of the server/tab to add a close button to</p> */ private void addCloseButtonToServerTab(String serverName) { int index = serversPane.indexOfTab(serverName); JPanel tabPanel = new JPanel(new GridBagLayout()); tabPanel.setOpaque(false); JLabel serverTitleLabel = new JLabel(serverName); JButton removeServerButton = new JButton("(X)"); removeServerButton.setBorder(BorderFactory.createEtchedBorder()); removeServerButton.setFocusable(false); removeServerButton.setBorderPainted(false); removeServerButton.setContentAreaFilled(false); removeServerButton.setRolloverEnabled(true); removeServerButton.setPreferredSize(new Dimension(18, 17)); removeServerButton.setUI(new BasicButtonUI()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.weightx = 1; tabPanel.add(serverTitleLabel, gridBagConstraints); gridBagConstraints.gridx++; gridBagConstraints.weightx = 0; tabPanel.add(removeServerButton, gridBagConstraints); serversPane.setTabComponentAt(index, tabPanel); removeServerButton.addActionListener(new CloseTabActionListener(serversPane, serverName)); } /** * Initializes the server launcher GUI * * @param width <p>The width of the GUI</p> * @param height <p>The height of the GUI</p> * @throws IOException <p>If unable to load the GUI icon</p> */ private void initialize(int width, int height) throws IOException { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | UnsupportedLookAndFeelException | InstantiationException | IllegalAccessException e ) { e.printStackTrace(); } frame = new JFrame("Minecraft server launcher"); frame.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); frame.getContentPane().setPreferredSize(new Dimension(width, height)); ImageIcon img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png"))); frame.setIconImage(img.getImage()); JMenuBar menuBar = new JMenuBar(); frame.setJMenuBar(menuBar); this.serverLauncherMenu = new ServerLauncherMenu(menuBar, this); mainTabbedPane = new JTabbedPane(JTabbedPane.TOP); frame.getContentPane().add(mainTabbedPane); JPanel controlPanelPanel = new JPanel(); mainTabbedPane.addTab("Control panel", null, controlPanelPanel, null); controlPanelTab = new ControlPanelTab(controlPanelPanel); JPanel controlServersPanel = new JPanel(); mainTabbedPane.addTab("Control servers", null, controlServersPanel, null); serverControlTab = new ServerControlTab(frame, controlServersPanel); JPanel serversPanel = new JPanel(); mainTabbedPane.addTab("Servers", null, serversPanel, null); SpringLayout serversPanelSpringLayout = new SpringLayout(); serversPanel.setLayout(serversPanelSpringLayout); serversPane = new JTabbedPane(JTabbedPane.TOP); serversPanelSpringLayout.putConstraint(SpringLayout.NORTH, serversPane, 0, SpringLayout.NORTH, serversPanel); serversPanelSpringLayout.putConstraint(SpringLayout.WEST, serversPane, 0, SpringLayout.WEST, serversPanel); serversPanelSpringLayout.putConstraint(SpringLayout.SOUTH, serversPane, 0, SpringLayout.SOUTH, serversPanel); serversPanelSpringLayout.putConstraint(SpringLayout.EAST, serversPane, 0, SpringLayout.EAST, serversPanel); serversPanel.add(serversPane); serversPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); frame.validate(); frame.pack(); frame.setVisible(true); applicationTray = new Tray(frame, this); updateGUIElementsWhenServersStartOrStop(false); } /** * Hides the GUI to the system tray */ public void hideToTray() { applicationTray.hideToTray(); } @Override public void actionPerformed(ActionEvent e) { Object actionSource = e.getSource(); //Register actions on the main tab handleMainTabButtons(actionSource); } /** * Handles buttons and the combo on the main tab * * @param actionSource <p>The object being interacted with</p> */ private void handleMainTabButtons(Object actionSource) { if (actionSource == addServerTabButton || actionSource == addServerPaneButton) { addServer(); } } /** * Adds a new server with a server tab */ private void addServer() { String serverName = JOptionPane.showInputDialog("Name of server: "); try { controller.getCurrentProfile().addCollection(serverName); } catch (ConfigurationException e1) { e1.printStackTrace(); } this.updateWithSavedProfileData(); controller.getCurrentProfile().updateConsoles(); } /** * Updates the ServerLauncherGUI components to block a user from doing illegal actions * * @param running <p>Whether the servers are currently running</p> */ public void updateGUIElementsWhenServersStartOrStop(boolean running) { boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running. mainTabbedPane.setEnabledAt(1, !stopped); mainTabbedPane.setEnabledAt(2, stopped); controlPanelTab.updateGUIElementsWhenServersStartOrStop(running); } /** * Gets a specific message from its key * * @param stringKey <p>The key for the string to get</p> * @return <p>The corresponding string</p> */ public String getMessage(String stringKey) { return textStrings.get(stringKey); } /** * Loads popup messages from a text file */ private void loadMessages() throws FileNotFoundException { textStrings = new HashMap<>(); Scanner file = getResourceAsScanner("menumsg.csv"); while (file.hasNextLine()) { String nextLine = file.nextLine(); String[] line = nextLine.split("="); String content = line[1].replaceAll("_BREAK_", System.getProperty("line.separator")); textStrings.put(line[0], content); } } }