7 Commits

Author SHA1 Message Date
de0f1a6e37 Adds unfinished code showing the idea of how dockable tabs are supposed to be implemented
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-10-03 14:23:25 +02:00
166d63f1b2 Moves the show consoles button to the main control panel
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
Also makes the control servers tab hidden if the servers are not running
2021-10-01 13:56:16 +02:00
8f25fa2796 Fixes the font of the status label
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-10-01 01:26:28 +02:00
3467c900f0 Changes some variable names 2021-10-01 01:09:34 +02:00
9f092a73fe Extracts the control panel tab to its own class, and makes the add server button into a tab button 2021-10-01 00:58:00 +02:00
50b9188229 Makes sure all GUI windows have the same icon
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-09-30 17:47:12 +02:00
b021de5594 Replaces the "Remove server" button with an (X) on the tab itself
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-09-29 13:16:57 +02:00
13 changed files with 508 additions and 231 deletions

View File

@ -141,14 +141,16 @@ public class Profile {
* @param name <p>The name of the collection and its elements</p> * @param name <p>The name of the collection and its elements</p>
*/ */
public void addCollection(String name) throws ConfigurationException { public void addCollection(String name) throws ConfigurationException {
if (name == null) { //If a user cancels or crosses out window //Skip if no name was given
if (name == null) {
return; return;
} }
if (getCollection(name) == null && !name.equals("All") && CommonFunctions.nameIsValid(name)) { if (getCollection(name) == null && !name.equals("All") && CommonFunctions.nameIsValid(name)) {
collections.add(new Collection(name)); collections.add(new Collection(name));
} else { } else {
serverLauncherGui.showError("A server name must my unique and not empty or \"All\"." + serverLauncherGui.showError("A server name must be unique and not empty. " +
"It can't contain any of the characters \"!\", \"?\" or \";\"."); "In addition, a server cannot be named: \"All\". " +
"It cannot contain any of the characters \"!\", \"?\" or \";\".");
} }
} }

View File

@ -379,7 +379,7 @@ public class ServerLauncherController {
* Updates the GUI as necessary to display loaded data * Updates the GUI as necessary to display loaded data
*/ */
private void executeGUILoadingTasks() { private void executeGUILoadingTasks() {
this.serverLauncherGUI.updateProfiles(); this.serverLauncherGUI.getControlPanelTab().updateProfiles();
this.serverLauncherGUI.updateWithSavedProfileData(); this.serverLauncherGUI.updateWithSavedProfileData();
this.currentProfile.updateConsoles(); this.currentProfile.updateConsoles();
if (this.downloadAllJars) { if (this.downloadAllJars) {

View File

@ -2,10 +2,14 @@ package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil; import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
import javax.imageio.ImageIO;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.io.IOException;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
/** /**
* The Backup GUI is used to display backup progress * The Backup GUI is used to display backup progress
@ -33,6 +37,13 @@ public class BackupGUI implements ActionListener {
frame = new JFrame("Running backup..."); frame = new JFrame("Running backup...");
frame.setBounds(100, 100, 500, 140); frame.setBounds(100, 100, 500, 140);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
ImageIcon img;
try {
img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png")));
frame.setIconImage(img.getImage());
} catch (IOException ignored) {
}
progressTextArea = new JTextArea(); progressTextArea = new JTextArea();
progressTextArea.setEditable(false); progressTextArea.setEditable(false);
progressBar = new JProgressBar(); progressBar = new JProgressBar();

View File

@ -0,0 +1,47 @@
package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Listener for clicking the close button of a server tab
*/
public class CloseTabActionListener implements ActionListener {
private final String tabName;
private final JTabbedPane tabPane;
/**
* Instantiates a new close tab action listener
* @param tabPane <p>The tab pane containing all tabs</p>
* @param tabName <p>The name of the tab connected to this action listener</p>
*/
public CloseTabActionListener(JTabbedPane tabPane, String tabName) {
this.tabName = tabName;
this.tabPane = tabPane;
}
@Override
public void actionPerformed(ActionEvent evt) {
int index = tabPane.indexOfTab(tabName);
if (index >= 0) {
//Abort if the user just mis-clicked
int answer = JOptionPane.showConfirmDialog(null,
String.format("Do you really want to remove the server %s?", tabName), "Remove server",
JOptionPane.YES_NO_OPTION
);
if (answer == JOptionPane.YES_NO_OPTION) {
//Remove the server
ServerLauncherController controller = Main.getController();
controller.getCurrentProfile().removeCollection(tabName);
controller.getGUI().updateWithSavedProfileData();
controller.getCurrentProfile().updateConsoles();
}
}
}
}

View File

@ -0,0 +1,217 @@
package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.concurrent.Executors;
public class ControlPanelTab implements ActionListener {
private JButton startServerButton;
private JButton stopServerButton;
private JButton backupButton;
private JButton addProfileButton;
private JButton showConsolesButton;
private JButton deleteProfileButton;
private JComboBox<String> profiles;
private final JPanel controlPanelPanel;
private final ServerLauncherController controller;
private final JLabel statusLabel = new JLabel("Servers are stopped");
public ControlPanelTab(JPanel controlPanelPanel) {
this.controlPanelPanel = controlPanelPanel;
this.controller = Main.getController();
initialize();
}
/**
* Sets the text of the status label
* @param text <p>The new text of the status label</p>
*/
public void setStatusText(String text) {
this.statusLabel.setText(text);
}
/**
* 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.
profiles.setEnabled(stopped);
addProfileButton.setEnabled(stopped);
deleteProfileButton.setEnabled(stopped);
startServerButton.setEnabled(stopped);
stopServerButton.setEnabled(running);
}
/**
* Stops all servers
*/
public void stopServers() {
GUI gui = Main.getController().getGUI();
try {
gui.setStatus("Servers are stopping...");
ServerHandler.stop();
} catch (IOException e1) {
gui.showError("Could not stop server.");
e1.printStackTrace();
} catch (InterruptedException e) {
gui.showError("Could not kill server.");
e.printStackTrace();
}
}
/**
* Gets the currently selected profile
*
* @return <p>The currently selected profile or null</p>
*/
public String getSelectedProfile() {
Object selectedProfile = profiles.getSelectedItem();
if (selectedProfile != null) {
return selectedProfile.toString();
} else {
return null;
}
}
/**
* Updates the profiles combo
*/
public void updateProfiles() {
String selectedProfile = Main.getController().getCurrentProfile().getName();
this.profiles.removeAllItems();
for (String profile : Main.getController().getProfileNames()) {
this.profiles.addItem(profile);
}
this.profiles.setSelectedItem(selectedProfile);
}
/**
* Deletes the selected profile
*/
private void deleteProfile() {
Object selected = profiles.getSelectedItem();
int answer = JOptionPane.showConfirmDialog(null,
String.format("Do you really want to remove the profile %s?", selected), "Remove profile",
JOptionPane.YES_NO_OPTION
);
if (answer == JOptionPane.YES_NO_OPTION) {
if (selected != null) {
controller.removeProfile(selected.toString());
updateProfiles();
}
}
}
/**
* Saves the previous profile and loads data from the new profile
*/
private void changeProfile() {
controller.saveState();
Object current = this.profiles.getSelectedItem();
if (current != null) {
controller.setCurrentProfile(current.toString());
}
controller.getGUI().updateWithSavedProfileData();
controller.getCurrentProfile().updateConsoles();
}
private void initialize() {
SpringLayout springLayout = new SpringLayout();
controlPanelPanel.setLayout(springLayout);
JLabel lblBasicControls = new JLabel("Basic controls");
springLayout.putConstraint(SpringLayout.NORTH, lblBasicControls, 10, SpringLayout.NORTH, controlPanelPanel);
controlPanelPanel.add(lblBasicControls);
startServerButton = new JButton("Start servers");
springLayout.putConstraint(SpringLayout.WEST, lblBasicControls, 0, SpringLayout.WEST, startServerButton);
springLayout.putConstraint(SpringLayout.NORTH, startServerButton, 6, SpringLayout.SOUTH, lblBasicControls);
springLayout.putConstraint(SpringLayout.WEST, startServerButton, 10, SpringLayout.WEST, controlPanelPanel);
controlPanelPanel.add(startServerButton);
startServerButton.addActionListener(this);
stopServerButton = new JButton("Stop servers");
springLayout.putConstraint(SpringLayout.NORTH, stopServerButton, 0, SpringLayout.NORTH, startServerButton);
springLayout.putConstraint(SpringLayout.WEST, stopServerButton, 6, SpringLayout.EAST, startServerButton);
controlPanelPanel.add(stopServerButton);
stopServerButton.addActionListener(this);
showConsolesButton = new JButton("View server consoles");
springLayout.putConstraint(SpringLayout.NORTH, showConsolesButton, 0, SpringLayout.NORTH, stopServerButton);
springLayout.putConstraint(SpringLayout.WEST, showConsolesButton, 6, SpringLayout.EAST, stopServerButton);
controlPanelPanel.add(showConsolesButton);
showConsolesButton.addActionListener(this);
backupButton = new JButton("Backup");
springLayout.putConstraint(SpringLayout.NORTH, backupButton, 0, SpringLayout.NORTH, showConsolesButton);
springLayout.putConstraint(SpringLayout.WEST, backupButton, 6, SpringLayout.EAST, showConsolesButton);
controlPanelPanel.add(backupButton);
backupButton.addActionListener(this);
JLabel profileLabel = new JLabel("Profile");
springLayout.putConstraint(SpringLayout.NORTH, profileLabel, 6, SpringLayout.SOUTH, startServerButton);
springLayout.putConstraint(SpringLayout.WEST, profileLabel, 10, SpringLayout.WEST, controlPanelPanel);
controlPanelPanel.add(profileLabel);
addProfileButton = new JButton("+");
springLayout.putConstraint(SpringLayout.NORTH, addProfileButton, 6, SpringLayout.SOUTH, profileLabel);
springLayout.putConstraint(SpringLayout.WEST, addProfileButton, 10, SpringLayout.WEST, controlPanelPanel);
controlPanelPanel.add(addProfileButton);
addProfileButton.addActionListener(this);
deleteProfileButton = new JButton("-");
springLayout.putConstraint(SpringLayout.NORTH, deleteProfileButton, 0, SpringLayout.NORTH, addProfileButton);
springLayout.putConstraint(SpringLayout.WEST, deleteProfileButton, 6, SpringLayout.EAST, addProfileButton);
controlPanelPanel.add(deleteProfileButton);
deleteProfileButton.addActionListener(this);
profiles = new JComboBox<>();
springLayout.putConstraint(SpringLayout.NORTH, profiles, 0, SpringLayout.NORTH, addProfileButton);
springLayout.putConstraint(SpringLayout.WEST, profiles, 6, SpringLayout.EAST, deleteProfileButton);
springLayout.putConstraint(SpringLayout.EAST, profiles, 124, SpringLayout.EAST, deleteProfileButton);
controlPanelPanel.add(profiles);
profiles.addActionListener(this);
springLayout.putConstraint(SpringLayout.NORTH, statusLabel, 6, SpringLayout.SOUTH, addProfileButton);
springLayout.putConstraint(SpringLayout.SOUTH, statusLabel, -10, SpringLayout.SOUTH, controlPanelPanel);
springLayout.putConstraint(SpringLayout.WEST, statusLabel, 10, SpringLayout.WEST, controlPanelPanel);
springLayout.putConstraint(SpringLayout.EAST, statusLabel, -10, SpringLayout.EAST, controlPanelPanel);
statusLabel.setFont(new Font("", Font.BOLD, 12));
controlPanelPanel.add(statusLabel);
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
Object actionSource = actionEvent.getSource();
if (actionSource == startServerButton) {
controller.saveState();
Executors.newSingleThreadExecutor().execute(ServerHandler::startServers);
} else if (actionSource == stopServerButton) {
stopServers();
} else if (actionSource == backupButton) {
//Run backup in its own thread to prevent locking up
Executors.newSingleThreadExecutor().execute(() -> BackupUtil.backup(controller.getGUI()));
} else if (actionSource == addProfileButton) {
controller.addProfile(JOptionPane.showInputDialog("Profile name: "));
updateProfiles();
} else if (actionSource == deleteProfileButton) {
deleteProfile();
} else if (actionSource == profiles) {
changeProfile();
} else if (actionSource == showConsolesButton) {
ServerConsoles.setAsVisible();
}
}
}

View File

@ -0,0 +1,35 @@
package net.knarcraft.minecraftserverlauncher.userinterface;
import javax.swing.*;
/**
* An extended JTabbedPane with dockable tabs
*/
public class JDockableTabbedPane extends JTabbedPane {
private String tabbedPaneId;
public JDockableTabbedPane(String tabbedPaneId) {
super();
this.tabbedPaneId = tabbedPaneId;
}
public JDockableTabbedPane(String tabbedPaneId, int tabPlacement) {
super(tabPlacement);
this.tabbedPaneId = tabbedPaneId;
}
public JDockableTabbedPane(String tabbedPaneId, int tabPlacement, int tabLayoutPolicy) {
super(tabPlacement, tabLayoutPolicy);
this.tabbedPaneId = tabbedPaneId;
}
/**
* Gets the id of this tabbed pane
* @return <p>The id of this tabbed pane</p>
*/
public String getTabbedPaneId() {
return tabbedPaneId;
}
}

View File

@ -1,7 +1,11 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import javax.imageio.ImageIO;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.io.IOException;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
/** /**
* This class keeps track of all consoles * This class keeps track of all consoles
@ -31,6 +35,12 @@ public class ServerConsoles {
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP); consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER); frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER);
ImageIcon img;
try {
img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png")));
frame.setIconImage(img.getImage());
} catch (IOException ignored) {
}
} }
} }

View File

@ -22,7 +22,6 @@ public class ServerControlTab implements ActionListener {
private JButton customCommandButton; private JButton customCommandButton;
private JButton saveServerButton; private JButton saveServerButton;
private JButton reloadButton; private JButton reloadButton;
private JButton showConsolesButton;
private JTextField customCommandTextField; private JTextField customCommandTextField;
private final ServerLauncherController controller = ServerLauncherController.getInstance(); private final ServerLauncherController controller = ServerLauncherController.getInstance();
@ -134,13 +133,6 @@ public class ServerControlTab implements ActionListener {
springLayout.putConstraint(SpringLayout.EAST, reloadButton, 0, SpringLayout.EAST, opButton); springLayout.putConstraint(SpringLayout.EAST, reloadButton, 0, SpringLayout.EAST, opButton);
controlServers.add(reloadButton); controlServers.add(reloadButton);
reloadButton.addActionListener(this); reloadButton.addActionListener(this);
showConsolesButton = new JButton("View server consoles");
springLayout.putConstraint(SpringLayout.NORTH, showConsolesButton, 0, SpringLayout.NORTH, saveServerButton);
springLayout.putConstraint(SpringLayout.WEST, showConsolesButton, 0, SpringLayout.WEST, lblTargetServer);
springLayout.putConstraint(SpringLayout.EAST, showConsolesButton, 0, SpringLayout.EAST, targetServerCombo);
controlServers.add(showConsolesButton);
showConsolesButton.addActionListener(this);
} }
/** /**
@ -181,9 +173,7 @@ public class ServerControlTab implements ActionListener {
//Registers actions on all commands executed on a specific server //Registers actions on all commands executed on a specific server
handleServerCommands(actionSource, selectedServerValue); handleServerCommands(actionSource, selectedServerValue);
if (actionSource == showConsolesButton) { if (actionSource == targetServerCombo) {
ServerConsoles.setAsVisible();
} else if (actionSource == targetServerCombo) {
updatePlayers(); updatePlayers();
} }
} }

View File

@ -3,12 +3,11 @@ package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import javax.swing.*; import javax.swing.*;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
@ -18,7 +17,6 @@ import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.Executors;
import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE; import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner;
@ -33,25 +31,19 @@ import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getR
*/ */
public class ServerLauncherGUI extends MessageHandler implements ActionListener, GUI { public class ServerLauncherGUI extends MessageHandler implements ActionListener, GUI {
private final JLabel lblStatusLabel = new JLabel("Servers are stopped");
private final ServerLauncherController controller; private final ServerLauncherController controller;
private Map<String, String> textStrings; private Map<String, String> textStrings;
private Tray applicationTray; private Tray applicationTray;
private JFrame frame; private JFrame frame;
private JTabbedPane tabbedPane; private JTabbedPane mainTabbedPane;
private JTabbedPane serversPane; private JTabbedPane serversPane;
private ServerControlTab serverControlTab; private ServerControlTab serverControlTab;
private ControlPanelTab controlPanelTab;
private ServerLauncherMenu serverLauncherMenu; private ServerLauncherMenu serverLauncherMenu;
//Basic controls private JButton addServerTabButton;
private JButton startServerButton; private JButton addServerPaneButton;
private JButton stopServerButton;
private JButton addServerButton;
private JButton backupButton;
private JButton addProfileButton;
private JButton deleteProfileButton;
private JComboBox<String> profiles;
/** /**
* Creates the application window * Creates the application window
@ -99,9 +91,17 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
return this.serversPane; 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 @Override
public void setStatus(String text) { public void setStatus(String text) {
this.lblStatusLabel.setText(text); controlPanelTab.setStatusText(text);
this.logMessage(text); this.logMessage(text);
} }
@ -120,18 +120,6 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
return chooser.getSelectedFile(); return chooser.getSelectedFile();
} }
/**
* Updates the profiles combo
*/
public void updateProfiles() {
String selectedProfile = Main.getController().getCurrentProfile().getName();
this.profiles.removeAllItems();
for (String profile : Main.getController().getProfileNames()) {
this.profiles.addItem(profile);
}
this.profiles.setSelectedItem(selectedProfile);
}
/** /**
* Gets the server control tab used by this GUI * Gets the server control tab used by this GUI
* *
@ -160,7 +148,82 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
serverControlTab.update(); serverControlTab.update();
for (Collection collection : controller.getCurrentProfile().getCollections()) { for (Collection collection : controller.getCurrentProfile().getCollections()) {
serversPane.addTab(collection.getName(), collection.getServerTab().getPanel()); 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));
} }
/** /**
@ -194,93 +257,30 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
this.serverLauncherMenu = new ServerLauncherMenu(menuBar, this); this.serverLauncherMenu = new ServerLauncherMenu(menuBar, this);
tabbedPane = new JTabbedPane(JTabbedPane.TOP); mainTabbedPane = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(tabbedPane); frame.getContentPane().add(mainTabbedPane);
JPanel panelBasic = new JPanel(); JPanel controlPanelPanel = new JPanel();
tabbedPane.addTab("Control panel", null, panelBasic, null); mainTabbedPane.addTab("Control panel", null, controlPanelPanel, null);
SpringLayout sl_panel = new SpringLayout(); controlPanelTab = new ControlPanelTab(controlPanelPanel);
panelBasic.setLayout(sl_panel);
JLabel lblBasicControls = new JLabel("Basic controls"); JPanel controlServersPanel = new JPanel();
sl_panel.putConstraint(SpringLayout.NORTH, lblBasicControls, 10, SpringLayout.NORTH, panelBasic); mainTabbedPane.addTab("Control servers", null, controlServersPanel, null);
panelBasic.add(lblBasicControls); serverControlTab = new ServerControlTab(frame, controlServersPanel);
startServerButton = new JButton("Start servers"); JPanel serversPanel = new JPanel();
sl_panel.putConstraint(SpringLayout.WEST, lblBasicControls, 0, SpringLayout.WEST, startServerButton); mainTabbedPane.addTab("Servers", null, serversPanel, null);
sl_panel.putConstraint(SpringLayout.NORTH, startServerButton, 6, SpringLayout.SOUTH, lblBasicControls); SpringLayout serversPanelSpringLayout = new SpringLayout();
sl_panel.putConstraint(SpringLayout.WEST, startServerButton, 10, SpringLayout.WEST, panelBasic); serversPanel.setLayout(serversPanelSpringLayout);
panelBasic.add(startServerButton);
startServerButton.addActionListener(this);
stopServerButton = new JButton("Stop servers"); serversPane = new JTabbedPane(JTabbedPane.TOP);
sl_panel.putConstraint(SpringLayout.NORTH, stopServerButton, 0, SpringLayout.NORTH, startServerButton); serversPanelSpringLayout.putConstraint(SpringLayout.NORTH, serversPane, 0, SpringLayout.NORTH, serversPanel);
sl_panel.putConstraint(SpringLayout.WEST, stopServerButton, 6, SpringLayout.EAST, startServerButton); serversPanelSpringLayout.putConstraint(SpringLayout.WEST, serversPane, 0, SpringLayout.WEST, serversPanel);
panelBasic.add(stopServerButton); serversPanelSpringLayout.putConstraint(SpringLayout.SOUTH, serversPane, 0, SpringLayout.SOUTH, serversPanel);
stopServerButton.addActionListener(this); serversPanelSpringLayout.putConstraint(SpringLayout.EAST, serversPane, 0, SpringLayout.EAST, serversPanel);
serversPanel.add(serversPane);
JLabel lblProfile = new JLabel("Profile"); serversPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
sl_panel.putConstraint(SpringLayout.NORTH, lblProfile, 6, SpringLayout.SOUTH, startServerButton);
sl_panel.putConstraint(SpringLayout.WEST, lblProfile, 10, SpringLayout.WEST, panelBasic);
panelBasic.add(lblProfile);
addProfileButton = new JButton("+");
sl_panel.putConstraint(SpringLayout.NORTH, addProfileButton, 6, SpringLayout.SOUTH, lblProfile);
sl_panel.putConstraint(SpringLayout.WEST, addProfileButton, 10, SpringLayout.WEST, panelBasic);
panelBasic.add(addProfileButton);
addProfileButton.addActionListener(this);
deleteProfileButton = new JButton("-");
sl_panel.putConstraint(SpringLayout.NORTH, deleteProfileButton, 0, SpringLayout.NORTH, addProfileButton);
sl_panel.putConstraint(SpringLayout.WEST, deleteProfileButton, 6, SpringLayout.EAST, addProfileButton);
panelBasic.add(deleteProfileButton);
deleteProfileButton.addActionListener(this);
profiles = new JComboBox<>();
sl_panel.putConstraint(SpringLayout.NORTH, profiles, 0, SpringLayout.NORTH, addProfileButton);
sl_panel.putConstraint(SpringLayout.WEST, profiles, 6, SpringLayout.EAST, deleteProfileButton);
sl_panel.putConstraint(SpringLayout.EAST, profiles, 124, SpringLayout.EAST, deleteProfileButton);
panelBasic.add(profiles);
profiles.addActionListener(this);
sl_panel.putConstraint(SpringLayout.NORTH, lblStatusLabel, 6, SpringLayout.SOUTH, addProfileButton);
sl_panel.putConstraint(SpringLayout.SOUTH, lblStatusLabel, -10, SpringLayout.SOUTH, panelBasic);
sl_panel.putConstraint(SpringLayout.WEST, lblStatusLabel, 10, SpringLayout.WEST, panelBasic);
sl_panel.putConstraint(SpringLayout.EAST, lblStatusLabel, -10, SpringLayout.EAST, panelBasic);
panelBasic.add(lblStatusLabel);
addServerButton = new JButton("Add server");
sl_panel.putConstraint(SpringLayout.NORTH, addServerButton, 0, SpringLayout.NORTH, startServerButton);
sl_panel.putConstraint(SpringLayout.WEST, addServerButton, 6, SpringLayout.EAST, stopServerButton);
panelBasic.add(addServerButton);
addServerButton.addActionListener(this);
backupButton = new JButton("Backup");
sl_panel.putConstraint(SpringLayout.NORTH, backupButton, 0, SpringLayout.NORTH, startServerButton);
sl_panel.putConstraint(SpringLayout.WEST, backupButton, 6, SpringLayout.EAST, addServerButton);
panelBasic.add(backupButton);
backupButton.addActionListener(this);
JPanel controlServers = new JPanel();
tabbedPane.addTab("Control servers", null, controlServers, null);
serverControlTab = new ServerControlTab(frame, controlServers);
JPanel panel_2 = new JPanel();
tabbedPane.addTab("Servers", null, panel_2, null);
SpringLayout sl_panel_2 = new SpringLayout();
panel_2.setLayout(sl_panel_2);
JTabbedPane tabbedPane_1 = new JTabbedPane(JTabbedPane.TOP);
sl_panel_2.putConstraint(SpringLayout.NORTH, tabbedPane_1, 0, SpringLayout.NORTH, panel_2);
sl_panel_2.putConstraint(SpringLayout.WEST, tabbedPane_1, 0, SpringLayout.WEST, panel_2);
sl_panel_2.putConstraint(SpringLayout.SOUTH, tabbedPane_1, 0, SpringLayout.SOUTH, panel_2);
sl_panel_2.putConstraint(SpringLayout.EAST, tabbedPane_1, 0, SpringLayout.EAST, panel_2);
panel_2.add(tabbedPane_1);
this.serversPane = tabbedPane_1;
tabbedPane_1.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
frame.validate(); frame.validate();
frame.pack(); frame.pack();
@ -296,21 +296,6 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
applicationTray.hideToTray(); applicationTray.hideToTray();
} }
/**
* Gets the currently selected profile
*
* @return <p>The currently selected profile or null</p>
*/
public String getSelectedProfile() {
Object selectedProfile = profiles.getSelectedItem();
if (selectedProfile != null) {
return selectedProfile.toString();
} else {
return null;
}
}
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
Object actionSource = e.getSource(); Object actionSource = e.getSource();
@ -325,34 +310,8 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
* @param actionSource <p>The object being interacted with</p> * @param actionSource <p>The object being interacted with</p>
*/ */
private void handleMainTabButtons(Object actionSource) { private void handleMainTabButtons(Object actionSource) {
if (actionSource == startServerButton) { if (actionSource == addServerTabButton || actionSource == addServerPaneButton) {
controller.saveState();
Executors.newSingleThreadExecutor().execute(ServerHandler::startServers);
} else if (actionSource == stopServerButton) {
stopServers();
} else if (actionSource == addServerButton) {
addServer(); addServer();
} else if (actionSource == backupButton) {
//Run backup in its own thread to prevent locking up
Executors.newSingleThreadExecutor().execute(() -> BackupUtil.backup(this));
} else if (actionSource == addProfileButton) {
controller.addProfile(JOptionPane.showInputDialog("Profile name: "));
updateProfiles();
} else if (actionSource == deleteProfileButton) {
deleteProfile();
} else if (actionSource == profiles) {
changeProfile();
}
}
/**
* Deletes the selected profile
*/
private void deleteProfile() {
Object selected = profiles.getSelectedItem();
if (selected != null) {
controller.removeProfile(selected.toString());
updateProfiles();
} }
} }
@ -377,42 +336,9 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
*/ */
public void updateGUIElementsWhenServersStartOrStop(boolean running) { public void updateGUIElementsWhenServersStartOrStop(boolean running) {
boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running. boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running.
profiles.setEnabled(stopped); mainTabbedPane.setEnabledAt(1, !stopped);
addProfileButton.setEnabled(stopped); mainTabbedPane.setEnabledAt(2, stopped);
deleteProfileButton.setEnabled(stopped); controlPanelTab.updateGUIElementsWhenServersStartOrStop(running);
startServerButton.setEnabled(stopped);
addServerButton.setEnabled(stopped);
tabbedPane.setEnabledAt(2, stopped);
stopServerButton.setEnabled(running);
}
/**
* Saves the previous profile and loads data from the new profile
*/
private void changeProfile() {
controller.saveState();
Object current = this.profiles.getSelectedItem();
if (current != null) {
controller.setCurrentProfile(current.toString());
}
this.updateWithSavedProfileData();
controller.getCurrentProfile().updateConsoles();
}
/**
* Stops all servers
*/
public void stopServers() {
try {
setStatus("Servers are stopping...");
ServerHandler.stop();
} catch (IOException e1) {
showError("Could not stop server.");
e1.printStackTrace();
} catch (InterruptedException e) {
showError("Could not kill server.");
e.printStackTrace();
}
} }
/** /**

View File

@ -237,7 +237,7 @@ public class ServerLauncherMenu implements ActionListener {
* Asks the user for a delay if checked, and sets the value to the current profile * Asks the user for a delay if checked, and sets the value to the current profile
*/ */
private void delay() { private void delay() {
String selectedProfile = serverLauncherGUI.getSelectedProfile(); String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
if (selectedProfile != null) { if (selectedProfile != null) {
Profile profile = controller.getProfileByName(selectedProfile); Profile profile = controller.getProfileByName(selectedProfile);
if (delayStartupCheckBoxMenuItem.isSelected()) { if (delayStartupCheckBoxMenuItem.isSelected()) {
@ -260,7 +260,7 @@ public class ServerLauncherMenu implements ActionListener {
* Saves the runInBackground setting to the current profile * Saves the runInBackground setting to the current profile
*/ */
private void background() { private void background() {
String selectedProfile = serverLauncherGUI.getSelectedProfile(); String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
if (selectedProfile != null) { if (selectedProfile != null) {
Profile profile = controller.getProfileByName(selectedProfile); Profile profile = controller.getProfileByName(selectedProfile);
Objects.requireNonNull(profile).setRunInBackground(runInBackgroundCheckBoxMenuItem.isSelected()); Objects.requireNonNull(profile).setRunInBackground(runInBackgroundCheckBoxMenuItem.isSelected());
@ -273,7 +273,7 @@ public class ServerLauncherMenu implements ActionListener {
* Saves the downloadJars setting to the current profile * Saves the downloadJars setting to the current profile
*/ */
private void downloadJars() { private void downloadJars() {
String selectedProfile = serverLauncherGUI.getSelectedProfile(); String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
if (selectedProfile != null) { if (selectedProfile != null) {
controller.setDownloadAllJars(downloadJarsCheckBoxMenuItem.isSelected()); controller.setDownloadAllJars(downloadJarsCheckBoxMenuItem.isSelected());
} else { } else {

View File

@ -23,11 +23,9 @@ public class ServerTab implements ActionListener {
private final JComboBox<String> serverVersions; private final JComboBox<String> serverVersions;
private final JComboBox<String> maxRam; private final JComboBox<String> maxRam;
private final JCheckBox enabledCheckbox; private final JCheckBox enabledCheckbox;
private final JButton removeServerButton;
private final JButton browseButton; private final JButton browseButton;
private final JTextField directory; private final JTextField directory;
private final JPanel panel; private final JPanel panel;
private final String name;
/** /**
* Initializes a new server tab with the given name * Initializes a new server tab with the given name
@ -36,7 +34,6 @@ public class ServerTab implements ActionListener {
* @throws ConfigurationException <p>If unable to create the new tab</p> * @throws ConfigurationException <p>If unable to create the new tab</p>
*/ */
public ServerTab(String name) throws ConfigurationException { public ServerTab(String name) throws ConfigurationException {
this.name = name;
panel = new JPanel(); panel = new JPanel();
Main.getController().getGUI().getPane().addTab(name, null, panel, null); Main.getController().getGUI().getPane().addTab(name, null, panel, null);
SpringLayout sl_panel_3 = new SpringLayout(); SpringLayout sl_panel_3 = new SpringLayout();
@ -88,14 +85,6 @@ public class ServerTab implements ActionListener {
panel.add(enabledCheckbox); panel.add(enabledCheckbox);
enabledCheckbox.addActionListener(this); enabledCheckbox.addActionListener(this);
removeServerButton = new JButton("Remove server");
sl_panel_3.putConstraint(SpringLayout.NORTH, removeServerButton, 0, SpringLayout.NORTH, serverVersions);
sl_panel_3.putConstraint(SpringLayout.SOUTH, removeServerButton, 0, SpringLayout.SOUTH, serverVersions);
sl_panel_3.putConstraint(SpringLayout.WEST, removeServerButton, 6, SpringLayout.EAST, serverVersions);
sl_panel_3.putConstraint(SpringLayout.EAST, removeServerButton, -10, SpringLayout.EAST, panel);
panel.add(removeServerButton);
removeServerButton.addActionListener(this);
JLabel lblDirectory = new JLabel("Directory"); JLabel lblDirectory = new JLabel("Directory");
sl_panel_3.putConstraint(SpringLayout.WEST, lblDirectory, 6, SpringLayout.EAST, enabledCheckbox); sl_panel_3.putConstraint(SpringLayout.WEST, lblDirectory, 6, SpringLayout.EAST, enabledCheckbox);
panel.add(lblDirectory); panel.add(lblDirectory);
@ -112,7 +101,7 @@ public class ServerTab implements ActionListener {
browseButton = new JButton("Browse"); browseButton = new JButton("Browse");
sl_panel_3.putConstraint(SpringLayout.EAST, directory, -6, SpringLayout.WEST, browseButton); sl_panel_3.putConstraint(SpringLayout.EAST, directory, -6, SpringLayout.WEST, browseButton);
sl_panel_3.putConstraint(SpringLayout.NORTH, browseButton, 3, SpringLayout.SOUTH, removeServerButton); sl_panel_3.putConstraint(SpringLayout.NORTH, browseButton, 3, SpringLayout.SOUTH, serverVersions);
sl_panel_3.putConstraint(SpringLayout.EAST, browseButton, -10, SpringLayout.EAST, panel); sl_panel_3.putConstraint(SpringLayout.EAST, browseButton, -10, SpringLayout.EAST, panel);
sl_panel_3.putConstraint(SpringLayout.SOUTH, directory, 0, SpringLayout.SOUTH, browseButton); sl_panel_3.putConstraint(SpringLayout.SOUTH, directory, 0, SpringLayout.SOUTH, browseButton);
sl_panel_3.putConstraint(SpringLayout.NORTH, directory, 0, SpringLayout.NORTH, browseButton); sl_panel_3.putConstraint(SpringLayout.NORTH, directory, 0, SpringLayout.NORTH, browseButton);
@ -209,9 +198,7 @@ public class ServerTab implements ActionListener {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (e.getSource() == removeServerButton) { if (e.getSource() == browseButton) {
remove();
} else if (e.getSource() == browseButton) {
browse(); browse();
} else if (e.getSource() == serverTypes) { } else if (e.getSource() == serverTypes) {
try { try {
@ -222,15 +209,6 @@ public class ServerTab implements ActionListener {
} }
} }
/**
* Removes the collection containing this ServerTab, and updates everything necessary
*/
private void remove() {
Main.getController().getCurrentProfile().removeCollection(this.name);
Main.getController().getGUI().updateWithSavedProfileData();
Main.getController().getCurrentProfile().updateConsoles();
}
/** /**
* Asks the user for server location and updates the GUI if given a valid value * Asks the user for server location and updates the GUI if given a valid value
*/ */

View File

@ -0,0 +1,61 @@
package net.knarcraft.minecraftserverlauncher.userinterface;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.MouseEvent;
/**
* A listener for detecting the dragging of a tab to make it dock or undock
*/
public class TabDragListener extends MouseInputAdapter {
Point dragStartPoint;
Component draggedComponent;
String draggedTabTitle;
JDockableTabbedPane tabbedPaneToListenTo;
public TabDragListener(JDockableTabbedPane tabbedPaneToListenTo) {
this.tabbedPaneToListenTo = tabbedPaneToListenTo;
}
@Override
public void mousePressed(MouseEvent e) {
dragStartPoint = e.getPoint();
//Loop through tabbed panes to find the dragged one
for (int i = 0; i < tabbedPaneToListenTo.getTabCount(); i++) {
Rectangle bounds = tabbedPaneToListenTo.getBoundsAt(i);
if (bounds.contains(dragStartPoint)) {
draggedComponent = tabbedPaneToListenTo.getComponentAt(i);
draggedTabTitle = tabbedPaneToListenTo.getTitleAt(i);
break;
}
}
}
@Override
public void mouseDragged(MouseEvent e) {
Point dragEndPoint = e.getPoint();
if (draggedComponent != null) {
// check for a significant drag
//TODO: Check if tab is dragged onto another JDockableTabbedPane with the same id
if (Math.abs(dragEndPoint.getY() - dragStartPoint.getY()) > 30) {
//TODO: Undock by creating a new JDockableTabbedPane with the same id
//TODO: If dragging onto another JDockableTabbedPane with the same id, combine
//TODO: Make the listener keep track of all its created windows
//TODO: If a child window is closed, dock its tab to the main window
//TODO: Keep track of the original window vs. the child window
//undock(draggedComponent, draggedTabTitle);
draggedComponent = null;
}
}
}
@Override
public void mouseReleased(MouseEvent arg0) {
draggedComponent = null;
draggedTabTitle = null;
}
}

View File

@ -59,7 +59,7 @@ public class Tray {
trayIcon = new TrayIcon(trayImage, "Minecraft Server Launcher", popup); trayIcon = new TrayIcon(trayImage, "Minecraft Server Launcher", popup);
trayIcon.setImageAutoSize(true); trayIcon.setImageAutoSize(true);
ActionListener exitListener = e -> { ActionListener exitListener = e -> {
serverLauncherGUI.stopServers(); serverLauncherGUI.getControlPanelTab().stopServers();
controller.saveState(); controller.saveState();
System.exit(0); System.exit(0);
}; };
@ -92,7 +92,7 @@ public class Tray {
e1.printStackTrace(); e1.printStackTrace();
} }
} else { } else {
serverLauncherGUI.stopServers(); serverLauncherGUI.getControlPanelTab().stopServers();
controller.saveState(); controller.saveState();
System.exit(0); System.exit(0);
} }
@ -114,7 +114,7 @@ public class Tray {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
controller.saveState(); controller.saveState();
serverLauncherGUI.stopServers(); serverLauncherGUI.getControlPanelTab().stopServers();
System.exit(0); System.exit(0);
} }
}); });