diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildTools.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildTools.java deleted file mode 100644 index b67307c..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildTools.java +++ /dev/null @@ -1,462 +0,0 @@ -/* - * SK's Minecraft Launcher - * Copyright (C) 2010-2014 Albert Pham and contributors - * Please see LICENSE.txt for license information. - */ - -package com.skcraft.launcher.buildtools; - -import com.beust.jcommander.JCommander; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter.Lf2SpacesIndenter; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.skcraft.concurrency.ObservableFuture; -import com.skcraft.launcher.Instance; -import com.skcraft.launcher.InstanceList; -import com.skcraft.launcher.Launcher; -import com.skcraft.launcher.auth.OfflineSession; -import com.skcraft.launcher.auth.Session; -import com.skcraft.launcher.builder.BuilderConfig; -import com.skcraft.launcher.builder.BuilderOptions; -import com.skcraft.launcher.builder.FnPatternList; -import com.skcraft.launcher.buildtools.compile.*; -import com.skcraft.launcher.buildtools.compile.BuildDialog.BuildOptions; -import com.skcraft.launcher.buildtools.project.BuilderConfigDialog; -import com.skcraft.launcher.buildtools.http.LocalHttpServerBuilder; -import com.skcraft.launcher.buildtools.compile.DeployServerDialog.DeployOptions; -import com.skcraft.launcher.dialog.ConfigurationDialog; -import com.skcraft.launcher.dialog.ConsoleFrame; -import com.skcraft.launcher.dialog.ProgressDialog; -import com.skcraft.launcher.launch.LaunchOptions; -import com.skcraft.launcher.launch.LaunchOptions.UpdatePolicy; -import com.skcraft.launcher.model.modpack.LaunchModifier; -import com.skcraft.launcher.persistence.Persistence; -import com.skcraft.launcher.swing.SwingHelper; -import lombok.Getter; -import lombok.extern.java.Log; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import java.util.regex.Pattern; - -@Log -public class BuildTools { - - private static final DateFormat VERSION_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); - private static final Pattern FILENAME_SANITIZE = Pattern.compile("[^a-z0-9_\\-\\.]+"); - private static final DefaultPrettyPrinter lf2ListPrettyPrinter; - - private final Launcher launcher; - @Getter - private int port; - @Getter - private final File inputDir; - @Getter - private final File srcDir; - @Getter - private final File wwwDir; - @Getter - private final File distDir; - - static { - lf2ListPrettyPrinter = new DefaultPrettyPrinter(); - lf2ListPrettyPrinter.indentArraysWith(Lf2SpacesIndenter.instance); - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - public BuildTools(File baseDir, int port) throws IOException { - File launcherDir = new File(baseDir, "staging/launcher"); - inputDir = baseDir; - srcDir = new File(baseDir, BuilderOptions.DEFAULT_SRC_DIRNAME); - wwwDir = new File(baseDir, "staging/www"); - distDir = new File(baseDir, "upload"); - - this.port = port; - - srcDir.mkdirs(); - new File(baseDir, BuilderOptions.DEFAULT_LOADERS_DIRNAME).mkdir(); - launcherDir.mkdirs(); - wwwDir.mkdirs(); - - launcher = new Launcher(launcherDir); - setPort(port); - } - - private void setPort(int port) { - this.port = port; - launcher.getProperties().setProperty("newsUrl", "http://localhost:" + port + "/news.html"); - launcher.getProperties().setProperty("packageListUrl", "http://localhost:" + port + "/packages.json"); - launcher.getProperties().setProperty("selfUpdateUrl", "http://localhost:" + port + "/latest.json"); - } - - public File getConfigFile() { - return new File(inputDir, BuilderOptions.DEFAULT_CONFIG_FILENAME); - } - - public String generateManifestName() { - File file = getConfigFile(); - if (file.exists()) { - BuilderConfig config = Persistence.read(file, BuilderConfig.class, true); - if (config != null) { - String name = Strings.nullToEmpty(config.getName()); - name = name.toLowerCase(); - name = FILENAME_SANITIZE.matcher(name).replaceAll("-"); - name = name.trim(); - if (!name.isEmpty()) { - return name + ".json"; - } - } - } - - return "my_modpack.json"; - } - - public String getCurrentModpackName() { - File file = getConfigFile(); - if (file.exists()) { - BuilderConfig config = Persistence.read(file, BuilderConfig.class, true); - if (config != null) { - return config.getName(); - } - } - - return null; - } - - public Instance findCurrentInstance(List instances) { - String expected = getCurrentModpackName(); - - for (Instance instance : instances) { - if (instance.getName().equals(expected)) { - return instance; - } - } - - return null; - } - - private void addDefaultConfig(BuilderConfig config) { - config.setName("My Modpack"); - config.setTitle("My Modpack"); - config.setGameVersion("1.8"); - - LaunchModifier launchModifier = new LaunchModifier(); - launchModifier.setFlags(ImmutableList.of("-Dfml.ignoreInvalidMinecraftCertificates=true")); - config.setLaunchModifier(launchModifier); - - FnPatternList userFiles = new FnPatternList(); - userFiles.setInclude(Lists.newArrayList("options.txt", "optionsshaders.txt", "mods/VoxelMods/*")); - userFiles.setExclude(Lists.newArrayList()); - config.setUserFiles(userFiles); - } - - public Server startHttpServer() throws Exception { - LocalHttpServerBuilder builder = new LocalHttpServerBuilder(); - builder.setBaseDir(wwwDir); - builder.setPort(port); - - Server server = builder.build(); - server.start(); - setPort(((ServerConnector) server.getConnectors()[0]).getLocalPort()); - return server; - } - - private void showMainWindow() { - final ToolsFrame frame = new ToolsFrame(); - - frame.getEditConfigButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - File file = getConfigFile(); - boolean existed = file.exists(); - - BuilderConfig config = Persistence.read(file, BuilderConfig.class); - if (!existed) { - addDefaultConfig(config); - } - - if (BuilderConfigDialog.showEditor(frame, config)) { - try { - Persistence.write(file, config, lf2ListPrettyPrinter); - } catch (IOException e) { - SwingHelper.showErrorDialog(frame, "Couldn't write modpack.json to disk due to an error", "Write Error", e); - } - } - } - }); - - frame.getOpenFolderButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - SwingHelper.browseDir(getInputDir(), frame); - } - }); - - frame.getCheckProblemsButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ProblemChecker runnable = new ProblemChecker(BuildTools.this); - ObservableFuture> future = new ObservableFuture>(launcher.getExecutor().submit(runnable), runnable); - ProgressDialog.showProgress(frame, future, "Checking for problems...", "Checking for problems..."); - - Futures.addCallback(future, new FutureCallback>() { - @Override - public void onSuccess(List problems) { - if (problems.isEmpty()) { - SwingHelper.showMessageDialog(frame, "No potential problems found!", "Success", null, JOptionPane.INFORMATION_MESSAGE); - } else { - ProblemViewer viewer = new ProblemViewer(frame, problems); - viewer.setVisible(true); - } - } - - @Override - public void onFailure(Throwable t) { - } - }); - - SwingHelper.addErrorDialogCallback(frame, future); - } - }); - - frame.getBuildButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - final BuildOptions options = BuildDialog.showBuildDialog(frame, generateVersionFromDate(), generateManifestName(), distDir); - if (options != null) { - ConsoleFrame.showMessages(); - - options.getDestDir().mkdirs(); - ModpackBuilder runnable = new ModpackBuilder(inputDir, options.getDestDir(), options.getVersion(), options.getManifestFilename(), options.isClean()); - ObservableFuture future = new ObservableFuture(launcher.getExecutor().submit(runnable), runnable); - ProgressDialog.showProgress(frame, future, "Building modpack...", "Building modpack for release..."); - - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(ModpackBuilder result) { - SwingHelper.browseDir(options.getDestDir(), frame); - } - - @Override - public void onFailure(Throwable t) { - } - }); - - SwingHelper.addErrorDialogCallback(frame, future); - } - } - }); - - frame.getDeployServerButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - final DeployOptions options = DeployServerDialog.showDeployDialog(frame); - if (options != null) { - ConsoleFrame.showMessages(); - - distDir.mkdirs(); - ServerDeployer runnable = new ServerDeployer(srcDir, options); - ObservableFuture future = new ObservableFuture(launcher.getExecutor().submit(runnable), runnable); - ProgressDialog.showProgress(frame, future, "Deploying files...", "Deploying server files..."); - - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(ServerDeployer result) { - SwingHelper.showMessageDialog(frame, "Server deployment complete!", "Success", null, JOptionPane.INFORMATION_MESSAGE); - } - - @Override - public void onFailure(Throwable t) { - } - }); - - SwingHelper.addErrorDialogCallback(frame, future); - } - } - }); - - frame.getTestButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ConsoleFrame.showMessages(); - - ModpackBuilder runnable = new ModpackBuilder(inputDir, wwwDir, generateVersionFromDate(), "staging.json", false); - ObservableFuture future = new ObservableFuture(launcher.getExecutor().submit(runnable), runnable); - ProgressDialog.showProgress(frame, future, "Preparing files...", "Preparing files for launch..."); - SwingHelper.addErrorDialogCallback(frame, future); - - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(ModpackBuilder result) { - launchInstance(frame); - ConsoleFrame.hideMessages(); - } - - @Override - public void onFailure(Throwable t) { - } - }); - } - }); - - frame.getOptionsButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ConfigurationDialog configDialog = new ConfigurationDialog(frame, launcher); - configDialog.setVisible(true); - } - }); - - frame.getClearInstanceButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - DirectoryRemover remover = new DirectoryRemover(launcher.getInstancesDir()); - ObservableFuture future = new ObservableFuture(launcher.getExecutor().submit(remover), remover); - ProgressDialog.showProgress(frame, future, "Removing files...", "Removing files..."); - SwingHelper.addErrorDialogCallback(frame, future); - } - }); - - frame.getClearWebRootButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - DirectoryRemover remover = new DirectoryRemover(wwwDir); - ObservableFuture future = new ObservableFuture(launcher.getExecutor().submit(remover), remover); - ProgressDialog.showProgress(frame, future, "Removing files...", "Removing files..."); - SwingHelper.addErrorDialogCallback(frame, future); - } - }); - - frame.getOpenConsoleButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ConsoleFrame.showMessages(); - } - }); - - frame.getDocsButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - SwingHelper.openURL("https://github.com/SKCraft/Launcher/wiki", frame); - } - }); - - frame.getQuitButton().addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - frame.dispose(); - System.exit(0); - } - }); - - frame.setVisible(true); - } - - private void launchInstance(final Window window) { - final InstanceList instanceList = launcher.getInstances(); - InstanceList.Enumerator loader = instanceList.createEnumerator(); - ObservableFuture future = new ObservableFuture(launcher.getExecutor().submit(loader), loader); - ProgressDialog.showProgress(window, future, "Loading modpacks...", "Loading modpacks..."); - SwingHelper.addErrorDialogCallback(window, future); - - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(InstanceList result) { - Session session = new OfflineSession("Player"); - - Instance instance = findCurrentInstance(instanceList.getInstances()); - - if (instance != null) { - LaunchOptions options = new LaunchOptions.Builder() - .setInstance(instance) - .setUpdatePolicy(UpdatePolicy.ALWAYS_UPDATE) - .setWindow(window) - .setSession(session) - .build(); - - launcher.getLaunchSupervisor().launch(options); - } else { - SwingHelper.showErrorDialog(window, - "After generating the necessary files, it appears the modpack can't be found in the " + - "launcher. Did you change modpack.json while the launcher was launching?", "Launch Error"); - } - } - - @Override - public void onFailure(Throwable t) { - } - }); - } - - public static void main(String[] args) throws Exception { - Launcher.setupLogger(); - System.setProperty("skcraftLauncher.killWithoutConfirm", "true"); - - ToolArguments options = new ToolArguments(); - new JCommander(options, args); - - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - UIManager.getDefaults().put("SplitPane.border", BorderFactory.createEmptyBorder()); - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception ignored) { - } - } - }); - - File inputDir = new ProjectDirectoryChooser(options.getDir()).choose(); - - if (inputDir == null) { - System.exit(100); - return; - } - - final BuildTools main = new BuildTools(inputDir, options.getPort()); - - try { - main.startHttpServer(); - } catch (Throwable t) { - log.log(Level.WARNING, "Web server start failure", t); - SwingHelper.showErrorDialog(null, "Couldn't start the local web server on a free TCP port! " + - "The web server is required to temporarily host the modpack files for the launcher.", "Build Tools Error", t); - System.exit(1); - return; - } - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - main.showMainWindow(); - } catch (Throwable t) { - log.log(Level.WARNING, "Load failure", t); - SwingHelper.showErrorDialog(null, "Failed to launch build tools!", "Build Tools Error", t); - } - } - }); - } - - public static String generateVersionFromDate() { - Date today = Calendar.getInstance().getTime(); - return VERSION_DATE_FORMAT.format(today); - } - -} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ProjectDirectoryChooser.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/ProjectDirectoryChooser.java deleted file mode 100644 index f5c9a90..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ProjectDirectoryChooser.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SK's Minecraft Launcher - * Copyright (C) 2010-2014 Albert Pham and contributors - * Please see LICENSE.txt for license information. - */ - -package com.skcraft.launcher.buildtools; - -import com.skcraft.launcher.builder.BuilderOptions; -import lombok.Getter; - -import javax.swing.*; -import java.io.File; -import java.lang.reflect.InvocationTargetException; - -class ProjectDirectoryChooser { - - @Getter - private File inputDir; - - public ProjectDirectoryChooser(File inputDir) { - this.inputDir = inputDir; - } - - public File choose() throws InvocationTargetException, InterruptedException { - final File currentDir = new File("."); - - if (inputDir == null) { - if (new File(currentDir, BuilderOptions.DEFAULT_CONFIG_FILENAME).exists()) { - inputDir = currentDir; - } else { - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - inputDir = ProjectDirectoryDialog.showDirectoryDialog(null, currentDir); - } - }); - } - } - - return inputDir; - } - -} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ProjectDirectoryDialog.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/ProjectDirectoryDialog.java deleted file mode 100644 index 87e2493..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ProjectDirectoryDialog.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SK's Minecraft Launcher - * Copyright (C) 2010-2014 Albert Pham and contributors - * Please see LICENSE.txt for license information. - */ - -package com.skcraft.launcher.buildtools; - -import com.skcraft.launcher.swing.DirectoryField; -import com.skcraft.launcher.swing.SwingHelper; -import net.miginfocom.swing.MigLayout; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; - -public class ProjectDirectoryDialog extends JDialog { - - private final DirectoryField directoryField = new DirectoryField(); - private File projectDir; - - public ProjectDirectoryDialog(Window parent) { - super(parent, "Select Modpack Directory", ModalityType.DOCUMENT_MODAL); - - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - initComponents(); - setResizable(false); - pack(); - setLocationRelativeTo(parent); - } - - private void initComponents() { - JPanel container = new JPanel(); - container.setLayout(new MigLayout("insets dialog")); - - container.add(new JLabel("Please select the project directory."), "wrap"); - container.add(directoryField, "span"); - - JButton openButton = new JButton("Open"); - JButton cancelButton = new JButton("Cancel"); - - container.add(openButton, "tag ok, span, split 2, sizegroup bttn, gaptop unrel"); - container.add(cancelButton, "tag cancel, sizegroup bttn"); - - add(container, BorderLayout.CENTER); - - openButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - String path = directoryField.getPath(); - if (path.isEmpty()) { - SwingHelper.showErrorDialog(ProjectDirectoryDialog.this, "Please select a directory.", "No Directory"); - return; - } - - projectDir = new File(path); - dispose(); - } - }); - - cancelButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }); - } - - public static File showDirectoryDialog(Window parent, File initialDir) { - ProjectDirectoryDialog dialog = new ProjectDirectoryDialog(parent); - dialog.directoryField.setPath(initialDir.getAbsolutePath()); - dialog.setVisible(true); - return dialog.projectDir; - } - -} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolArguments.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolArguments.java deleted file mode 100644 index 29adc35..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolArguments.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SK's Minecraft Launcher - * Copyright (C) 2010-2014 Albert Pham and contributors - * Please see LICENSE.txt for license information. - */ - -package com.skcraft.launcher.buildtools; - -import com.beust.jcommander.Parameter; -import lombok.Data; - -import java.io.File; - -@Data -class ToolArguments { - - @Parameter(names = "--dir") - private File dir; - - @Parameter(names = "--port") - private int port = 0; - -} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolsFrame.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolsFrame.java deleted file mode 100644 index c7ffd25..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolsFrame.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * SK's Minecraft Launcher - * Copyright (C) 2010-2014 Albert Pham and contributors - * Please see LICENSE.txt for license information. - */ - -package com.skcraft.launcher.buildtools; - -import com.skcraft.launcher.swing.SwingHelper; -import lombok.Data; -import lombok.extern.java.Log; -import net.miginfocom.swing.MigLayout; - -import javax.swing.*; -import java.awt.*; -import java.awt.image.BufferedImage; - -@Log -@Data -public class ToolsFrame extends JFrame { - - private final JButton editConfigButton = new JButton("Edit modpack.json", SwingHelper.readImageIcon(ToolsFrame.class, "edit.png")); - private final JButton openFolderButton = new JButton("Open Modpack Files", SwingHelper.readImageIcon(ToolsFrame.class, "open_folder.png")); - private final JButton checkProblemsButton = new JButton("Check for Potential Problems", SwingHelper.readImageIcon(ToolsFrame.class, "check.png")); - private final JButton testButton = new JButton("Run Modpack", SwingHelper.readImageIcon(ToolsFrame.class, "test.png")); - private final JButton buildButton = new JButton("Build Client Modpack", SwingHelper.readImageIcon(ToolsFrame.class, "build.png")); - private final JButton deployServerButton = new JButton("Copy Server Mods to Folder", SwingHelper.readImageIcon(ToolsFrame.class, "server.png")); - private final JButton optionsButton = new JButton("Test Launcher Options", SwingHelper.readImageIcon(ToolsFrame.class, "options.png")); - private final JButton clearInstanceButton = new JButton("Delete Instance from Test Launcher", SwingHelper.readImageIcon(ToolsFrame.class, "clean.png")); - private final JButton clearWebRootButton = new JButton("Delete Generated Modpack Files", SwingHelper.readImageIcon(ToolsFrame.class, "clean.png")); - private final JButton openConsoleButton = new JButton("Console"); - private final JButton docsButton = new JButton("Help"); - private final JButton quitButton = new JButton("Quit"); - - public ToolsFrame() { - super("Modpack Build Tools"); - - setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - initComponents(); - pack(); - setLocationRelativeTo(null); - - SwingHelper.setIconImage(this, ToolsFrame.class, "icon.png"); - } - - private void initComponents() { - JPanel container = new JPanel(); - container.setLayout(new MigLayout("fill, insets dialog, wrap 1")); - - BufferedImage header = SwingHelper.readIconImage(ToolsFrame.class, "header.png"); - if (header != null) { - add(new JLabel(new ImageIcon(header)), BorderLayout.NORTH); - } - - JTabbedPane tabbedPane = new JTabbedPane(); - tabbedPane.addTab("Create", null, createProjectPanel()); - tabbedPane.addTab("Test", null, createTestPanel()); - tabbedPane.addTab("Release", null, createReleasePanel()); - container.add(tabbedPane, "grow, gapbottom 20"); - - container.add(docsButton, "span, split 3, sizegroup bttn"); - container.add(openConsoleButton, "sizegroup bttn"); - container.add(quitButton, "tag ok, sizegroup bttn"); - - add(container, BorderLayout.CENTER); - } - - private JPanel createProjectPanel() { - JPanel container = new JPanel(); - SwingHelper.removeOpaqueness(container); - container.setLayout(new MigLayout("fillx, insets dialog, wrap 1", "", "")); - - container.add(editConfigButton, "grow, tag ok"); - container.add(openFolderButton, "grow, tag ok"); - container.add(checkProblemsButton, "grow, tag ok"); - - return container; - } - - private JPanel createTestPanel() { - JPanel container = new JPanel(); - SwingHelper.removeOpaqueness(container); - container.setLayout(new MigLayout("fillx, insets dialog, wrap 1", "", "")); - - container.add(testButton, "grow, tag ok"); - container.add(optionsButton, "grow, tag ok"); - container.add(clearInstanceButton, "grow, tag ok"); - container.add(clearWebRootButton, "grow, tag ok"); - - return container; - } - - private JPanel createReleasePanel() { - JPanel container = new JPanel(); - SwingHelper.removeOpaqueness(container); - container.setLayout(new MigLayout("fillx, insets dialog, wrap 1", "", "")); - - container.add(buildButton, "grow, tag ok"); - container.add(deployServerButton, "grow, tag ok"); - - return container; - } - -} diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/header.png b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/header.png deleted file mode 100644 index f58b1a0..0000000 Binary files a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/header.png and /dev/null differ diff --git a/build-tools/build.gradle b/creator-tools/build.gradle similarity index 51% rename from build-tools/build.gradle rename to creator-tools/build.gradle index 4259bbc..719fe44 100644 --- a/build-tools/build.gradle +++ b/creator-tools/build.gradle @@ -1,13 +1,25 @@ apply plugin: 'com.github.johnrengelman.shadow' +version = "2.0" +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + dependencies { compile project(':launcher-builder') compile 'org.eclipse.jetty:jetty-server:9.3.1.v20150714' } +processResources { + filesMatching('**/*.properties') { + filter { + it.replace('${project.version}', project.version) + } + } +} + jar { manifest { - attributes("Main-Class": "com.skcraft.launcher.buildtools.BuildTools") + attributes("Main-Class": "com.skcraft.launcher.creator.Creator") } } diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/Creator.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/Creator.java new file mode 100644 index 0000000..b37af60 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/Creator.java @@ -0,0 +1,84 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator; + +import com.skcraft.launcher.Launcher; +import com.skcraft.launcher.creator.controller.WelcomeController; +import com.skcraft.launcher.creator.dialog.WelcomeDialog; +import com.skcraft.launcher.creator.model.creator.CreatorConfig; +import com.skcraft.launcher.creator.model.creator.RecentEntry; +import com.skcraft.launcher.creator.model.creator.Workspace; +import com.skcraft.launcher.persistence.Persistence; +import com.skcraft.launcher.swing.SwingHelper; +import lombok.Getter; + +import javax.swing.*; +import javax.swing.filechooser.FileSystemView; +import java.io.File; +import java.util.Iterator; +import java.util.List; + +public class Creator { + + @Getter private final File dataDir; + @Getter private final CreatorConfig config; + + public Creator() { + this.dataDir = getAppDataDir(); + this.config = Persistence.load(new File(dataDir, "config.json"), CreatorConfig.class); + + // Remove deleted workspaces + List recentEntries = config.getRecentEntries(); + Iterator it = recentEntries.iterator(); + while (it.hasNext()) { + RecentEntry workspace = it.next(); + if (!Workspace.getWorkspaceFile(workspace.getPath()).exists()) { + it.remove(); + } + } + } + + public void showWelcome() { + WelcomeDialog dialog = new WelcomeDialog(); + WelcomeController controller = new WelcomeController(dialog, this); + controller.show(); + } + + private static File getFileChooseDefaultDir() { + JFileChooser chooser = new JFileChooser(); + FileSystemView fsv = chooser.getFileSystemView(); + return fsv.getDefaultDirectory(); + } + + private static File getAppDataDir() { + String osName = System.getProperty("os.name").toLowerCase(); + if (osName.contains("win")) { + return new File(getFileChooseDefaultDir(), "SKCraft Modpack Creator"); + } else { + return new File(System.getProperty("user.home"), ".skcraftcreator"); + } + } + + public static void main(String[] args) throws Exception { + Launcher.setupLogger(); + System.setProperty("skcraftLauncher.killWithoutConfirm", "true"); + + final Creator creator = new Creator(); + + SwingUtilities.invokeAndWait(() -> { + UIManager.getDefaults().put("SplitPane.border", BorderFactory.createEmptyBorder()); + SwingHelper.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + + try { + creator.showWelcome(); + } catch (Exception e) { + SwingHelper.showErrorDialog(null, "Failed to start the modpack creator program.", "Start Error", e); + } + }); + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/GenerateListingController.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/GenerateListingController.java new file mode 100644 index 0000000..688cad8 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/GenerateListingController.java @@ -0,0 +1,218 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.controller; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import com.google.common.io.Files; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.skcraft.concurrency.Deferred; +import com.skcraft.concurrency.Deferreds; +import com.skcraft.concurrency.SettableProgress; +import com.skcraft.launcher.creator.dialog.GenerateListingDialog; +import com.skcraft.launcher.creator.dialog.ManifestEntryDialog; +import com.skcraft.launcher.creator.model.creator.ManifestEntry; +import com.skcraft.launcher.creator.model.creator.Workspace; +import com.skcraft.launcher.creator.model.swing.ListingType; +import com.skcraft.launcher.creator.model.swing.ManifestEntryTableModel; +import com.skcraft.launcher.dialog.ProgressDialog; +import com.skcraft.launcher.persistence.Persistence; +import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.util.SwingExecutor; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; +import java.util.stream.Collectors; + +public class GenerateListingController { + + private final GenerateListingDialog dialog; + private final Workspace workspace; + private final List manifestEntries; + private final ListeningExecutorService executor; + private final ManifestEntryTableModel manifestTableModel; + + public GenerateListingController(GenerateListingDialog dialog, Workspace workspace, List manifestEntries, ListeningExecutorService executor) { + this.dialog = dialog; + this.workspace = workspace; + this.manifestEntries = manifestEntries; + this.executor = executor; + + this.manifestTableModel = new ManifestEntryTableModel(manifestEntries); + dialog.getManifestsTable().setModel(manifestTableModel); + dialog.getManifestsTableAdjuster().adjustColumns(); + + initListeners(); + + setListingType(workspace.getPackageListingType()); + } + + public void setOutputDir(File dir) { + dialog.getDestDirField().setPath(dir.getAbsolutePath()); + } + + public void setListingType(ListingType type) { + dialog.getListingTypeCombo().setSelectedItem(type); + } + + public void show() { + dialog.setVisible(true); + } + + public Optional getManifestFromIndex(int selectedIndex) { + if (selectedIndex >= 0) { + ManifestEntry manifest = manifestEntries.get(selectedIndex); + if (manifest != null) { + return Optional.fromNullable(manifest); + } + } + return Optional.absent(); + } + + public Optional getSelectedManifest() { + JTable table = dialog.getManifestsTable(); + int selectedIndex = table.getSelectedRow(); + if (selectedIndex >= 0) { + selectedIndex = table.convertRowIndexToModel(selectedIndex); + ManifestEntry manifest = manifestEntries.get(selectedIndex); + if (manifest != null) { + return Optional.fromNullable(manifest); + } + } + + SwingHelper.showErrorDialog(dialog, "Please select a modpack from the list.", "Error"); + return Optional.absent(); + } + + private void updateManifestEntryInTable(ManifestEntry manifestEntry) { + int index = manifestEntries.indexOf(manifestEntry); + if (index >= 0) { + manifestTableModel.fireTableRowsUpdated(index, index); + } + } + + private void initListeners() { + dialog.getManifestsTable().addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + if (e.getClickCount() == 2) { + JTable table = (JTable) e.getSource(); + Point point = e.getPoint(); + int selectedIndex = table.rowAtPoint(point); + if (selectedIndex >= 0) { + selectedIndex = table.convertRowIndexToModel(selectedIndex); + Optional optional = getManifestFromIndex(selectedIndex); + if (optional.isPresent()) { + if (showModifyDialog(optional.get())) { + updateManifestEntryInTable(optional.get()); + } + } + } + } + } + }); + + dialog.getListingTypeCombo().addItemListener(e -> { + ListingType type = (ListingType) e.getItem(); + dialog.getGameKeyWarning().setVisible(!type.isGameKeyCompatible()); + }); + + dialog.getEditManifestButton().addActionListener(e -> { + Optional optional = getSelectedManifest(); + if (optional.isPresent()) { + if (showModifyDialog(optional.get())) { + updateManifestEntryInTable(optional.get()); + } + } + }); + + dialog.getGenerateButton().addActionListener(e -> tryGenerate()); + + dialog.getCancelButton().addActionListener(e -> dialog.dispose()); + } + + private boolean showModifyDialog(ManifestEntry manifestEntry) { + ManifestEntryDialog modifyDialog = new ManifestEntryDialog(dialog); + modifyDialog.setTitle("Modify " + manifestEntry.getManifestInfo().getLocation()); + ManifestEntryController controller = new ManifestEntryController(modifyDialog, manifestEntry); + return controller.show(); + } + + private boolean tryGenerate() { + String path = dialog.getDestDirField().getPath().trim(); + + if (path.isEmpty()) { + SwingHelper.showErrorDialog(dialog, "A directory must be entered.", "Error"); + return false; + } + + List selected = manifestEntries.stream() + .filter(ManifestEntry::isSelected) + .sorted() + .collect(Collectors.toCollection(Lists::newArrayList)); + + if (selected.isEmpty()) { + SwingHelper.showErrorDialog(dialog, "At least one modpack must be selected to appear in the package list.", "Error"); + return false; + } + + ListingType listingType = (ListingType) dialog.getListingTypeCombo().getSelectedItem(); + File destDir = new File(path); + destDir.mkdirs(); + File file = new File(destDir, listingType.getFilename()); + + workspace.setPackageListingEntries(selected); + workspace.setPackageListingType(listingType); + Persistence.commitAndForget(workspace); + + SettableProgress progress = new SettableProgress("Generating package listing...", -1); + + Deferred deferred = Deferreds.makeDeferred(executor.submit(() -> listingType.generate(selected))) + .thenTap(() -> progress.set("Deleting older package listing files...", -1)) + .thenApply(input -> { + for (ListingType otherListingType : ListingType.values()) { + File f = new File(destDir, otherListingType.getFilename()); + if (f.exists()) { + f.delete(); + } + } + + return input; + }) + .thenTap(() -> progress.set("Writing package listing to disk...", -1)) + .thenApply(input -> { + try { + Files.write(input, file, Charset.forName("UTF-8")); + return file; + } catch (IOException e) { + throw new RuntimeException("Failed to write package listing file to disk", e); + } + }) + .handleAsync(v -> { + if (listingType.isGameKeyCompatible()) { + SwingHelper.showMessageDialog(dialog, "Successfully generated package listing.", "Success", null, JOptionPane.INFORMATION_MESSAGE); + } else { + SwingHelper.showMessageDialog(dialog, "Successfully generated package listing.\n\n" + + "Note that any modpacks with game keys set were not added.", + "Success", null, JOptionPane.INFORMATION_MESSAGE); + } + dialog.dispose(); + SwingHelper.browseDir(destDir, dialog); + }, ex -> {}, SwingExecutor.INSTANCE); + + ProgressDialog.showProgress(dialog, deferred, progress, "Writing package listing...", "Writing package listing..."); + SwingHelper.addErrorDialogCallback(dialog, deferred); + + return true; + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/ManifestEntryController.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/ManifestEntryController.java new file mode 100644 index 0000000..c5cc42e --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/ManifestEntryController.java @@ -0,0 +1,55 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.controller; + +import com.skcraft.launcher.creator.dialog.ManifestEntryDialog; +import com.skcraft.launcher.creator.model.creator.ManifestEntry; +import com.skcraft.launcher.swing.SwingHelper; + +public class ManifestEntryController { + + private final ManifestEntryDialog dialog; + private final ManifestEntry manifestEntry; + + private boolean save; + + public ManifestEntryController(ManifestEntryDialog dialog, ManifestEntry manifestEntry) { + this.dialog = dialog; + this.manifestEntry = manifestEntry; + + initListeners(); + copyFrom(); + } + + private void copyFrom() { + dialog.getIncludeCheck().setSelected(manifestEntry.isSelected()); + dialog.getPrioritySpinner().setValue(manifestEntry.getManifestInfo().getPriority()); + SwingHelper.setTextAndResetCaret(dialog.getGameKeysText(), SwingHelper.listToLines(manifestEntry.getGameKeys())); + } + + private void copyTo() { + manifestEntry.setSelected(dialog.getIncludeCheck().isSelected()); + manifestEntry.getManifestInfo().setPriority((Integer) dialog.getPrioritySpinner().getValue()); + manifestEntry.setGameKeys(SwingHelper.linesToList(dialog.getGameKeysText().getText())); + } + + public boolean show() { + dialog.setVisible(true); + return save; + } + + private void initListeners() { + dialog.getOkButton().addActionListener(e -> { + copyTo(); + save = true; + dialog.dispose(); + }); + + dialog.getCancelButton().addActionListener(e -> dialog.dispose()); + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/PackManagerController.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/PackManagerController.java new file mode 100644 index 0000000..582fef0 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/PackManagerController.java @@ -0,0 +1,752 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.controller; + +import com.google.common.base.Optional; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.skcraft.concurrency.Deferred; +import com.skcraft.concurrency.Deferreds; +import com.skcraft.concurrency.SettableProgress; +import com.skcraft.launcher.InstanceList; +import com.skcraft.launcher.Launcher; +import com.skcraft.launcher.auth.OfflineSession; +import com.skcraft.launcher.auth.Session; +import com.skcraft.launcher.builder.BuilderConfig; +import com.skcraft.launcher.builder.FnPatternList; +import com.skcraft.launcher.creator.model.creator.Pack; +import com.skcraft.launcher.creator.controller.task.*; +import com.skcraft.launcher.creator.dialog.*; +import com.skcraft.launcher.creator.dialog.BuildDialog.BuildOptions; +import com.skcraft.launcher.creator.dialog.DeployServerDialog.DeployOptions; +import com.skcraft.launcher.creator.model.creator.ManifestEntry; +import com.skcraft.launcher.creator.model.creator.Problem; +import com.skcraft.launcher.creator.model.creator.Workspace; +import com.skcraft.launcher.creator.model.swing.PackTableModel; +import com.skcraft.launcher.creator.server.TestServer; +import com.skcraft.launcher.creator.server.TestServerBuilder; +import com.skcraft.launcher.creator.swing.PackDirectoryFilter; +import com.skcraft.launcher.dialog.ConfigurationDialog; +import com.skcraft.launcher.dialog.ConsoleFrame; +import com.skcraft.launcher.dialog.ProgressDialog; +import com.skcraft.launcher.model.modpack.LaunchModifier; +import com.skcraft.launcher.persistence.Persistence; +import com.skcraft.launcher.swing.PopupMouseAdapter; +import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.util.MorePaths; +import com.skcraft.launcher.util.SwingExecutor; +import lombok.Getter; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.regex.Pattern; + +public class PackManagerController { + + private static final DateFormat VERSION_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + private static final Pattern FILENAME_SANITIZE = Pattern.compile("[^a-z0-9_\\-\\.]+"); + + @Getter private final File workspaceDir; + @Getter private final File workspaceFile; + @Getter private final File dataDir; + @Getter private final File distDir; + @Getter private File webRoot; + @Getter private Workspace workspace; + @Getter private final Launcher launcher; + @Getter private final ListeningExecutorService executor; + @Getter private final TestServer testServer; + + private File lastServerDestDir; + + private final PackManagerFrame frame; + private PackTableModel packTableModel; + + public PackManagerController(PackManagerFrame frame, File workspaceDir) throws IOException { + this.workspaceDir = workspaceDir; + this.dataDir = Workspace.getDataDir(workspaceDir); + workspaceFile = Workspace.getWorkspaceFile(workspaceDir); + + this.distDir = new File(workspaceDir, "_upload"); + File launcherDir = new File(dataDir, "staging/launcher"); + this.webRoot = new File(dataDir, "staging/www"); + + launcherDir.mkdirs(); + webRoot.mkdirs(); + + this.launcher = new Launcher(launcherDir); + this.executor = launcher.getExecutor(); + this.frame = frame; + + TestServerBuilder builder = new TestServerBuilder(); + builder.setBaseDir(webRoot); + builder.setPort(0); + testServer = builder.build(); + } + + public void show() { + frame.setVisible(true); + frame.setTitle("Modpack Creator - [" + workspaceDir.getAbsolutePath() + "]"); + + initListeners(); + loadWorkspace(); + + Deferreds.makeDeferred(executor.submit(() -> { + startServer(); + return null; + })) + .handle( + result -> { + }, + (ex) -> SwingHelper.showErrorDialog(frame, "Failed to start a local web server. You will be unable to test modpacks.", "Error", ex) + ); + } + + private void startServer() throws Exception { + testServer.start(); + + launcher.getProperties().setProperty("newsUrl", "http://localhost:" + testServer.getLocalPort() + "/news.html"); + launcher.getProperties().setProperty("packageListUrl", "http://localhost:" + testServer.getLocalPort() + "/packages.json"); + launcher.getProperties().setProperty("selfUpdateUrl", "http://localhost:" + testServer.getLocalPort() + "/latest.json"); + } + + private void loadWorkspace() { + PackLoader loader = new PackLoader(); + + SettableProgress progress = new SettableProgress("Loading workspace...", -1); + + Deferred deferred = Deferreds.makeDeferred(executor.submit(() -> { + Workspace workspace = Persistence.load(workspaceFile, Workspace.class); + workspace.setDirectory(workspaceDir); + workspace.load(); + if (!workspaceFile.exists()) { + Persistence.commitAndForget(workspace); + } + this.workspace = workspace; + return workspace; + })) + .thenTap(() -> progress.observe(loader)) + .thenApply(loader) + .thenApplyAsync(packs -> { + JTable table = frame.getPackTable(); + packTableModel = new PackTableModel(packs); + table.setModel(packTableModel); + packTableModel.fireTableDataChanged(); + table.getRowSorter().toggleSortOrder(1); + if (packTableModel.getRowCount() > 0) { + table.addRowSelectionInterval(0, 0); + } + + return packs; + }, SwingExecutor.INSTANCE); + + ProgressDialog.showProgress(frame, deferred, progress, "Loading workspace...", "Loading workspace..."); + SwingHelper.addErrorDialogCallback(frame, deferred); + } + + private boolean checkPackLoaded(Pack pack) { + if (pack.isLoaded()) { + return true; + } else { + SwingHelper.showErrorDialog(frame, "The selected pack could not be loaded. You will have to remove it from the workspace or change its location.", "Error"); + return false; + } + } + + public Optional getPackFromIndex(int selectedIndex, boolean requireLoaded) { + if (selectedIndex >= 0) { + Pack pack = workspace.getPacks().get(selectedIndex); + if (pack != null && (!requireLoaded || checkPackLoaded(pack))) { + return Optional.fromNullable(pack); + } + } + return Optional.absent(); + } + + public Optional getSelectedPack(boolean requireLoaded) { + JTable table = frame.getPackTable(); + int selectedIndex = table.getSelectedRow(); + if (selectedIndex >= 0) { + selectedIndex = table.convertRowIndexToModel(selectedIndex); + Pack pack = workspace.getPacks().get(selectedIndex); + if (pack != null && (!requireLoaded || checkPackLoaded(pack))) { + return Optional.fromNullable(pack); + } + } + + SwingHelper.showErrorDialog(frame, "Please select a modpack from the list.", "Error"); + return Optional.absent(); + } + + public boolean writeWorkspace() { + try { + Persistence.commit(workspace); + return true; + } catch (IOException e) { + SwingHelper.showErrorDialog(frame, "Failed to write the current state of the workspace to disk. " + + "Any recent changes to the list of modpacks may not appear in the workspace on the next load.", "Error", e); + return false; + } + } + + public boolean writeBuilderConfig(Pack pack, BuilderConfig config) { + try { + Persistence.write(pack.getConfigFile(), config, Persistence.L2F_LIST_PRETTY_PRINTER); + return true; + } catch (IOException e) { + SwingHelper.showErrorDialog(frame, "Failed to write modpack.json to disk. Aborting.", "Error", e); + return false; + } + } + + public boolean canAddPackDir(File dir) { + try { + if (dir.exists() && !dir.isDirectory()) { + SwingHelper.showErrorDialog(frame, "The selected path is a file that already exists. It must be a directory.", "Error"); + return false; + } else if (dir.getCanonicalPath().equals(workspaceDir.getCanonicalPath())) { + SwingHelper.showErrorDialog(frame, "You cannot choose the workspace directory.", "Error"); + return false; + } else if (workspace.hasPack(dir)) { + SwingHelper.showErrorDialog(frame, "There is already a modpack in this workspace that uses that directory.", "Error"); + return false; + } else { + return true; + } + } catch (IOException e) { + SwingHelper.showErrorDialog(frame, "An unexpected error occurred while checking if the modpack being added can be added.", "Error", e); + return false; + } + } + + public boolean addPackToWorkspace(Pack pack) { + pack.load(); + + try { + File base = workspaceDir; + File child = pack.getDirectory(); + if (MorePaths.isSubDirectory(base, child)) { + pack.setLocation(MorePaths.relativize(base, child)); + } + } catch (IOException e) { + SwingHelper.showErrorDialog(frame, "An unexpected error occurred that could have been caused by the removal " + + "of the workspace or modpack directory.", "Error", e); + return false; + } + + List packs = workspace.getPacks(); + pack.setWorkspace(workspace); + packs.add(pack); + packTableModel.fireTableRowsInserted(packs.size() - 1, packs.size() - 1); + writeWorkspace(); + + return true; + } + + public void updatePackInWorkspace(Pack pack) { + List packs = workspace.getPacks(); + pack.load(); + int index = packs.indexOf(pack); + if (index >= 0) { + packTableModel.fireTableRowsUpdated(index, index); + } + writeWorkspace(); + } + + public boolean removePackFromWorkspace(Pack pack) { + if (workspace.getPacks().remove(pack)) { + packTableModel.fireTableDataChanged(); + writeWorkspace(); + return true; + } else { + return false; + } + } + + private void addDefaultConfig(BuilderConfig config) { + LaunchModifier launchModifier = new LaunchModifier(); + launchModifier.setFlags(ImmutableList.of("-Dfml.ignoreInvalidMinecraftCertificates=true")); + config.setLaunchModifier(launchModifier); + + FnPatternList userFiles = new FnPatternList(); + userFiles.setInclude(Lists.newArrayList("options.txt", "optionsshaders.txt")); + userFiles.setExclude(Lists.newArrayList()); + config.setUserFiles(userFiles); + } + + private void initListeners() { + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + try { + testServer.stop(); + } catch (Exception ignored) { + } + System.exit(0); // TODO: Proper shutdown + } + }); + + frame.getPackTable().addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + if (e.getClickCount() == 2) { + JTable table = (JTable) e.getSource(); + Point point = e.getPoint(); + int selectedIndex = table.rowAtPoint(point); + if (selectedIndex >= 0) { + selectedIndex = table.convertRowIndexToModel(selectedIndex); + Optional optional = getPackFromIndex(selectedIndex, true); + if (optional.isPresent()) { + if (e.isControlDown()) { + SwingHelper.browseDir(optional.get().getDirectory(), frame); + } else { + startTest(optional.get()); + } + } + } + } + } + }); + + frame.getPackTable().addMouseListener(new PopupMouseAdapter() { + @Override + protected void showPopup(MouseEvent e) { + JTable table = (JTable) e.getSource(); + Point point = e.getPoint(); + int selectedIndex = table.rowAtPoint(point); + if (selectedIndex >= 0) { + table.setRowSelectionInterval(selectedIndex, selectedIndex); + Optional optional = getSelectedPack(false); + if (optional.isPresent()) { + popupPackMenu(e.getComponent(), e.getX(), e.getY(), optional.get()); + } + } + } + }); + + frame.getNewPackMenuItem().addActionListener(event -> tryAddPackViaDialog()); + + frame.getNewPackAtLocationMenuItem().addActionListener(e -> tryAddPackViaDirectory(true)); + + frame.getImportPackMenuItem().addActionListener(event -> tryAddPackViaDirectory(false)); + + frame.getRemovePackItem().addActionListener(e -> { + Optional optional = getSelectedPack(false); + + if (optional.isPresent()) { + Pack pack = optional.get(); + + if (!pack.isLoaded() || SwingHelper.confirmDialog(frame, "Are you sure that you want to remove this modpack? No files will be deleted " + + "and you can later re-import the modpack using 'Add Existing'.", "Confirm")) { + removePackFromWorkspace(pack); + } + } + }); + + frame.getDeletePackItem().addActionListener(e -> { + Optional optional = getSelectedPack(false); + + if (optional.isPresent()) { + Pack pack = optional.get(); + + String input = JOptionPane.showInputDialog( + frame, + "Are you sure that you want to delete '" + pack.getDirectory().getAbsolutePath() + "'? " + + "If yes, type 'delete' below.", + "Confirm", + JOptionPane.WARNING_MESSAGE); + + if (input != null && input.replaceAll("'", "").equalsIgnoreCase("delete")) { + removePackFromWorkspace(pack); + + DirectoryDeleter deleter = new DirectoryDeleter(pack.getDirectory()); + Deferred deferred = Deferreds.makeDeferred(executor.submit(deleter), executor); + ProgressDialog.showProgress(frame, deferred, deleter, "Deleting modpack...", "Deleting modpack..."); + SwingHelper.addErrorDialogCallback(frame, deferred); + } else if (input != null) { + SwingHelper.showMessageDialog(frame, "You did not enter the correct word. Nothing was deleted.", "Failure", null, JOptionPane.INFORMATION_MESSAGE); + } + } + }); + + frame.getChangePackLocationMenuItem().addActionListener(e -> { + Optional optional = getSelectedPack(false); + + if (optional.isPresent()) { + Pack pack = optional.get(); + + JFileChooser chooser = new JFileChooser(); + chooser.setDialogTitle("Choose New Folder for Pack"); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setFileFilter(new PackDirectoryFilter()); + + File dir = workspaceDir; + + do { + chooser.setCurrentDirectory(dir); + int returnVal = chooser.showOpenDialog(frame); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + dir = chooser.getSelectedFile(); + } else { + return; + } + } while (!canAddPackDir(dir)); + + pack.setLocation(dir.getAbsolutePath()); + updatePackInWorkspace(pack); + } + }); + + frame.getRefreshMenuItem().addActionListener(e -> loadWorkspace()); + + frame.getQuitMenuItem().addActionListener(e -> { + frame.dispose(); + }); + + frame.getEditConfigMenuItem().addActionListener(e -> { + Optional optional = getSelectedPack(true); + + if (optional.isPresent()) { + Pack pack = optional.get(); + File file = pack.getConfigFile(); + BuilderConfig config = Persistence.read(file, BuilderConfig.class); + + if (BuilderConfigDialog.showEditor(frame, config)) { + writeBuilderConfig(pack, config); + updatePackInWorkspace(pack); + } + } + }); + + frame.getOpenFolderMenuItem().addActionListener(e -> { + Optional optional = getSelectedPack(true); + + if (optional.isPresent()) { + SwingHelper.browseDir(optional.get().getDirectory(), frame); + } + }); + + frame.getCheckProblemsMenuItem().addActionListener(e -> { + Optional optional = getSelectedPack(true); + + if (optional.isPresent()) { + ProblemChecker checker = new ProblemChecker(optional.get()); + Deferred deferred = Deferreds.makeDeferred(executor.submit(checker), executor) + .handleAsync(this::showProblems, (ex) -> { + }, SwingExecutor.INSTANCE); + SwingHelper.addErrorDialogCallback(frame, deferred); + } + }); + + frame.getTestMenuItem().addActionListener(e -> { + Optional optional = getSelectedPack(true); + + if (optional.isPresent()) { + Pack pack = optional.get(); + startTest(pack); + } + }); + + frame.getOptionsMenuItem().addActionListener(e -> { + ConfigurationDialog configDialog = new ConfigurationDialog(frame, launcher); + configDialog.setVisible(true); + }); + + frame.getClearInstanceMenuItem().addActionListener(e -> { + DirectoryDeleter deleter = new DirectoryDeleter(launcher.getInstancesDir()); + Deferred deferred = Deferreds.makeDeferred(executor.submit(deleter), executor); + ProgressDialog.showProgress(frame, deferred, deleter, "Deleting test instances...", "Deleting test instances..."); + SwingHelper.addErrorDialogCallback(frame, deferred); + }); + + frame.getClearWebRootMenuItem().addActionListener(e -> { + DirectoryDeleter deleter = new DirectoryDeleter(webRoot); + Deferred deferred = Deferreds.makeDeferred(executor.submit(deleter), executor); + ProgressDialog.showProgress(frame, deferred, deleter, "Deleting web server files...", "Deleting web server files..."); + SwingHelper.addErrorDialogCallback(frame, deferred); + }); + + frame.getBuildMenuItem().addActionListener(e -> { + Optional optional = getSelectedPack(true); + + if (optional.isPresent()) { + Pack pack = optional.get(); + buildPack(pack); + } + }); + + frame.getDeployServerMenuItem().addActionListener(e -> { + Optional optional = getSelectedPack(true); + + if (optional.isPresent()) { + Pack pack = optional.get(); + DeployOptions options = DeployServerDialog.showDeployDialog(frame, lastServerDestDir); + + if (options != null) { + ConsoleFrame.showMessages(); + + File destDir = options.getDestDir(); + destDir.mkdirs(); + lastServerDestDir = destDir; + + ServerDeploy deploy = new ServerDeploy(pack.getSourceDir(), options); + Deferred deferred = Deferreds.makeDeferred(executor.submit(deploy), executor) + .handleAsync(r -> SwingHelper.showMessageDialog(frame, "Server deployment complete!", "Success", null, JOptionPane.INFORMATION_MESSAGE), + ex -> {}, + SwingExecutor.INSTANCE); + ProgressDialog.showProgress(frame, deferred, deploy, "Deploying files...", "Deploying server files..."); + SwingHelper.addErrorDialogCallback(frame, deferred); + } + } + }); + + frame.getGeneratePackagesMenuItem().addActionListener(e -> { + List entries = workspace.getPackageListingEntries(); + ManifestInfoEnumerator enumerator = new ManifestInfoEnumerator(distDir); + Deferred deferred = Deferreds.makeDeferred(executor.submit(() -> enumerator.apply(entries))) + .handleAsync(loaded -> { + GenerateListingDialog dialog = new GenerateListingDialog(frame); + GenerateListingController controller = new GenerateListingController(dialog, workspace, loaded, executor); + controller.setOutputDir(distDir); + controller.show(); + }, ex -> {}, SwingExecutor.INSTANCE); + ProgressDialog.showProgress(frame, deferred, new SettableProgress("Searching...", -1), "Searching for manifests...", "Searching for manifests..."); + SwingHelper.addErrorDialogCallback(frame, deferred); + }); + + frame.getOpenOutputFolderMenuItem().addActionListener(e -> SwingHelper.browseDir(distDir, frame)); + + frame.getOpenConsoleMenuItem().addActionListener(e -> { + ConsoleFrame.showMessages(); + }); + + frame.getDocsMenuItem().addActionListener(e -> { + SwingHelper.openURL("https://github.com/SKCraft/Launcher/wiki", frame); + }); + + frame.getAboutMenuItem().addActionListener(e -> { + AboutDialog.showAboutDialog(frame); + }); + + SwingHelper.addActionListeners(frame.getNewPackButton(), frame.getNewPackMenuItem().getActionListeners()); + SwingHelper.addActionListeners(frame.getImportButton(), frame.getImportPackMenuItem().getActionListeners()); + SwingHelper.addActionListeners(frame.getEditConfigButton(), frame.getEditConfigMenuItem().getActionListeners()); + SwingHelper.addActionListeners(frame.getOpenFolderButton(), frame.getOpenFolderMenuItem().getActionListeners()); + SwingHelper.addActionListeners(frame.getCheckProblemsButton(), frame.getCheckProblemsMenuItem().getActionListeners()); + SwingHelper.addActionListeners(frame.getTestButton(), frame.getTestMenuItem().getActionListeners()); + SwingHelper.addActionListeners(frame.getBuildButton(), frame.getBuildMenuItem().getActionListeners()); + } + + private void popupPackMenu(Component component, int x, int y, Pack pack) { + JPopupMenu popup = new JPopupMenu(); + JMenuItem menuItem; + + menuItem = new JMenuItem("Edit modpack.json..."); + menuItem.addActionListener(e -> frame.getEditConfigMenuItem().doClick()); + popup.add(menuItem); + + menuItem = new JMenuItem("Open Directory"); + menuItem.addActionListener(e -> frame.getOpenFolderMenuItem().doClick()); + popup.add(menuItem); + + menuItem = new JMenuItem("Check for Problems"); + menuItem.addActionListener(e -> frame.getCheckProblemsMenuItem().doClick()); + popup.add(menuItem); + + popup.addSeparator(); + + menuItem = new JMenuItem("Test"); + menuItem.addActionListener(e -> frame.getTestMenuItem().doClick()); + popup.add(menuItem); + + menuItem = new JMenuItem("Build..."); + menuItem.addActionListener(e -> frame.getBuildMenuItem().doClick()); + popup.add(menuItem); + + menuItem = new JMenuItem("Deploy Server..."); + menuItem.addActionListener(e -> frame.getDeployServerMenuItem().doClick()); + popup.add(menuItem); + + popup.addSeparator(); + + menuItem = new JMenuItem("Change Location..."); + menuItem.addActionListener(e -> frame.getChangePackLocationMenuItem().doClick()); + popup.add(menuItem); + + menuItem = new JMenuItem("Remove..."); + menuItem.addActionListener(e -> frame.getRemovePackItem().doClick()); + popup.add(menuItem); + + menuItem = new JMenuItem("Delete Forever..."); + menuItem.addActionListener(e -> frame.getDeletePackItem().doClick()); + popup.add(menuItem); + + popup.show(component, x, y); + } + + private void tryAddPackViaDialog() { + BuilderConfig config = new BuilderConfig(); + addDefaultConfig(config); + Pack pack = new Pack(); + File dir; + + do { + if (BuilderConfigDialog.showEditor(frame, config)) { + dir = new File(workspaceDir, config.getName()); + } else { + return; + } + } while (!canAddPackDir(dir)); + + pack.setLocation(dir.getAbsolutePath()); + + if (pack.getConfigFile().exists()) { + if (SwingHelper.confirmDialog(frame, "There's already an existing modpack with that name, though " + + "it is not imported into this workspace. Would you like to import it and ignore " + + "the new modpack that you just entered?", "Conflict")) { + addPackToWorkspace(pack); + } + } else { + if (writeBuilderConfig(pack, config)) { + pack.createGuideFolders(); + addPackToWorkspace(pack); + } + } + } + + private void tryAddPackViaDirectory(boolean createNew) { + JFileChooser chooser = new JFileChooser(); + chooser.setDialogTitle("Choose Folder for Pack"); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setFileFilter(new PackDirectoryFilter()); + + File dir = workspaceDir; + + do { + chooser.setCurrentDirectory(dir); + int returnVal = chooser.showOpenDialog(frame); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + dir = chooser.getSelectedFile(); + } else { + return; + } + } while (!canAddPackDir(dir)); + + Pack pack = new Pack(); + pack.setLocation(dir.getAbsolutePath()); + + if (pack.getConfigFile().exists()) { + if (createNew) { + if (SwingHelper.confirmDialog(frame, "There's already a modpack in that directory. Do you want to import it instead?", "Exists Already")) { + addPackToWorkspace(pack); + } + } else { + addPackToWorkspace(pack); + } + } else if (createNew || SwingHelper.confirmDialog(frame, "You've selected a directory that doesn't seem to be a modpack " + + "(at least with the directory structure this program expects). Would you like to create the files necessary to turn " + + "that folder into a modpack?", "Import Error")) { + + BuilderConfig config = new BuilderConfig(); + addDefaultConfig(config); + + if (BuilderConfigDialog.showEditor(frame, config)) { + if (writeBuilderConfig(pack, config)) { + pack.createGuideFolders(); + addPackToWorkspace(pack); + } + } + } + } + + private void startTest(Pack pack) { + Session session = new OfflineSession("Player"); + String version = generateVersionFromDate(); + + PackBuilder builder = new PackBuilder(pack, webRoot, version, "staging.json", false); + InstanceList.Enumerator enumerator = launcher.getInstances().createEnumerator(); + TestLauncher instanceLauncher = new TestLauncher(launcher, frame, pack.getCachedConfig().getName(), session); + + SettableProgress progress = new SettableProgress(builder); + + ConsoleFrame.showMessages(); + + Deferred deferred = Deferreds.makeDeferred(executor.submit(builder), executor) + .thenTap(() -> progress.set("Loading instance in test launcher...", -1)) + .thenRun(enumerator) + .thenTap(() -> progress.set("Launching", -1)) + .thenApply(instanceLauncher) + .handleAsync(result -> ConsoleFrame.hideMessages(), ex -> {}, SwingExecutor.INSTANCE); + + ProgressDialog.showProgress(frame, deferred, progress, "Setting up test instance...", "Preparing files for launch..."); + SwingHelper.addErrorDialogCallback(frame, deferred); + } + + private void buildPack(Pack pack) { + String initialVersion = generateVersionFromDate(); + BuildOptions options = BuildDialog.showBuildDialog(frame, initialVersion, generateManifestName(pack), distDir); + + if (options != null) { + ConsoleFrame.showMessages(); + PackBuilder builder = new PackBuilder(pack, options.getDestDir(), options.getVersion(), options.getManifestFilename(), false); + Deferred deferred = Deferreds.makeDeferred(executor.submit(builder), executor) + .handleAsync(result -> { + ConsoleFrame.hideMessages(); + SwingHelper.showMessageDialog(frame, "Successfully generated the package files.", "Success", null, JOptionPane.INFORMATION_MESSAGE); + SwingHelper.browseDir(options.getDestDir(), frame); + }, ex -> {}, SwingExecutor.INSTANCE); + ProgressDialog.showProgress(frame, deferred, builder, "Building modpack...", "Building modpack..."); + SwingHelper.addErrorDialogCallback(frame, deferred); + } + } + + private void showProblems(List problems) { + if (problems.isEmpty()) { + SwingHelper.showMessageDialog(frame, "No potential problems found!", "Success", null, JOptionPane.INFORMATION_MESSAGE); + } else { + ProblemViewer viewer = new ProblemViewer(frame, problems); + viewer.setVisible(true); + } + } + + public String generateManifestName(Pack pack) { + File file = pack.getConfigFile(); + if (file.exists()) { + BuilderConfig config = Persistence.read(file, BuilderConfig.class, true); + if (config != null) { + String name = Strings.nullToEmpty(config.getName()); + name = name.toLowerCase(); + name = FILENAME_SANITIZE.matcher(name).replaceAll("-"); + name = name.trim(); + if (!name.isEmpty()) { + return name + ".json"; + } + } + } + + return "my_modpack.json"; + } + + public static String generateVersionFromDate() { + Date today = Calendar.getInstance().getTime(); + return VERSION_DATE_FORMAT.format(today); + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/WelcomeController.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/WelcomeController.java new file mode 100644 index 0000000..266cca2 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/WelcomeController.java @@ -0,0 +1,204 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.controller; + +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import com.skcraft.launcher.creator.Creator; +import com.skcraft.launcher.creator.dialog.AboutDialog; +import com.skcraft.launcher.creator.dialog.PackManagerFrame; +import com.skcraft.launcher.creator.dialog.WelcomeDialog; +import com.skcraft.launcher.creator.model.creator.RecentEntry; +import com.skcraft.launcher.creator.model.creator.Workspace; +import com.skcraft.launcher.creator.model.swing.RecentListModel; +import com.skcraft.launcher.creator.swing.WorkspaceDirectoryFilter; +import com.skcraft.launcher.persistence.Persistence; +import com.skcraft.launcher.swing.PopupMouseAdapter; +import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.util.MorePaths; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +public class WelcomeController { + + private final WelcomeDialog dialog; + private final Creator creator; + private final RecentListModel recentListModel; + + public WelcomeController(WelcomeDialog dialog, Creator creator) { + this.dialog = dialog; + this.creator = creator; + + initListeners(); + + recentListModel = new RecentListModel(creator.getConfig().getRecentEntries()); + dialog.getRecentList().setModel(recentListModel); + } + + public void show() { + dialog.setVisible(true); + } + + private boolean openWorkspace(File dir) { + try { + PackManagerFrame frame = new PackManagerFrame(); + PackManagerController controller = new PackManagerController(frame, dir); + addRecentEntry(dir); + controller.show(); + return true; + } catch (IOException e) { + SwingHelper.showErrorDialog(dialog, "An unexpected error has occurred.", "Error", e); + return false; + } + } + + private void addRecentEntry(File dir) { + List newEntries = creator.getConfig().getRecentEntries() + .stream() + .filter(entry -> { + try { + return !MorePaths.isSamePath(entry.getPath(), dir); + } catch (IOException ignored) { + return false; + } + }) + .collect(Collectors.toCollection(Lists::newArrayList)); + + RecentEntry recent = new RecentEntry(); + recent.setPath(dir); + newEntries.add(0, recent); + + creator.getConfig().setRecentEntries(newEntries); + + Persistence.commitAndForget(creator.getConfig()); + + recentListModel.fireUpdate(); + } + + private void removeRecentEntry(RecentEntry entry) { + creator.getConfig().getRecentEntries().remove(entry); + Persistence.commitAndForget(creator.getConfig()); + + recentListModel.fireUpdate(); + } + + private Optional getSelectedRecentEntry() { + int selectedIndex = dialog.getRecentList().getSelectedIndex(); + if (selectedIndex >= 0) { + return Optional.fromNullable(creator.getConfig().getRecentEntries().get(selectedIndex)); + } else { + return Optional.absent(); + } + } + + private Optional getWorkspaceDir() { + JFileChooser chooser = new JFileChooser(); + chooser.setDialogTitle("Select Workspace Directory"); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setFileFilter(new WorkspaceDirectoryFilter()); + + int returnVal = chooser.showOpenDialog(dialog); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + return Optional.fromNullable(chooser.getSelectedFile()); + } else { + return Optional.absent(); + } + } + + private void initListeners() { + dialog.getRecentList().addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + if (e.getClickCount() == 2) { + JList table = (JList) e.getSource(); + Point point = e.getPoint(); + int selectedIndex = table.locationToIndex(point); + if (selectedIndex >= 0) { + table.setSelectedIndex(selectedIndex); + Optional optional = getSelectedRecentEntry(); + if (optional.isPresent()) { + if (openWorkspace(optional.get().getPath())) { + dialog.dispose(); + } + } + } + } + } + }); + + dialog.getRecentList().addMouseListener(new PopupMouseAdapter() { + @Override + protected void showPopup(MouseEvent e) { + JList table = (JList) e.getSource(); + Point point = e.getPoint(); + int selectedIndex = table.locationToIndex(point); + if (selectedIndex >= 0) { + table.setSelectedIndex(selectedIndex); + Optional optional = getSelectedRecentEntry(); + if (optional.isPresent()) { + popupRecentWorkspaceMenu(e.getComponent(), e.getX(), e.getY(), optional.get()); + } + } + } + }); + + dialog.getNewButton().addActionListener(e -> { + Optional optional = getWorkspaceDir(); + if (optional.isPresent()) { + File workspaceFile = Workspace.getWorkspaceFile(optional.get()); + if (!workspaceFile.exists() || SwingHelper.confirmDialog(dialog, "There is already a workspace there. Do you want to load it?", "Existing")) { + if (openWorkspace(optional.get())) { + dialog.dispose(); + } + } + } + }); + + dialog.getOpenButton().addActionListener(e -> { + Optional optional = getWorkspaceDir(); + if (optional.isPresent()) { + File workspaceFile = Workspace.getWorkspaceFile(optional.get()); + if (workspaceFile.exists() || SwingHelper.confirmDialog(dialog, "Do you want to create a new workspace there?", "Create New")) { + if (openWorkspace(optional.get())) { + dialog.dispose(); + } + } + } + }); + + dialog.getHelpButton().addActionListener(e -> { + SwingHelper.openURL("https://github.com/SKCraft/Launcher/wiki", dialog); + }); + + dialog.getAboutButton().addActionListener(e -> { + AboutDialog.showAboutDialog(dialog); + }); + + dialog.getQuitButton().addActionListener(e -> { + dialog.dispose(); + }); + } + + private void popupRecentWorkspaceMenu(Component component, int x, int y, RecentEntry entry) { + JPopupMenu popup = new JPopupMenu(); + JMenuItem menuItem; + + menuItem = new JMenuItem("Remove"); + menuItem.addActionListener(e -> removeRecentEntry(entry)); + popup.add(menuItem); + + popup.show(component, x, y); + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/DirectoryRemover.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/DirectoryDeleter.java similarity index 68% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/DirectoryRemover.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/DirectoryDeleter.java index 1ba9072..99141dd 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/DirectoryRemover.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/DirectoryDeleter.java @@ -4,7 +4,7 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools; +package com.skcraft.launcher.creator.controller.task; import com.skcraft.concurrency.ProgressObservable; import com.skcraft.launcher.LauncherException; @@ -16,21 +16,17 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; -import static com.skcraft.launcher.LauncherUtils.checkInterrupted; - -public class DirectoryRemover implements Callable, ProgressObservable { +public class DirectoryDeleter implements Callable, ProgressObservable { private final File dir; - public DirectoryRemover(File dir) { + public DirectoryDeleter(File dir) { this.dir = dir; } @Override - public DirectoryRemover call() throws Exception { - checkInterrupted(); - - Thread.sleep(1000); + public File call() throws Exception { + Thread.sleep(2000); List failures = new ArrayList(); @@ -42,10 +38,10 @@ public class DirectoryRemover implements Callable, ProgressObs } if (failures.size() > 0) { - throw new LauncherException(failures.size() + " failed to delete", failures.size() + " file(s) failed to delete."); + throw new LauncherException(failures.size() + " failed to delete", failures.size() + " file(s) could not be deleted"); } - return this; + return dir; } @Override @@ -55,6 +51,7 @@ public class DirectoryRemover implements Callable, ProgressObs @Override public String getStatus() { - return "Removing files..."; + return "Deleting files..."; } + } diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/ManifestInfoEnumerator.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/ManifestInfoEnumerator.java new file mode 100644 index 0000000..86f6c0f --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/ManifestInfoEnumerator.java @@ -0,0 +1,66 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.controller.task; + +import com.skcraft.launcher.creator.model.creator.ManifestEntry; +import com.skcraft.launcher.model.modpack.Manifest; +import com.skcraft.launcher.model.modpack.ManifestInfo; +import com.skcraft.launcher.persistence.Persistence; + +import java.io.File; +import java.util.List; +import java.util.function.Function; + +public class ManifestInfoEnumerator implements Function, List> { + + private final File searchDir; + + public ManifestInfoEnumerator(File searchDir) { + this.searchDir = searchDir; + } + + @Override + public List apply(List entries) { + File[] files = searchDir.listFiles(f -> f.isFile() && f.getName().toLowerCase().endsWith(".json") && !f.getName().startsWith("packages.")); + + if (files != null) { + for (File file : files) { + String location = file.getName(); + Manifest manifest = Persistence.read(file, Manifest.class, true); + + if (manifest != null) { + ManifestInfo info = new ManifestInfo(); + info.setName(manifest.getName()); + info.setTitle(manifest.getTitle()); + info.setVersion(manifest.getVersion()); + info.setPriority(0); + info.setLocation(location); + + boolean found = false; + + for (ManifestEntry entry : entries) { + if (entry.getManifestInfo().getLocation().equals(location)) { + info.setPriority(entry.getManifestInfo().getPriority()); + entry.setManifestInfo(info); + found = true; + break; + } + } + + if (!found) { + ManifestEntry entry = new ManifestEntry(); + entry.setManifestInfo(info); + entries.add(entry); + } + } + } + } + + return entries; + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ModpackBuilder.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/PackBuilder.java similarity index 80% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ModpackBuilder.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/PackBuilder.java index 272a315..bf33fe2 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ModpackBuilder.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/PackBuilder.java @@ -4,12 +4,13 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.compile; +package com.skcraft.launcher.creator.controller.task; import com.skcraft.concurrency.ProgressObservable; import com.skcraft.launcher.LauncherException; import com.skcraft.launcher.LauncherUtils; import com.skcraft.launcher.builder.PackageBuilder; +import com.skcraft.launcher.creator.model.creator.Pack; import java.io.File; import java.io.IOException; @@ -17,16 +18,16 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; -public class ModpackBuilder implements Callable, ProgressObservable { +public class PackBuilder implements Callable, ProgressObservable { - private final File inputDir; + private final Pack pack; private final File outputDir; private final String version; private final String manifestFilename; private final boolean clean; - public ModpackBuilder(File inputDir, File outputDir, String version, String manifestFilename, boolean clean) { - this.inputDir = inputDir; + public PackBuilder(Pack pack, File outputDir, String version, String manifestFilename, boolean clean) { + this.pack = pack; this.outputDir = outputDir; this.version = version; this.manifestFilename = manifestFilename; @@ -34,7 +35,7 @@ public class ModpackBuilder implements Callable, ProgressObserva } @Override - public ModpackBuilder call() throws Exception { + public PackBuilder call() throws Exception { if (clean) { List failures = new ArrayList(); @@ -56,7 +57,7 @@ public class ModpackBuilder implements Callable, ProgressObserva String[] args = { "--version", version, "--manifest-dest", new File(outputDir, manifestFilename).getAbsolutePath(), - "-i", inputDir.getAbsolutePath(), + "-i", pack.getDirectory().getAbsolutePath(), "-o", outputDir.getAbsolutePath() }; PackageBuilder.main(args); diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/PackLoader.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/PackLoader.java new file mode 100644 index 0000000..df09771 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/PackLoader.java @@ -0,0 +1,57 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.controller.task; + +import com.google.common.base.Function; +import com.skcraft.concurrency.ProgressObservable; +import com.skcraft.launcher.creator.model.creator.Pack; +import com.skcraft.launcher.creator.model.creator.Workspace; + +import java.util.List; + +public class PackLoader implements ProgressObservable, Function> { + + private int index; + private int size = 0; + private Pack lastPack; + + @Override + public List apply(Workspace workspace) { + List packs = workspace.getPacks(); + size = packs.size(); + + for (Pack pack : packs) { + lastPack = pack; + pack.load(); + index++; + } + + lastPack = null; + + return packs; + } + + @Override + public double getProgress() { + if (size == 0) { + return -1; + } else { + return index / (double) size; + } + } + + @Override + public String getStatus() { + Pack pack = lastPack; + if (pack != null) { + return "Loading " + pack.getDirectory().getName() + "..."; + } else { + return "Enumerating packs..."; + } + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemChecker.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/ProblemChecker.java similarity index 78% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemChecker.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/ProblemChecker.java index 0719036..f23c1e1 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemChecker.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/ProblemChecker.java @@ -4,12 +4,13 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.compile; +package com.skcraft.launcher.creator.controller.task; import com.beust.jcommander.internal.Lists; import com.skcraft.concurrency.ProgressObservable; import com.skcraft.launcher.builder.BuilderOptions; -import com.skcraft.launcher.buildtools.BuildTools; +import com.skcraft.launcher.creator.model.creator.Pack; +import com.skcraft.launcher.creator.model.creator.Problem; import java.io.File; import java.util.List; @@ -17,51 +18,51 @@ import java.util.concurrent.Callable; public class ProblemChecker implements Callable>, ProgressObservable { - private final BuildTools buildTools; - private String status = "Checking for problems..."; + private final Pack pack; - public ProblemChecker(BuildTools buildTools) { - this.buildTools = buildTools; + public ProblemChecker(Pack pack) { + this.pack = pack; } @Override public List call() throws Exception { List problems = Lists.newArrayList(); - File inputDir = buildTools.getInputDir(); - File srcDir = buildTools.getSrcDir(); - File loadersDir = new File(inputDir, BuilderOptions.DEFAULT_LOADERS_DIRNAME); + File packDir = pack.getDirectory(); + File srcDir = pack.getSourceDir(); + + File loadersDir = new File(packDir, BuilderOptions.DEFAULT_LOADERS_DIRNAME); File modsDir = new File(srcDir, "mods"); boolean hasLoaders = hasFiles(loadersDir); boolean hasMods = hasFiles(modsDir); String[] files; - if (new File(inputDir, "_CLIENT").exists()) { + if (new File(packDir, "_CLIENT").exists()) { problems.add(new Problem("Root _CLIENT", "There's a _CLIENT folder that's not in " + "the src/ folder. Only files that are in src/ will actually appear in the " + "modpack, so you probably intended to put _CLIENT in src/.")); } - if (new File(inputDir, "_SERVER").exists()) { + if (new File(packDir, "_SERVER").exists()) { problems.add(new Problem("Root _SERVER", "There's a _SERVER folder that's not in " + "the src/ folder. Only files that are in src/ will actually appear in the " + "modpack, so you probably intended to put _SERVER in src/.")); } - if (new File(inputDir, "mods").exists()) { + if (new File(packDir, "mods").exists()) { problems.add(new Problem("Root mods", "There's a mods folder that's not in " + "the src/ folder. Only files that are in src/ will actually appear in the " + "modpack.")); } - if (new File(inputDir, "config").exists()) { + if (new File(packDir, "config").exists()) { problems.add(new Problem("Root mods", "There's a config folder that's not in " + "the src/ folder. Only files that are in src/ will actually appear in the " + "modpack.")); } - if (new File(inputDir, "version.json").exists()) { + if (new File(packDir, "version.json").exists()) { problems.add(new Problem("Legacy version.json", "There's a version.json file in the " + "project directory. If you are upgrading your modpack from an old version " + "of the launcher, then you should be able to delete version.json as it is " + @@ -83,7 +84,7 @@ public class ProblemChecker implements Callable>, ProgressObservab @Override public String getStatus() { - return status; + return "Checking for problems..."; } private static boolean hasFiles(File dir) { diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ServerDeployer.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/ServerDeploy.java similarity index 83% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ServerDeployer.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/ServerDeploy.java index a3aeec5..d392833 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ServerDeployer.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/ServerDeploy.java @@ -4,13 +4,13 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.compile; +package com.skcraft.launcher.creator.controller.task; import com.skcraft.concurrency.ProgressObservable; import com.skcraft.launcher.LauncherException; import com.skcraft.launcher.LauncherUtils; import com.skcraft.launcher.builder.ServerCopyExport; -import com.skcraft.launcher.buildtools.compile.DeployServerDialog.DeployOptions; +import com.skcraft.launcher.creator.dialog.DeployServerDialog.DeployOptions; import java.io.File; import java.io.IOException; @@ -18,18 +18,18 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; -public class ServerDeployer implements Callable, ProgressObservable { +public class ServerDeploy implements Callable, ProgressObservable { private final File srcDir; private final DeployOptions options; - public ServerDeployer(File srcDir, DeployOptions options) { + public ServerDeploy(File srcDir, DeployOptions options) { this.srcDir = srcDir; this.options = options; } @Override - public ServerDeployer call() throws Exception { + public ServerDeploy call() throws Exception { File modsDir = new File(options.getDestDir(), "mods"); if (options.isCleanMods() && modsDir.isDirectory()) { diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/TestLauncher.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/TestLauncher.java new file mode 100644 index 0000000..f96e983 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/controller/task/TestLauncher.java @@ -0,0 +1,81 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.controller.task; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.skcraft.concurrency.ProgressObservable; +import com.skcraft.launcher.Instance; +import com.skcraft.launcher.InstanceList; +import com.skcraft.launcher.Launcher; +import com.skcraft.launcher.auth.Session; +import com.skcraft.launcher.launch.LaunchOptions; +import com.skcraft.launcher.launch.LaunchOptions.UpdatePolicy; +import com.skcraft.launcher.swing.SwingHelper; + +import java.awt.*; +import java.util.List; + +public class TestLauncher implements Function, ProgressObservable { + + private final Launcher launcher; + private final Window window; + private final String id; + private final Session session; + + public TestLauncher(Launcher launcher, Window window, String id, Session session) { + this.launcher = launcher; + this.window = window; + this.id = id; + this.session = session; + } + + private Optional findInstance(List instances) { + for (Instance instance : instances) { + if (instance.getName().equals(id)) { + return Optional.fromNullable(instance); + } + } + + return Optional.absent(); + } + + @Override + public Instance apply(InstanceList instanceList) { + Optional optional = findInstance(instanceList.getInstances()); + + if (optional.isPresent()) { + LaunchOptions options = new LaunchOptions.Builder() + .setInstance(optional.get()) + .setUpdatePolicy(UpdatePolicy.ALWAYS_UPDATE) + .setWindow(window) + .setSession(session) + .build(); + + launcher.getLaunchSupervisor().launch(options); + + return optional.get(); + } else { + SwingHelper.showErrorDialog(window, + "After generating the necessary files, it appears the modpack can't be found in the " + + "launcher. Did you change modpack.json while the launcher was launching?", "Launch Error"); + + return null; + } + } + + @Override + public double getProgress() { + return -1; + } + + @Override + public String getStatus() { + return "Launching the game..."; + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/AboutDialog.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/AboutDialog.java new file mode 100644 index 0000000..dc1468a --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/AboutDialog.java @@ -0,0 +1,77 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.dialog; + +import com.skcraft.launcher.LauncherUtils; +import com.skcraft.launcher.creator.Creator; +import com.skcraft.launcher.swing.SwingHelper; +import lombok.extern.java.Log; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.util.Properties; +import java.util.logging.Level; + +@Log +public class AboutDialog extends JDialog { + + private String version; + + public AboutDialog(Window parent) { + super(parent, "About", ModalityType.DOCUMENT_MODAL); + + try { + Properties properties = LauncherUtils.loadProperties(Creator.class, "creator.properties", "com.skcraft.creator.propertiesFile"); + version = properties.getProperty("version", "????"); + } catch (IOException e) { + log.log(Level.WARNING, "Failed to get version", e); + version = "????"; + } + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + setResizable(false); + pack(); + setLocationRelativeTo(parent); + } + + private void initComponents() { + JPanel container = new JPanel(); + container.setLayout(new MigLayout("insets dialog")); + + container.add(new JLabel(SwingHelper.readImageIcon(Creator.class, "about_header.png")), "dock north"); + container.add(new JLabel("Version " + version), "wrap"); + container.add(new JLabel("Licensed under GNU General Public License, version 3."), "wrap, gapbottom unrel"); + container.add(new JLabel("Created by the SKCraft team. Visit our website!"), "wrap, gapbottom unrel"); + + JButton okButton = new JButton("OK"); + JButton sourceCodeButton = new JButton("Source Code"); + JButton skCraftButton = new JButton("Website"); + + container.add(sourceCodeButton, "span, split 3, sizegroup bttn"); + container.add(skCraftButton, "sizegroup bttn"); + container.add(okButton, "tag ok, sizegroup bttn"); + + add(container, BorderLayout.CENTER); + + getRootPane().setDefaultButton(okButton); + getRootPane().registerKeyboardAction(e -> okButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + + okButton.addActionListener(e -> dispose()); + sourceCodeButton.addActionListener(e -> SwingHelper.openURL("https://github.com/SKCraft/Launcher", this)); + skCraftButton.addActionListener(e -> SwingHelper.openURL("http://www.skcraft.com", this)); + } + + public static void showAboutDialog(Window parent) { + AboutDialog dialog = new AboutDialog(parent); + dialog.setVisible(true); + } +} + diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/BuildDialog.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/BuildDialog.java similarity index 77% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/BuildDialog.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/BuildDialog.java index 0ff94a6..3a8a036 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/BuildDialog.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/BuildDialog.java @@ -4,18 +4,18 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.compile; +package com.skcraft.launcher.creator.dialog; import com.skcraft.launcher.swing.DirectoryField; import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.swing.TextFieldPopupMenu; import lombok.Data; import lombok.Getter; import net.miginfocom.swing.MigLayout; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; import java.io.File; public class BuildDialog extends JDialog { @@ -23,7 +23,6 @@ public class BuildDialog extends JDialog { private final DirectoryField destDirField = new DirectoryField(); private final JTextField versionText = new JTextField(20); private final JTextField manifestFilenameText = new JTextField(30); - private final JCheckBox cleanCheck = new JCheckBox("Delete previously generated files first"); @Getter private BuildOptions options; @@ -38,6 +37,9 @@ public class BuildDialog extends JDialog { } private void initComponents() { + versionText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + manifestFilenameText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + JPanel container = new JPanel(); container.setLayout(new MigLayout("insets dialog")); @@ -50,9 +52,7 @@ public class BuildDialog extends JDialog { container.add(new JLabel("Output Directory:")); container.add(destDirField, "span"); - container.add(cleanCheck, "span, gapbottom unrel"); - - JButton buildButton = new JButton("Build..."); + JButton buildButton = new JButton("Build"); JButton cancelButton = new JButton("Cancel"); container.add(buildButton, "tag ok, span, split 2, sizegroup bttn"); @@ -60,19 +60,11 @@ public class BuildDialog extends JDialog { add(container, BorderLayout.CENTER); - buildButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - returnValue(); - } - }); + getRootPane().setDefaultButton(buildButton); + getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - cancelButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }); + buildButton.addActionListener(e -> returnValue()); + cancelButton.addActionListener(e -> dispose()); } private void returnValue() { @@ -94,7 +86,7 @@ public class BuildDialog extends JDialog { return; } - options = new BuildOptions(version, manifestFilename, cleanCheck.isSelected(), new File(destDirField.getPath())); + options = new BuildOptions(version, manifestFilename, new File(destDirField.getPath())); dispose(); } @@ -111,7 +103,6 @@ public class BuildDialog extends JDialog { public static class BuildOptions { private final String version; private final String manifestFilename; - private final boolean clean; private final File destDir; } diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/BuilderConfigDialog.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/BuilderConfigDialog.java similarity index 63% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/project/BuilderConfigDialog.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/BuilderConfigDialog.java index 56193d0..36b99f3 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/BuilderConfigDialog.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/BuilderConfigDialog.java @@ -4,25 +4,24 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.project; +package com.skcraft.launcher.creator.dialog; -import com.google.common.base.Joiner; +import com.google.common.base.Strings; import com.skcraft.launcher.builder.BuilderConfig; import com.skcraft.launcher.builder.FeaturePattern; import com.skcraft.launcher.builder.FnPatternList; +import com.skcraft.launcher.creator.model.swing.FeaturePatternTableModel; import com.skcraft.launcher.model.modpack.LaunchModifier; import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.swing.TextFieldPopupMenu; import net.miginfocom.swing.MigLayout; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; public class BuilderConfigDialog extends JDialog { - private static final Joiner NEW_LINE_JOINER = Joiner.on("\n"); - private final JTextField nameText = new JTextField(20); private final JTextField titleText = new JTextField(30); private final JTextField gameVersionText = new JTextField(10); @@ -36,7 +35,7 @@ public class BuilderConfigDialog extends JDialog { private boolean saved = false; public BuilderConfigDialog(Window parent, BuilderConfig config) { - super(parent, "Edit modpack.json", ModalityType.DOCUMENT_MODAL); + super(parent, "Modpack Properties", ModalityType.DOCUMENT_MODAL); this.config = config; @@ -47,9 +46,17 @@ public class BuilderConfigDialog extends JDialog { setLocationRelativeTo(parent); copyFrom(); + + nameText.requestFocus(); } private void initComponents() { + nameText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + titleText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + gameVersionText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + launchFlagsArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + userFilesIncludeArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + launchFlagsArea.setFont(nameText.getFont()); userFilesIncludeArea.setFont(nameText.getFont()); userFilesExcludeArea.setFont(nameText.getFont()); @@ -72,33 +79,28 @@ public class BuilderConfigDialog extends JDialog { container.add(saveButton, "tag ok, span, split 2, sizegroup bttn"); container.add(cancelButton, "tag cancel, sizegroup bttn"); + getRootPane().setDefaultButton(saveButton); + getRootPane().registerKeyboardAction(event -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + add(container, BorderLayout.CENTER); - saveButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (nameText.getText().trim().isEmpty()) { - SwingHelper.showErrorDialog(BuilderConfigDialog.this, "The 'Name' field cannot be empty.", "Input Error"); - return; - } - - if (gameVersionText.getText().trim().isEmpty()) { - SwingHelper.showErrorDialog(BuilderConfigDialog.this, "The 'Game Version' field must be a Minecraft version.", "Input Error"); - return; - } - - copyTo(); - saved = true; - dispose(); + saveButton.addActionListener(e -> { + if (nameText.getText().trim().isEmpty()) { + SwingHelper.showErrorDialog(BuilderConfigDialog.this, "The 'Name' field cannot be empty.", "Input Error"); + return; } + + if (gameVersionText.getText().trim().isEmpty()) { + SwingHelper.showErrorDialog(BuilderConfigDialog.this, "The 'Game Version' field must be a Minecraft version.", "Input Error"); + return; + } + + copyTo(); + saved = true; + dispose(); }); - cancelButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }); + cancelButton.addActionListener(e -> dispose()); } private JPanel createMainPanel() { @@ -158,42 +160,33 @@ public class BuilderConfigDialog extends JDialog { container.add(SwingHelper.wrapScrollPane(featuresTable), "grow, w 10:100:null, gaptop 10"); - newButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - FeaturePattern pattern = new FeaturePattern(); - if (FeaturePatternDialog.showEditor(BuilderConfigDialog.this, pattern)) { - featuresModel.addFeature(pattern); - } + newButton.addActionListener(e -> { + FeaturePattern pattern = new FeaturePattern(); + if (FeaturePatternDialog.showEditor(BuilderConfigDialog.this, pattern)) { + featuresModel.addFeature(pattern); } }); - editButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - int index = featuresTable.getSelectedRow(); - if (index > -1) { - FeaturePattern pattern = featuresModel.getFeature(index); - FeaturePatternDialog.showEditor(BuilderConfigDialog.this, pattern); - featuresModel.fireTableDataChanged(); - } else { - SwingHelper.showErrorDialog(BuilderConfigDialog.this, "Select a feature first.", "No Selection"); - } + editButton.addActionListener(e -> { + int index = featuresTable.getSelectedRow(); + if (index > -1) { + FeaturePattern pattern = featuresModel.getFeature(index); + FeaturePatternDialog.showEditor(BuilderConfigDialog.this, pattern); + featuresModel.fireTableDataChanged(); + } else { + SwingHelper.showErrorDialog(BuilderConfigDialog.this, "Select a feature first.", "No Selection"); } }); - deleteButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - int index = featuresTable.getSelectedRow(); - if (index > -1) { - FeaturePattern pattern = featuresModel.getFeature(index); - if (SwingHelper.confirmDialog(BuilderConfigDialog.this, "Are you sure that you want to delete '" + pattern.getFeature().getName() + "'?", "Delete")) { - featuresModel.removeFeature(index); - } - } else { - SwingHelper.showErrorDialog(BuilderConfigDialog.this, "Select a feature first.", "No Selection"); + deleteButton.addActionListener(e -> { + int index = featuresTable.getSelectedRow(); + if (index > -1) { + FeaturePattern pattern = featuresModel.getFeature(index); + if (SwingHelper.confirmDialog(BuilderConfigDialog.this, "Are you sure that you want to delete '" + pattern.getFeature().getName() + "'?", "Delete")) { + featuresModel.removeFeature(index); } + } else { + SwingHelper.showErrorDialog(BuilderConfigDialog.this, "Select a feature first.", "No Selection"); } }); @@ -204,16 +197,16 @@ public class BuilderConfigDialog extends JDialog { SwingHelper.setTextAndResetCaret(nameText, config.getName()); SwingHelper.setTextAndResetCaret(titleText, config.getTitle()); SwingHelper.setTextAndResetCaret(gameVersionText, config.getGameVersion()); - SwingHelper.setTextAndResetCaret(launchFlagsArea, NEW_LINE_JOINER.join(config.getLaunchModifier().getFlags())); - SwingHelper.setTextAndResetCaret(userFilesIncludeArea, NEW_LINE_JOINER.join(config.getUserFiles().getInclude())); - SwingHelper.setTextAndResetCaret(userFilesExcludeArea, NEW_LINE_JOINER.join(config.getUserFiles().getExclude())); + SwingHelper.setTextAndResetCaret(launchFlagsArea, SwingHelper.listToLines(config.getLaunchModifier().getFlags())); + SwingHelper.setTextAndResetCaret(userFilesIncludeArea, SwingHelper.listToLines(config.getUserFiles().getInclude())); + SwingHelper.setTextAndResetCaret(userFilesExcludeArea, SwingHelper.listToLines(config.getUserFiles().getExclude())); featuresModel = new FeaturePatternTableModel(config.getFeatures()); featuresTable.setModel(featuresModel); } private void copyTo() { config.setName(nameText.getText().trim()); - config.setTitle(titleText.getText().trim()); + config.setTitle(Strings.emptyToNull(titleText.getText().trim())); config.setGameVersion(gameVersionText.getText().trim()); LaunchModifier launchModifier = config.getLaunchModifier(); diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/DeployServerDialog.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/DeployServerDialog.java similarity index 78% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/DeployServerDialog.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/DeployServerDialog.java index 3836a9b..b2d2e82 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/DeployServerDialog.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/DeployServerDialog.java @@ -4,7 +4,7 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.compile; +package com.skcraft.launcher.creator.dialog; import com.skcraft.launcher.swing.DirectoryField; import com.skcraft.launcher.swing.SwingHelper; @@ -14,8 +14,7 @@ import net.miginfocom.swing.MigLayout; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; import java.io.File; public class DeployServerDialog extends JDialog { @@ -46,7 +45,7 @@ public class DeployServerDialog extends JDialog { container.add(cleanModsCheck, "span, gapbottom unrel"); - JButton buildButton = new JButton("Deploy..."); + JButton buildButton = new JButton("Deploy"); JButton cancelButton = new JButton("Cancel"); container.add(buildButton, "tag ok, span, split 2, sizegroup bttn"); @@ -54,19 +53,11 @@ public class DeployServerDialog extends JDialog { add(container, BorderLayout.CENTER); - buildButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - returnValue(); - } - }); + getRootPane().setDefaultButton(buildButton); + getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); - cancelButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }); + buildButton.addActionListener(e -> returnValue()); + cancelButton.addActionListener(e -> dispose()); } private void returnValue() { @@ -88,8 +79,11 @@ public class DeployServerDialog extends JDialog { dispose(); } - public static DeployOptions showDeployDialog(Window parent) { + public static DeployOptions showDeployDialog(Window parent, File destDir) { DeployServerDialog dialog = new DeployServerDialog(parent); + if (destDir != null) { + dialog.destDirField.setPath(destDir.getAbsolutePath()); + } dialog.setVisible(true); return dialog.getOptions(); } diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternDialog.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/FeaturePatternDialog.java similarity index 74% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternDialog.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/FeaturePatternDialog.java index 8c3a682..f57a783 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternDialog.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/FeaturePatternDialog.java @@ -4,20 +4,21 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.project; +package com.skcraft.launcher.creator.dialog; import com.google.common.base.Joiner; import com.skcraft.launcher.builder.FeaturePattern; import com.skcraft.launcher.builder.FnPatternList; +import com.skcraft.launcher.creator.model.swing.RecommendationComboBoxModel; import com.skcraft.launcher.model.modpack.Feature; import com.skcraft.launcher.model.modpack.Feature.Recommendation; import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.swing.TextFieldPopupMenu; import net.miginfocom.swing.MigLayout; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; public class FeaturePatternDialog extends JDialog { @@ -48,6 +49,11 @@ public class FeaturePatternDialog extends JDialog { } private void initComponents() { + nameText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + descArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + includeArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + excludeArea.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + descArea.setFont(nameText.getFont()); includeArea.setFont(nameText.getFont()); excludeArea.setFont(nameText.getFont()); @@ -78,38 +84,33 @@ public class FeaturePatternDialog extends JDialog { container.add(okButton, "tag ok, span, split 2, sizegroup bttn"); container.add(cancelButton, "tag cancel, sizegroup bttn"); + getRootPane().setDefaultButton(okButton); + getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + add(container, BorderLayout.CENTER); - okButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (nameText.getText().trim().isEmpty()) { - SwingHelper.showErrorDialog(FeaturePatternDialog.this, "The 'Feature Name' field cannot be empty.", "Input Error"); - return; - } - - if (descArea.getText().trim().isEmpty()) { - SwingHelper.showErrorDialog(FeaturePatternDialog.this, "The 'Description' field cannot be empty.", "Input Error"); - return; - } - - if (includeArea.getText().trim().isEmpty()) { - SwingHelper.showErrorDialog(FeaturePatternDialog.this, "The 'Include Patterns' field cannot be empty.", "Input Error"); - return; - } - - copyTo(); - saved = true; - dispose(); + okButton.addActionListener(e -> { + if (nameText.getText().trim().isEmpty()) { + SwingHelper.showErrorDialog(FeaturePatternDialog.this, "The 'Feature Name' field cannot be empty.", "Input Error"); + return; } + + if (descArea.getText().trim().isEmpty()) { + SwingHelper.showErrorDialog(FeaturePatternDialog.this, "The 'Description' field cannot be empty.", "Input Error"); + return; + } + + if (includeArea.getText().trim().isEmpty()) { + SwingHelper.showErrorDialog(FeaturePatternDialog.this, "The 'Include Patterns' field cannot be empty.", "Input Error"); + return; + } + + copyTo(); + saved = true; + dispose(); }); - cancelButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }); + cancelButton.addActionListener(e -> dispose()); } private void copyFrom() { diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTable.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/FeaturePatternTable.java similarity index 52% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTable.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/FeaturePatternTable.java index 9e69caf..333699a 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTable.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/FeaturePatternTable.java @@ -4,21 +4,13 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.project; +package com.skcraft.launcher.creator.dialog; + +import com.skcraft.launcher.swing.DefaultTable; -import javax.swing.*; import javax.swing.table.TableModel; -import java.awt.*; -class FeaturePatternTable extends JTable { - - public FeaturePatternTable() { - setShowGrid(false); - setRowHeight((int) (Math.max(getRowHeight(), new JCheckBox().getPreferredSize().getHeight() - 2))); - setIntercellSpacing(new Dimension(0, 0)); - setFillsViewportHeight(true); - setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - } +class FeaturePatternTable extends DefaultTable { @Override public void setModel(TableModel dataModel) { diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/GenerateListingDialog.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/GenerateListingDialog.java new file mode 100644 index 0000000..d778271 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/GenerateListingDialog.java @@ -0,0 +1,77 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.dialog; + +import com.skcraft.launcher.creator.Creator; +import com.skcraft.launcher.creator.model.swing.ListingType; +import com.skcraft.launcher.creator.model.swing.ListingTypeComboBoxModel; +import com.skcraft.launcher.swing.DefaultTable; +import com.skcraft.launcher.swing.DirectoryField; +import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.swing.TableColumnAdjuster; +import lombok.Getter; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +public class GenerateListingDialog extends JDialog { + + @Getter private final DirectoryField destDirField = new DirectoryField(); + @Getter private final JComboBox listingTypeCombo = new JComboBox<>(new ListingTypeComboBoxModel()); + @Getter private final JTable manifestsTable = new DefaultTable(); + @Getter private final JLabel gameKeyWarning = new JLabel("Selected listing type won't support adding modpacks using 'game keys'.", SwingHelper.readImageIcon(Creator.class, "warning_icon.png"), SwingConstants.LEFT); + + @Getter private final JButton editManifestButton = new JButton("Modify..."); + + @Getter private final JButton generateButton = new JButton("Generate"); + @Getter private final JButton cancelButton = new JButton("Cancel"); + + @Getter private final TableColumnAdjuster manifestsTableAdjuster = new TableColumnAdjuster(manifestsTable); + + public GenerateListingDialog(Window parent) { + super(parent, "Generate Package Listing", ModalityType.DOCUMENT_MODAL); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + pack(); + setLocationRelativeTo(parent); + } + + private void initComponents() { + manifestsTableAdjuster.adjustColumns(); + manifestsTableAdjuster.setDynamicAdjustment(true); + + manifestsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); + manifestsTable.setAutoCreateRowSorter(true); + + JPanel container = new JPanel(); + container.setLayout(new MigLayout("insets dialog, fill", "[grow 0][grow 100]")); + + container.add(new JLabel("Output Directory:")); + container.add(destDirField, "span"); + + container.add(new JLabel("Package Listing Type:")); + container.add(listingTypeCombo, "span"); + container.add(gameKeyWarning, "span, skip 1, hidemode 3"); + + container.add(new JLabel("Modpacks to Include:"), "span, gaptop unrel"); + container.add(SwingHelper.wrapScrollPane(manifestsTable), "grow, pushy, span, w 500:650, h 170"); + container.add(editManifestButton, "gapbottom unrel, span, split 2"); + container.add(new JLabel("Previously-selected modpacks and those in the _upload directory are the available options."), "gapbottom unrel"); + + container.add(generateButton, "tag ok, span, split 2, sizegroup bttn"); + container.add(cancelButton, "tag cancel, sizegroup bttn"); + + add(container, BorderLayout.CENTER); + + getRootPane().setDefaultButton(generateButton); + getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/ManifestEntryDialog.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/ManifestEntryDialog.java new file mode 100644 index 0000000..60f3cab --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/ManifestEntryDialog.java @@ -0,0 +1,64 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.dialog; + +import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.swing.TextFieldPopupMenu; +import lombok.Getter; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +public class ManifestEntryDialog extends JDialog { + + @Getter private final JSpinner prioritySpinner = new JSpinner(); + @Getter private final JTextArea gameKeysText = new JTextArea(5, 30); + @Getter private final JCheckBox includeCheck = new JCheckBox("Include in package listing"); + + @Getter private final JButton okButton = new JButton("OK"); + @Getter private final JButton cancelButton = new JButton("Cancel"); + + public ManifestEntryDialog(Window parent) { + super(parent, "Modpack Entry", ModalityType.DOCUMENT_MODAL); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + setResizable(false); + pack(); + setLocationRelativeTo(parent); + } + + private void initComponents() { + gameKeysText.setFont(prioritySpinner.getFont()); + + prioritySpinner.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + gameKeysText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + + JPanel container = new JPanel(); + container.setLayout(new MigLayout("insets dialog")); + + container.add(includeCheck, "span, gapbottom unrel"); + + container.add(new JLabel("Priority:")); + container.add(prioritySpinner, "span, split 2, w 50"); + container.add(new JLabel("(Greater is higher)")); + + container.add(new JLabel("Game Keys:")); + container.add(SwingHelper.wrapScrollPane(gameKeysText), "span"); + + container.add(okButton, "tag ok, span, split 2, sizegroup bttn, gaptop unrel"); + container.add(cancelButton, "tag cancel, sizegroup bttn"); + + add(container, BorderLayout.CENTER); + + getRootPane().setDefaultButton(okButton); + getRootPane().registerKeyboardAction(e -> cancelButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/PackManagerFrame.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/PackManagerFrame.java new file mode 100644 index 0000000..a80a60f --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/PackManagerFrame.java @@ -0,0 +1,175 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.dialog; + +import com.skcraft.launcher.creator.Creator; +import com.skcraft.launcher.swing.DefaultTable; +import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.swing.TableColumnAdjuster; +import lombok.Getter; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +public class PackManagerFrame extends JFrame { + + @Getter private final JButton newPackButton = new JButton("New Pack", SwingHelper.readImageIcon(Creator.class, "new.png")); + @Getter private final JButton importButton = new JButton("Add Existing", SwingHelper.readImageIcon(Creator.class, "import.png")); + @Getter private final JButton editConfigButton = new JButton("Modify", SwingHelper.readImageIcon(Creator.class, "edit.png")); + @Getter private final JButton openFolderButton = new JButton("Open", SwingHelper.readImageIcon(Creator.class, "open_folder.png")); + @Getter private final JButton checkProblemsButton = new JButton("Check", SwingHelper.readImageIcon(Creator.class, "check.png")); + @Getter private final JButton testButton = new JButton("Test", SwingHelper.readImageIcon(Creator.class, "test.png")); + @Getter private final JButton buildButton = new JButton("Build", SwingHelper.readImageIcon(Creator.class, "build.png")); + + @Getter private final JMenuItem newPackMenuItem = new JMenuItem("New Pack..."); + @Getter private final JMenuItem newPackAtLocationMenuItem = new JMenuItem("New Pack at Location..."); + @Getter private final JMenuItem importPackMenuItem = new JMenuItem("Add Existing Pack..."); + @Getter private final JMenuItem changePackLocationMenuItem = new JMenuItem("Change Pack Location..."); + @Getter private final JMenuItem refreshMenuItem = new JMenuItem("Reload Workspace"); + @Getter private final JMenuItem removePackItem = new JMenuItem("Remove Pack..."); + @Getter private final JMenuItem deletePackItem = new JMenuItem("Delete Pack Forever..."); + @Getter private final JMenuItem quitMenuItem = new JMenuItem("Exit"); + @Getter private final JMenuItem editConfigMenuItem = new JMenuItem("Edit modpack.json..."); + @Getter private final JMenuItem openFolderMenuItem = new JMenuItem("Open Directory"); + @Getter private final JMenuItem checkProblemsMenuItem = new JMenuItem("Scan for Problems..."); + @Getter private final JMenuItem testMenuItem = new JMenuItem("Test Pack"); + @Getter private final JMenuItem optionsMenuItem = new JMenuItem("Test Launcher Options..."); + @Getter private final JMenuItem clearInstanceMenuItem = new JMenuItem("Delete Test Launcher Instances"); + @Getter private final JMenuItem clearWebRootMenuItem = new JMenuItem("Empty Test Web Server"); + @Getter private final JMenuItem buildMenuItem = new JMenuItem("Build Pack..."); + @Getter private final JMenuItem deployServerMenuItem = new JMenuItem("Deploy Server..."); + @Getter private final JMenuItem generatePackagesMenuItem = new JMenuItem("Generate packages.json..."); + @Getter private final JMenuItem openOutputFolderMenuItem = new JMenuItem("Open Upload Folder"); + @Getter private final JMenuItem openConsoleMenuItem = new JMenuItem("Open Console"); + @Getter private final JMenuItem docsMenuItem = new JMenuItem("Documentation"); + @Getter private final JMenuItem aboutMenuItem = new JMenuItem("About"); + + @Getter private final JTable packTable = new DefaultTable(); + + public PackManagerFrame() { + super("Modpack Creator"); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + initMenu(); + pack(); + setLocationRelativeTo(null); + + SwingHelper.setIconImage(this, Creator.class, "icon.png"); + } + + private void initComponents() { + TableColumnAdjuster adjuster = new TableColumnAdjuster(packTable); + adjuster.adjustColumns(); + adjuster.setDynamicAdjustment(true); + + packTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); + packTable.setAutoCreateRowSorter(true); + + JPanel container = new JPanel(); + container.setLayout(new MigLayout("fill, wrap 1")); + + container.add(createToolbar(), "dock north"); + container.add(SwingHelper.wrapScrollPane(packTable), "grow, span, w null:800:null"); + + add(container, BorderLayout.CENTER); + } + + private JToolBar createToolbar() { + JToolBar toolBar = new JToolBar("Toolbar"); + + toolBar.setFloatable(false); + + toolBar.add(newPackButton); + toolBar.add(importButton); + toolBar.addSeparator(); + toolBar.add(editConfigButton); + toolBar.add(openFolderButton); + toolBar.add(checkProblemsButton); + toolBar.addSeparator(); + toolBar.add(testButton); + toolBar.add(buildButton); + + return toolBar; + } + + private void initMenu() { + newPackMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK)); + newPackAtLocationMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK | Event.SHIFT_MASK)); + editConfigMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, Event.CTRL_MASK)); + openFolderMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Event.CTRL_MASK | Event.SHIFT_MASK)); + testMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0)); + buildMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F10, Event.SHIFT_MASK)); + deployServerMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F9, Event.SHIFT_MASK)); + docsMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); + + JMenuBar menuBar; + JMenu menu; + + menuBar = new JMenuBar(); + + menu = new JMenu("File"); + menu.setMnemonic('f'); + menuBar.add(menu); + menu.add(newPackMenuItem); + menu.add(newPackAtLocationMenuItem); + menu.add(importPackMenuItem); + menu.addSeparator(); + menu.add(changePackLocationMenuItem); + menu.add(removePackItem); + menu.add(deletePackItem); + menu.addSeparator(); + menu.add(refreshMenuItem); + menu.addSeparator(); + menu.add(quitMenuItem); + + menu = new JMenu("Edit"); + menu.setMnemonic('e'); + menuBar.add(menu); + menu.add(editConfigMenuItem); + menu.add(openFolderMenuItem); + menu.addSeparator(); + menu.add(checkProblemsMenuItem); + + menu = new JMenu("Test"); + menu.setMnemonic('t'); + menuBar.add(menu); + menu.add(testMenuItem); + menu.addSeparator(); + menu.add(optionsMenuItem); + menu.addSeparator(); + menu.add(clearInstanceMenuItem); + menu.add(clearWebRootMenuItem); + + menu = new JMenu("Build"); + menu.setMnemonic('b'); + menuBar.add(menu); + menu.add(buildMenuItem); + menu.add(deployServerMenuItem); + menu.addSeparator(); + menu.add(generatePackagesMenuItem); + menu.addSeparator(); + menu.add(openOutputFolderMenuItem); + + menu = new JMenu("Tools"); + menu.setMnemonic('t'); + menuBar.add(menu); + menu.add(openConsoleMenuItem); + + menu = new JMenu("Help"); + menu.setMnemonic('h'); + menuBar.add(menu); + menu.add(docsMenuItem); + menu.addSeparator(); + menu.add(aboutMenuItem); + + setJMenuBar(menuBar); + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTable.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/ProblemTable.java similarity index 55% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTable.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/ProblemTable.java index d73f442..0cdf8bd 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTable.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/ProblemTable.java @@ -4,21 +4,17 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.compile; +package com.skcraft.launcher.creator.dialog; + +import com.skcraft.launcher.swing.DefaultTable; -import javax.swing.*; import javax.swing.table.TableModel; -import java.awt.*; -class ProblemTable extends JTable { +class ProblemTable extends DefaultTable { public ProblemTable() { - setShowGrid(false); - setRowHeight((int) (Math.max(getRowHeight(), new JCheckBox().getPreferredSize().getHeight() - 2))); - setIntercellSpacing(new Dimension(0, 0)); - setFillsViewportHeight(true); + super(); setTableHeader(null); - setSelectionMode(ListSelectionModel.SINGLE_SELECTION); } @Override diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemViewer.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/ProblemViewer.java similarity index 71% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemViewer.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/ProblemViewer.java index d20bcca..03f0abe 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemViewer.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/ProblemViewer.java @@ -4,17 +4,17 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.compile; +package com.skcraft.launcher.creator.dialog; +import com.skcraft.launcher.creator.model.creator.Problem; +import com.skcraft.launcher.creator.model.swing.ProblemTableModel; import com.skcraft.launcher.swing.SwingHelper; +import com.skcraft.launcher.swing.TextFieldPopupMenu; import net.miginfocom.swing.MigLayout; import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; import java.util.List; public class ProblemViewer extends JDialog { @@ -37,6 +37,8 @@ public class ProblemViewer extends JDialog { } private void initComponents() { + explanationText.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); + explanationText.setFont(new JTextField().getFont()); explanationText.setEditable(false); explanationText.setLineWrap(true); @@ -59,21 +61,16 @@ public class ProblemViewer extends JDialog { add(container, BorderLayout.CENTER); - problemTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - Problem selected = problemTableModel.getProblem(problemTable.getSelectedRow()); - if (selected != null) { - SwingHelper.setTextAndResetCaret(explanationText, selected.getExplanation()); - } + getRootPane().setDefaultButton(closeButton); + getRootPane().registerKeyboardAction(e -> closeButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + + problemTable.getSelectionModel().addListSelectionListener(e -> { + Problem selected = problemTableModel.getProblem(problemTable.getSelectedRow()); + if (selected != null) { + SwingHelper.setTextAndResetCaret(explanationText, selected.getExplanation()); } }); - closeButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }); + closeButton.addActionListener(e -> dispose()); } } diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/WelcomeDialog.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/WelcomeDialog.java new file mode 100644 index 0000000..f1f2099 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/dialog/WelcomeDialog.java @@ -0,0 +1,70 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.dialog; + +import com.skcraft.launcher.creator.Creator; +import com.skcraft.launcher.creator.model.creator.RecentEntry; +import com.skcraft.launcher.creator.swing.BorderCellRenderer; +import com.skcraft.launcher.swing.SwingHelper; +import lombok.Getter; +import net.miginfocom.swing.MigLayout; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +public class WelcomeDialog extends JFrame { + + @Getter private final JButton newButton = new JButton("New Workspace...", SwingHelper.readImageIcon(Creator.class, "new.png")); + @Getter private final JButton openButton = new JButton("Open Workspace...", SwingHelper.readImageIcon(Creator.class, "open_folder.png")); + @Getter private final JButton helpButton = new JButton("Help"); + @Getter private final JButton aboutButton = new JButton("About"); + @Getter private final JButton quitButton = new JButton("Quit"); + @Getter private final JList recentList = new JList<>(); + + public WelcomeDialog() { + super("Modpack Creator"); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + setResizable(false); + pack(); + setLocationRelativeTo(null); + + SwingHelper.setIconImage(this, Creator.class, "icon.png"); + } + + private void initComponents() { + recentList.setCellRenderer(new BorderCellRenderer(BorderFactory.createEmptyBorder(5, 5, 5, 5))); + + JPanel container = new JPanel(); + container.setLayout(new MigLayout("insets 50 20")); + + container.add(new JLabel(SwingHelper.readImageIcon(Creator.class, "welcome_logo.png")), "wrap, gap 20 20, gapbottom 30"); + + container.add(newButton, "grow, gap 50 50, wrap"); + container.add(openButton, "grow, gap 50 50, wrap"); + + JScrollPane recentScrollPane = new JScrollPane(recentList); + recentScrollPane.setBorder(BorderFactory.createMatteBorder(0, 1, 0, 0, Color.LIGHT_GRAY)); + recentScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); + container.add(recentScrollPane, "dock east, w 280, h 390"); + + JPanel buttons = new JPanel(); + buttons.setLayout(new MigLayout("insets 20", "[][]push[]")); + buttons.add(helpButton); + buttons.add(aboutButton); + buttons.add(quitButton); + container.add(buttons, "dock south"); + + add(container, BorderLayout.CENTER); + + getRootPane().registerKeyboardAction(e -> quitButton.doClick(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); + } + + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/CreatorConfig.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/CreatorConfig.java new file mode 100644 index 0000000..7e852de --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/CreatorConfig.java @@ -0,0 +1,33 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.creator; + +import com.google.common.collect.Lists; +import lombok.Data; + +import java.util.List; + +@Data +public class CreatorConfig { + + private List recentEntries = Lists.newArrayList(); + + public void setRecentEntries(List recentEntries) { + this.recentEntries = recentEntries != null ? recentEntries : Lists.newArrayList(); + } + + @Override + public boolean equals(Object o) { + return super.equals(o); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/ManifestEntry.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/ManifestEntry.java new file mode 100644 index 0000000..bfe51b1 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/ManifestEntry.java @@ -0,0 +1,27 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.creator; + +import com.google.common.collect.Lists; +import com.skcraft.launcher.model.modpack.ManifestInfo; +import lombok.Data; + +import java.util.List; + +@Data +public class ManifestEntry implements Comparable { + + private boolean selected = false; + private ManifestInfo manifestInfo; + private List gameKeys = Lists.newArrayList(); + + @Override + public int compareTo(ManifestEntry o) { + return manifestInfo.compareTo(o.getManifestInfo()); + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/Pack.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/Pack.java new file mode 100644 index 0000000..035316a --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/Pack.java @@ -0,0 +1,67 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.creator; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.skcraft.launcher.builder.BuilderConfig; +import com.skcraft.launcher.builder.BuilderOptions; +import com.skcraft.launcher.creator.model.creator.Workspace; +import com.skcraft.launcher.persistence.Persistence; +import lombok.Data; + +import java.io.File; + +@Data +public class Pack { + + private String location; + @JsonIgnore private Workspace workspace; + @JsonIgnore private BuilderConfig cachedConfig; + + @JsonIgnore + public File getDirectory() { + File path = new File(location); + if (path.isAbsolute()) { + return path; + } else { + return new File(workspace.getDirectory(), location); + } + } + + @JsonIgnore + public File getLoadersDir() { + return new File(getDirectory(), "loaders"); + } + + @JsonIgnore + public File getSourceDir() { + return new File(getDirectory(), "src"); + } + + @JsonIgnore + public File getConfigFile() { + return new File(getDirectory(), BuilderOptions.DEFAULT_CONFIG_FILENAME); + } + + public void load() { + setCachedConfig(Persistence.read(getConfigFile(), BuilderConfig.class, true)); + getLoadersDir().mkdirs(); + getSourceDir().mkdirs(); + } + + public void createGuideFolders() { + new File(getSourceDir(), "config").mkdirs(); + new File(getSourceDir(), "mods").mkdirs(); + new File(getSourceDir(), "resourcepacks").mkdirs(); + } + + @JsonIgnore + public boolean isLoaded() { + return cachedConfig != null; + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/Problem.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/Problem.java similarity index 90% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/Problem.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/Problem.java index a2227ce..fcc56ef 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/Problem.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/Problem.java @@ -4,7 +4,7 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.compile; +package com.skcraft.launcher.creator.model.creator; import lombok.Data; diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/RecentEntry.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/RecentEntry.java new file mode 100644 index 0000000..7b1b244 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/RecentEntry.java @@ -0,0 +1,27 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.creator; + +import lombok.Data; + +import java.io.File; + +@Data +public class RecentEntry { + + private File path; + + public void setPath(File path) { + this.path = path != null ? path : new File("."); + } + + @Override + public String toString() { + return path.getAbsolutePath(); + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/Workspace.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/Workspace.java new file mode 100644 index 0000000..6b7b1f9 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/creator/Workspace.java @@ -0,0 +1,78 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.creator; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.google.common.collect.Lists; +import com.skcraft.launcher.creator.model.swing.ListingType; +import lombok.Data; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +@Data +public class Workspace { + + public static final String DIR_NAME = ".modpacks"; + public static final String FILENAME = "workspace.json"; + + @JsonIgnore private File directory; + private List packs = Lists.newArrayList(); + private List packageListingEntries = Lists.newArrayList(); + private ListingType packageListingType = ListingType.STATIC; + + public void setPacks(List packs) { + this.packs = packs != null ? packs : Lists.newArrayList(); + } + + public void setPackageListingEntries(List entries) { + this.packageListingEntries = entries != null ? entries : Lists.newArrayList(); + } + + public void setPackageListingType(ListingType packageListingType) { + this.packageListingType = packageListingType != null ? packageListingType : ListingType.STATIC; + } + + public boolean hasPack(File dir) { + for (Pack pack : packs) { + try { + if (pack.getDirectory().getCanonicalPath().equals(dir.getCanonicalPath())) { + return true; + } + } catch (IOException ignored) { + } + } + + return false; + } + + public void load() { + for (Pack pack : getPacks()) { + pack.setWorkspace(this); + } + } + + @Override + public boolean equals(Object o) { + return super.equals(o); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + public static File getDataDir(File workspaceDir) { + return new File(workspaceDir, DIR_NAME); + } + + public static File getWorkspaceFile(File workspaceDir) { + return new File(getDataDir(workspaceDir), FILENAME); + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTableModel.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/FeaturePatternTableModel.java similarity index 95% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTableModel.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/FeaturePatternTableModel.java index bf84cb3..5eb2879 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTableModel.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/FeaturePatternTableModel.java @@ -4,14 +4,14 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.project; +package com.skcraft.launcher.creator.model.swing; import com.skcraft.launcher.builder.FeaturePattern; import javax.swing.table.AbstractTableModel; import java.util.List; -class FeaturePatternTableModel extends AbstractTableModel { +public class FeaturePatternTableModel extends AbstractTableModel { private final List features; diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ListingType.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ListingType.java new file mode 100644 index 0000000..7ddd8eb --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ListingType.java @@ -0,0 +1,96 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.swing; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; +import com.skcraft.launcher.creator.model.creator.ManifestEntry; +import com.skcraft.launcher.model.modpack.ManifestInfo; +import com.skcraft.launcher.model.modpack.PackageList; +import com.skcraft.launcher.persistence.Persistence; +import lombok.Getter; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +public enum ListingType { + + STATIC("packages.json (static)", false, "packages.json") { + @Override + public String generate(List entries) throws IOException { + PackageList list = new PackageList(); + list.setPackages(Lists.newArrayList()); + list.setMinimumVersion(PackageList.MIN_VERSION); + for (ManifestEntry entry : entries) { + if (entry.getGameKeys().isEmpty()) { + list.getPackages().add(entry.getManifestInfo()); + } + } + return Persistence.writeValueAsString(list, Persistence.L2F_LIST_PRETTY_PRINTER); + } + }, + PHP("packages.php (requires PHP on web server) ", true, "packages.php") { + @Override + public String generate(List entries) throws IOException { + StringBuilder builder = new StringBuilder(); + builder.append(" keys = entry.getGameKeys(); + + if (!keys.isEmpty()) { + builder.append("if (count(array_intersect([").append(escapeKeys(keys)).append("], $keys)) > 0)\r\n"); + } + + builder.append("$packages[] = [\r\n"); + builder.append(" 'name' => '").append(escape(info.getName())).append("',\r\n"); + if (info.getTitle() != null) { + builder.append(" 'title' => '").append(escape(info.getTitle())).append("',\r\n"); + } + builder.append(" 'version' => '").append(escape(info.getVersion())).append("',\r\n"); + builder.append(" 'priority' => ").append(info.getPriority()).append(",\r\n"); + builder.append(" 'location' => '").append(escape(info.getLocation())).append("',\r\n"); + builder.append("];\r\n\r\n"); + } + + builder.append("$out = ['minimumVersion' => ").append(PackageList.MIN_VERSION).append(", 'packages' => $packages];\r\n"); + builder.append("header('Content-Type: text/plain; charset=utf-8');\r\n"); + builder.append("echo json_encode($out);\r\n"); + return builder.toString(); + } + + private String escape(String t) { + return t.replaceAll("[\\\\\"']", "\\$0").replace("\r", "\\r").replace("\n", "\\n"); + } + + private String escapeKeys(List list) { + return Joiner.on(", ").join(list.stream().map(s -> "'" + escape(s.toLowerCase()) + "'").collect(Collectors.toList())); + } + }; + + @Getter private final String name; + @Getter private final boolean gameKeyCompatible; + @Getter private final String filename; + + ListingType(String name, boolean gameKeyCompatible, String filename) { + this.name = name; + this.gameKeyCompatible = gameKeyCompatible; + this.filename = filename; + } + + @Override + public String toString() { + return name; + } + + public abstract String generate(List entries) throws IOException; + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ListingTypeComboBoxModel.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ListingTypeComboBoxModel.java new file mode 100644 index 0000000..2c1ca28 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ListingTypeComboBoxModel.java @@ -0,0 +1,35 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.swing; + +import javax.swing.*; + +public class ListingTypeComboBoxModel extends AbstractListModel implements ComboBoxModel { + + private ListingType selection = ListingType.STATIC; + + @Override + public void setSelectedItem(Object anItem) { + selection = (ListingType) anItem; + } + + @Override + public ListingType getSelectedItem() { + return selection; + } + + @Override + public int getSize() { + return ListingType.values().length; + } + + @Override + public ListingType getElementAt(int index) { + return ListingType.values()[index]; + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ManifestEntryTableModel.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ManifestEntryTableModel.java new file mode 100644 index 0000000..304fc2b --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ManifestEntryTableModel.java @@ -0,0 +1,122 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.swing; + +import com.google.common.base.Joiner; +import com.skcraft.launcher.creator.model.creator.ManifestEntry; + +import javax.swing.table.AbstractTableModel; +import java.util.List; + +public class ManifestEntryTableModel extends AbstractTableModel { + + private final Joiner GAME_KEY_JOINER = Joiner.on(", "); + private final List entries; + + public ManifestEntryTableModel(List entries) { + this.entries = entries; + } + + @Override + public String getColumnName(int columnIndex) { + switch (columnIndex) { + case 0: + return ""; + case 1: + return "Modpack"; + case 2: + return "Version"; + case 3: + return "Priority"; + case 4: + return "Location"; + case 5: + return "Game Keys"; + default: + return null; + } + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case 0: + return Boolean.class; + case 1: + return String.class; + case 2: + return String.class; + case 3: + return Integer.class; + case 4: + return String.class; + case 5: + return String.class; + default: + return null; + } + } + @Override + public void setValueAt(Object value, int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + entries.get(rowIndex).setSelected((Boolean) value); + break; + default: + break; + } + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + return true; + default: + return false; + } + } + + @Override + public int getRowCount() { + return entries.size(); + } + + @Override + public int getColumnCount() { + return 6; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + ManifestEntry entry = entries.get(rowIndex); + + switch (columnIndex) { + case 0: + return entry.isSelected(); + case 1: + String title = entry.getManifestInfo().getTitle(); + if (title != null) { + return title; + } else { + return entry.getManifestInfo().getName(); + } + case 2: + return entry.getManifestInfo().getVersion(); + case 3: + return entry.getManifestInfo().getPriority(); + case 4: + return entry.getManifestInfo().getLocation(); + case 5: + List gameKeys = entry.getGameKeys(); + return gameKeys != null ? GAME_KEY_JOINER.join(gameKeys) : ""; + default: + return null; + } + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/PackTableModel.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/PackTableModel.java new file mode 100644 index 0000000..11f9a06 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/PackTableModel.java @@ -0,0 +1,101 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.swing; + +import com.skcraft.launcher.Launcher; +import com.skcraft.launcher.builder.BuilderConfig; +import com.skcraft.launcher.creator.model.creator.Pack; +import com.skcraft.launcher.creator.dialog.ProblemViewer; +import com.skcraft.launcher.swing.SwingHelper; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import java.util.List; + +public class PackTableModel extends AbstractTableModel { + + private final ImageIcon instanceIcon; + private final ImageIcon warningIcon; + private final List packs; + + public PackTableModel(List packs) { + this.packs = packs; + + instanceIcon = SwingHelper.readImageIconScaled(Launcher.class, "instance_icon.png", 16, 16); + warningIcon = SwingHelper.readImageIcon(ProblemViewer.class, "warning_icon.png"); + } + + @Override + public String getColumnName(int columnIndex) { + switch (columnIndex) { + case 0: + return ""; + case 1: + return "Name"; + case 2: + return "Title"; + case 3: + return "Game Version"; + case 4: + return "Location"; + default: + return null; + } + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case 0: + return ImageIcon.class; + default: + return String.class; + } + } + + @Override + public void setValueAt(Object value, int rowIndex, int columnIndex) { + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public int getRowCount() { + return packs.size(); + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Pack pack = packs.get(rowIndex); + + BuilderConfig config = pack.getCachedConfig(); + + switch (columnIndex) { + case 0: + return config != null ? instanceIcon : warningIcon; + case 1: + return config != null ? config.getName() : ""; + case 2: + return config != null ? config.getTitle() : "?"; + case 3: + return config != null ? config.getGameVersion() : "?"; + case 4: + return pack.getLocation(); + default: + return null; + } + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTableModel.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ProblemTableModel.java similarity index 85% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTableModel.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ProblemTableModel.java index 3d290ab..28d01df 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/compile/ProblemTableModel.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/ProblemTableModel.java @@ -4,20 +4,22 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.compile; +package com.skcraft.launcher.creator.model.swing; +import com.skcraft.launcher.creator.Creator; +import com.skcraft.launcher.creator.model.creator.Problem; import com.skcraft.launcher.swing.SwingHelper; import javax.swing.*; import javax.swing.table.AbstractTableModel; import java.util.List; -class ProblemTableModel extends AbstractTableModel { +public class ProblemTableModel extends AbstractTableModel { private static final ImageIcon WARNING_ICON; static { - WARNING_ICON = SwingHelper.readImageIcon(ProblemTableModel.class, "warning_icon.png"); + WARNING_ICON = SwingHelper.readImageIcon(Creator.class, "warning_icon.png"); } private final List problems; diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/RecentListModel.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/RecentListModel.java new file mode 100644 index 0000000..2852147 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/RecentListModel.java @@ -0,0 +1,35 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.model.swing; + +import com.skcraft.launcher.creator.model.creator.RecentEntry; + +import javax.swing.*; +import java.util.List; + +public class RecentListModel extends AbstractListModel { + + private final List recentEntries; + + public RecentListModel(List recentEntries) { + this.recentEntries = recentEntries; + } + + @Override + public int getSize() { + return recentEntries.size(); + } + + @Override + public RecentEntry getElementAt(int index) { + return recentEntries.get(index); + } + + public void fireUpdate() { + fireContentsChanged(this, 0, Integer.MAX_VALUE); + } +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/RecommendationComboBoxModel.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/RecommendationComboBoxModel.java similarity index 84% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/project/RecommendationComboBoxModel.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/RecommendationComboBoxModel.java index 04bbd5f..2bd78c6 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/RecommendationComboBoxModel.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/model/swing/RecommendationComboBoxModel.java @@ -4,13 +4,13 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.project; +package com.skcraft.launcher.creator.model.swing; import com.skcraft.launcher.model.modpack.Feature.Recommendation; import javax.swing.*; -class RecommendationComboBoxModel extends AbstractListModel implements ComboBoxModel { +public class RecommendationComboBoxModel extends AbstractListModel implements ComboBoxModel { private Recommendation selection; diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LatestHandler.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/LatestHandler.java similarity index 96% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LatestHandler.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/server/LatestHandler.java index 19a805d..aa4f752 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LatestHandler.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/LatestHandler.java @@ -4,7 +4,7 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.http; +package com.skcraft.launcher.creator.server; import com.fasterxml.jackson.databind.ObjectMapper; import com.skcraft.launcher.selfupdate.LatestVersionInfo; diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/NewsHandler.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/NewsHandler.java similarity index 96% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/http/NewsHandler.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/server/NewsHandler.java index 763c5b2..2e5e607 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/NewsHandler.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/NewsHandler.java @@ -4,7 +4,7 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.http; +package com.skcraft.launcher.creator.server; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/PackagesHandler.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/PackagesHandler.java similarity index 98% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/http/PackagesHandler.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/server/PackagesHandler.java index 4ea72b6..6fb0b2d 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/PackagesHandler.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/PackagesHandler.java @@ -4,7 +4,7 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.http; +package com.skcraft.launcher.creator.server; import com.beust.jcommander.internal.Lists; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/server/TestServer.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/TestServer.java new file mode 100644 index 0000000..a2750e1 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/TestServer.java @@ -0,0 +1,32 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.server; + +import lombok.Getter; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; + +public class TestServer { + + @Getter private final Server server; + + public TestServer(Server server) { + this.server = server; + } + + public void start() throws Exception { + getServer().start(); + } + + public int getLocalPort() { + return ((ServerConnector) server.getConnectors()[0]).getLocalPort(); + } + + public void stop() throws Exception { + getServer().stop(); + } +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LocalHttpServerBuilder.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/TestServerBuilder.java similarity index 89% rename from build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LocalHttpServerBuilder.java rename to creator-tools/src/main/java/com/skcraft/launcher/creator/server/TestServerBuilder.java index ee10495..d8ad19d 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LocalHttpServerBuilder.java +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/server/TestServerBuilder.java @@ -4,7 +4,7 @@ * Please see LICENSE.txt for license information. */ -package com.skcraft.launcher.buildtools.http; +package com.skcraft.launcher.creator.server; import com.fasterxml.jackson.databind.ObjectMapper; import org.eclipse.jetty.server.Handler; @@ -16,7 +16,7 @@ import org.eclipse.jetty.server.handler.gzip.GzipHandler; import java.io.File; -public class LocalHttpServerBuilder { +public class TestServerBuilder { private File baseDir = new File("."); private int port = 28888; @@ -25,7 +25,7 @@ public class LocalHttpServerBuilder { return baseDir; } - public LocalHttpServerBuilder setBaseDir(File baseDir) { + public TestServerBuilder setBaseDir(File baseDir) { this.baseDir = baseDir; return this; } @@ -34,12 +34,12 @@ public class LocalHttpServerBuilder { return port; } - public LocalHttpServerBuilder setPort(int port) { + public TestServerBuilder setPort(int port) { this.port = port; return this; } - public Server build() throws Exception { + public TestServer build() { Server server = new Server(port); ObjectMapper mapper = new ObjectMapper(); @@ -72,7 +72,7 @@ public class LocalHttpServerBuilder { server.setHandler(gzip); gzip.setHandler(contexts); - return server; + return new TestServer(server); } } diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/swing/BorderCellRenderer.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/swing/BorderCellRenderer.java new file mode 100644 index 0000000..00ca509 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/swing/BorderCellRenderer.java @@ -0,0 +1,28 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.swing; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.*; + +public class BorderCellRenderer implements ListCellRenderer { + + private final Border border; + private final DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer(); + + public BorderCellRenderer(Border border) { + this.border = border; + } + + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + JLabel renderer = (JLabel) defaultRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + renderer.setBorder(border); + return renderer; + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/swing/PackDirectoryFilter.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/swing/PackDirectoryFilter.java new file mode 100644 index 0000000..333c859 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/swing/PackDirectoryFilter.java @@ -0,0 +1,26 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.swing; + +import com.skcraft.launcher.creator.model.creator.Workspace; + +import javax.swing.filechooser.FileFilter; +import java.io.File; + +public class PackDirectoryFilter extends FileFilter { + + @Override + public boolean accept(File f) { + return f.isDirectory() && !f.getName().equals(Workspace.DIR_NAME); + } + + @Override + public String getDescription() { + return "Directories"; + } + +} diff --git a/creator-tools/src/main/java/com/skcraft/launcher/creator/swing/WorkspaceDirectoryFilter.java b/creator-tools/src/main/java/com/skcraft/launcher/creator/swing/WorkspaceDirectoryFilter.java new file mode 100644 index 0000000..4e936b5 --- /dev/null +++ b/creator-tools/src/main/java/com/skcraft/launcher/creator/swing/WorkspaceDirectoryFilter.java @@ -0,0 +1,24 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.creator.swing; + +import javax.swing.filechooser.FileFilter; +import java.io.File; + +public class WorkspaceDirectoryFilter extends FileFilter { + + @Override + public boolean accept(File f) { + return f.isDirectory(); + } + + @Override + public String getDescription() { + return "Directories"; + } + +} diff --git a/creator-tools/src/main/resources/com/skcraft/launcher/creator/about_header.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/about_header.png new file mode 100644 index 0000000..0986006 Binary files /dev/null and b/creator-tools/src/main/resources/com/skcraft/launcher/creator/about_header.png differ diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/build.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/build.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/build.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/build.png diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/check.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/check.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/check.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/check.png diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/clean.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/clean.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/clean.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/clean.png diff --git a/creator-tools/src/main/resources/com/skcraft/launcher/creator/creator.properties b/creator-tools/src/main/resources/com/skcraft/launcher/creator/creator.properties new file mode 100644 index 0000000..4b5c12b --- /dev/null +++ b/creator-tools/src/main/resources/com/skcraft/launcher/creator/creator.properties @@ -0,0 +1,7 @@ +# +# SK's Minecraft Launcher +# Copyright (C) 2010-2014 Albert Pham and contributors +# Please see LICENSE.txt for license information. +# + +version=${project.version} diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/edit.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/edit.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/edit.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/edit.png diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/help.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/help.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/help.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/help.png diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/icon.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/icon.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/icon.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/icon.png diff --git a/creator-tools/src/main/resources/com/skcraft/launcher/creator/import.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/import.png new file mode 100644 index 0000000..e044513 Binary files /dev/null and b/creator-tools/src/main/resources/com/skcraft/launcher/creator/import.png differ diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/log.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/log.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/log.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/log.png diff --git a/creator-tools/src/main/resources/com/skcraft/launcher/creator/new.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/new.png new file mode 100644 index 0000000..ce39f47 Binary files /dev/null and b/creator-tools/src/main/resources/com/skcraft/launcher/creator/new.png differ diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/open_folder.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/open_folder.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/open_folder.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/open_folder.png diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/options.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/options.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/options.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/options.png diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/server.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/server.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/server.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/server.png diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/test.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/test.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/test.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/test.png diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/compile/warning_icon.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/warning_icon.png similarity index 100% rename from build-tools/src/main/resources/com/skcraft/launcher/buildtools/compile/warning_icon.png rename to creator-tools/src/main/resources/com/skcraft/launcher/creator/warning_icon.png diff --git a/creator-tools/src/main/resources/com/skcraft/launcher/creator/welcome_logo.png b/creator-tools/src/main/resources/com/skcraft/launcher/creator/welcome_logo.png new file mode 100644 index 0000000..cc1602d Binary files /dev/null and b/creator-tools/src/main/resources/com/skcraft/launcher/creator/welcome_logo.png differ diff --git a/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderUtils.java b/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderUtils.java index 8f2e722..091e63f 100644 --- a/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderUtils.java +++ b/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderUtils.java @@ -9,14 +9,16 @@ package com.skcraft.launcher.builder; import com.beust.jcommander.internal.Lists; import org.apache.commons.compress.compressors.CompressorStreamFactory; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public final class BuilderUtils { + private static final DateFormat VERSION_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + private BuilderUtils() { } @@ -49,4 +51,9 @@ public final class BuilderUtils { } } + public static String generateVersionFromDate() { + Date today = Calendar.getInstance().getTime(); + return VERSION_DATE_FORMAT.format(today); + } + } diff --git a/launcher/src/main/java/com/skcraft/concurrency/Callback.java b/launcher/src/main/java/com/skcraft/concurrency/Callback.java new file mode 100644 index 0000000..05f8bc0 --- /dev/null +++ b/launcher/src/main/java/com/skcraft/concurrency/Callback.java @@ -0,0 +1,13 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.concurrency; + +public interface Callback { + + void handle(T value); + +} diff --git a/launcher/src/main/java/com/skcraft/concurrency/Deferred.java b/launcher/src/main/java/com/skcraft/concurrency/Deferred.java new file mode 100644 index 0000000..22c3900 --- /dev/null +++ b/launcher/src/main/java/com/skcraft/concurrency/Deferred.java @@ -0,0 +1,142 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.concurrency; + +import com.google.common.base.Function; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; + +import java.util.concurrent.Callable; + +/** + * An extension of {@link ListenableFuture} that provides convenience methods + * to register functions that are triggered after upon the completion of + * the underlying task. + * + *

Dependent functions are executed using the "default" executor which + * is specified when {@code Deferred} is first created, unless + * the async variants are used to register the function.

+ * + * @param The type returned + */ +public interface Deferred extends ListenableFuture { + + /** + * Returns a new Deferred that represents the asynchronous computation + * of the given action, which is only executed upon the normal completion + * of this Deferred in the default executor. + * + * @param task The task + * @param The return type of the task + * @return The new Deferred + */ + Deferred thenRun(Callable task); + + /** + * Returns a new Deferred that represents the asynchronous computation + * of the given action, which is only executed upon the normal completion + * of this Deferred in the provided executor. + * + * @param task The task + * @param The return type of the task + * @return The new Deferred + */ + Deferred thenRunAsync(Callable task, ListeningExecutorService executor); + + /** + * Returns a new Deferred that represents the asynchronous execution + * of the given action, which is only executed upon the normal completion + * of this Deferred in the provided executor. + * + * @param task The task + * @return The new Deferred + */ + Deferred thenRun(Runnable task); + + /** + * Returns a new Deferred that represents the asynchronous execution + * of the given action, which is only executed upon the normal completion + * of this Deferred in the default executor. + * + * @param task The task + * @return The new Deferred + */ + Deferred thenRunAsync(Runnable task, ListeningExecutorService executor); + + /** + * Returns a new Deferred that represents the asynchronous execution + * of the given action as a side effect that does not change the value + * passed between the prior Deferred to any dependent Deferred instances. + * + *

The given action is only executed in the default executor upon the + * normal completion of this Deferred.

+ * + * @param task The task + * @return The new Deferred + */ + Deferred thenTap(Runnable task); + + /** + * Returns a new Deferred that represents the asynchronous execution + * of the given action as a side effect that does not change the value + * passed between the prior Deferred to any dependent Deferred instances. + * + *

The given action is only executed in the provided executor upon the + * normal completion of this Deferred.

+ * + * @param task The task + * @return The new Deferred + */ + Deferred thenTapAsync(Runnable task, ListeningExecutorService executor); + + /** + * Returns a new Deferred that represents the asynchronous execution + * of the given function, which transforms the value of the previous + * Deferred into a new value. + * + *

The given action is only executed in the default executor upon the + * normal completion of this Deferred.

+ * + * @param function The function + * @return The new Deferred + */ + Deferred thenApply(Function function); + + /** + * Returns a new Deferred that represents the asynchronous execution + * of the given function, which transforms the value of the previous + * Deferred into a new value. + * + *

The given action is only executed in the provided executor upon the + * normal completion of this Deferred.

+ * + * @param function The function + * @return The new Deferred + */ + Deferred thenApplyAsync(Function function, ListeningExecutorService executor); + + /** + * Adds callbacks that are executed asynchronously on success or failure + * using the default executor. + * + * @param onSuccess The success callback + * @param onFailure The failure callback + * @return The Deferred + */ + Deferred handle(Callback onSuccess, Callback onFailure); + + /** + * Adds callbacks that are executed asynchronously on success or failure. + * + * @param onSuccess The success callback + * @param onFailure The failure callback + * @param executor The executor + * @return The Deferred + */ + Deferred handleAsync(Callback onSuccess, Callback onFailure, ListeningExecutorService executor); + +} diff --git a/launcher/src/main/java/com/skcraft/concurrency/DeferredImpl.java b/launcher/src/main/java/com/skcraft/concurrency/DeferredImpl.java new file mode 100644 index 0000000..1a2b93a --- /dev/null +++ b/launcher/src/main/java/com/skcraft/concurrency/DeferredImpl.java @@ -0,0 +1,140 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.concurrency; + +import com.google.common.base.Function; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; + +import java.util.concurrent.*; + +class DeferredImpl implements Deferred { + + private final ListenableFuture future; + private final ListeningExecutorService defaultExecutor; + + DeferredImpl(ListenableFuture future, ListeningExecutorService defaultExecutor) { + this.future = future; + this.defaultExecutor = defaultExecutor; + } + + @Override + public Deferred thenRun(Callable task) { + return thenRunAsync(task, defaultExecutor); + } + + @Override + public Deferred thenRunAsync(final Callable task, ListeningExecutorService executor) { + return new DeferredImpl(Futures.transform(future, new Function() { + @Override + public O apply(I input) { + try { + return task.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }, executor), defaultExecutor); + } + + @Override + public Deferred thenRun(Runnable task) { + return thenRunAsync(task, defaultExecutor); + } + + @Override + public Deferred thenRunAsync(final Runnable task, ListeningExecutorService executor) { + return new DeferredImpl(Futures.transform(future, new Function() { + @Override + public Void apply(I input) { + task.run(); + return null; + } + }), defaultExecutor); + } + + @Override + public Deferred thenTap(Runnable task) { + return thenTapAsync(task, defaultExecutor); + } + + @Override + public Deferred thenTapAsync(final Runnable task, ListeningExecutorService executor) { + return thenApplyAsync(new Function() { + @Override + public I apply(I input) { + task.run(); + return input; + } + }, executor); + } + + @Override + public Deferred thenApply(Function function) { + return thenApplyAsync(function, defaultExecutor); + } + + @Override + public Deferred thenApplyAsync(Function function, ListeningExecutorService executor) { + return new DeferredImpl(Futures.transform(future, function, executor), defaultExecutor); + } + + @Override + public Deferred handle(Callback onSuccess, Callback onFailure) { + return handleAsync(onSuccess, onFailure, defaultExecutor); + } + + @Override + public Deferred handleAsync(final Callback onSuccess, final Callback onFailure, ListeningExecutorService executor) { + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(I result) { + onSuccess.handle(result); + } + + @Override + public void onFailure(Throwable t) { + onFailure.handle(t); + } + }, executor); + + return this; + } + + @Override + public void addListener(Runnable listener, Executor executor) { + future.addListener(listener, executor); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return future.cancel(mayInterruptIfRunning); + } + + @Override + public boolean isCancelled() { + return future.isCancelled(); + } + + @Override + public boolean isDone() { + return future.isDone(); + } + + @Override + public I get() throws InterruptedException, ExecutionException { + return future.get(); + } + + @Override + public I get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return future.get(timeout, unit); + } + +} diff --git a/launcher/src/main/java/com/skcraft/concurrency/Deferreds.java b/launcher/src/main/java/com/skcraft/concurrency/Deferreds.java new file mode 100644 index 0000000..3144b37 --- /dev/null +++ b/launcher/src/main/java/com/skcraft/concurrency/Deferreds.java @@ -0,0 +1,45 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.concurrency; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +/** + * Utility class for working with Deferred. + */ +public final class Deferreds { + + private Deferreds() { + } + + /** + * Make a new Deferred from the given future, using the same thread + * executor as the default executor. + * + * @param future The future + * @param The type returned by the future + * @return A new Deferred + */ + public static Deferred makeDeferred(ListenableFuture future) { + return makeDeferred(future, MoreExecutors.sameThreadExecutor()); + } + + /** + * Make a new Deferred from the given future. + * + * @param future The future + * @param executor The default executor + * @param The type returned by the future + * @return A new Deferred + */ + public static Deferred makeDeferred(ListenableFuture future, ListeningExecutorService executor) { + return new DeferredImpl(future, executor); + } + +} diff --git a/launcher/src/main/java/com/skcraft/concurrency/SettableProgress.java b/launcher/src/main/java/com/skcraft/concurrency/SettableProgress.java new file mode 100644 index 0000000..ce8f20b --- /dev/null +++ b/launcher/src/main/java/com/skcraft/concurrency/SettableProgress.java @@ -0,0 +1,46 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.concurrency; + +public class SettableProgress implements ProgressObservable { + + private ProgressObservable delegate; + private String status = ""; + private double progress = -1; + + public SettableProgress(String status, double progress) { + this.status = status; + this.progress = progress; + } + + public SettableProgress(ProgressObservable observable) { + this.delegate = observable; + } + + public synchronized void observe(ProgressObservable observable) { + delegate = observable; + } + + public synchronized void set(String status, double progress) { + delegate = null; + this.progress = progress; + this.status = status; + } + + @Override + public double getProgress() { + ProgressObservable delegate = this.delegate; + return delegate != null ? delegate.getProgress() : progress; + } + + @Override + public String getStatus() { + ProgressObservable delegate = this.delegate; + return delegate != null ? delegate.getStatus() : status; + } + +} diff --git a/launcher/src/main/java/com/skcraft/launcher/LauncherUtils.java b/launcher/src/main/java/com/skcraft/launcher/LauncherUtils.java index 0cf6e99..caf9537 100644 --- a/launcher/src/main/java/com/skcraft/launcher/LauncherUtils.java +++ b/launcher/src/main/java/com/skcraft/launcher/LauncherUtils.java @@ -42,13 +42,17 @@ public final class LauncherUtils { Properties prop = new Properties(); try { InputStream in = closer.register(clazz.getResourceAsStream(name)); - prop.load(in); - String extraPath = System.getProperty(extraProperty); - if (extraPath != null) { - log.info("Loading extra properties for " + - clazz.getCanonicalName() + ":" + name + " from " + extraPath + "..."); - in = closer.register(new BufferedInputStream(closer.register(new FileInputStream(extraPath)))); + if (in != null) { prop.load(in); + String extraPath = System.getProperty(extraProperty); + if (extraPath != null) { + log.info("Loading extra properties for " + + clazz.getCanonicalName() + ":" + name + " from " + extraPath + "..."); + in = closer.register(new BufferedInputStream(closer.register(new FileInputStream(extraPath)))); + prop.load(in); + } + } else { + throw new FileNotFoundException(); } } finally { closer.close(); diff --git a/launcher/src/main/java/com/skcraft/launcher/dialog/ProgressDialog.java b/launcher/src/main/java/com/skcraft/launcher/dialog/ProgressDialog.java index ad8f467..c2f14e9 100644 --- a/launcher/src/main/java/com/skcraft/launcher/dialog/ProgressDialog.java +++ b/launcher/src/main/java/com/skcraft/launcher/dialog/ProgressDialog.java @@ -8,6 +8,7 @@ package com.skcraft.launcher.dialog; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import com.skcraft.concurrency.ObservableFuture; import com.skcraft.concurrency.ProgressObservable; import com.skcraft.launcher.swing.LinedBoxPanel; @@ -156,6 +157,10 @@ public class ProgressDialog extends JDialog { } public static void showProgress(final Window owner, final ObservableFuture future, String title, String message) { + showProgress(owner, future, future, title, message); + } + + public static void showProgress(final Window owner, final ListenableFuture future, ProgressObservable observable, String title, String message) { final ProgressDialog dialog = new ProgressDialog(owner, title, message) { @Override protected void cancel() { @@ -166,7 +171,7 @@ public class ProgressDialog extends JDialog { lastDialogRef = new WeakReference(dialog); final Timer timer = new Timer(); - timer.scheduleAtFixedRate(new UpdateProgress(dialog, future), 400, 400); + timer.scheduleAtFixedRate(new UpdateProgress(dialog, observable), 400, 400); Futures.addCallback(future, new FutureCallback() { @Override diff --git a/launcher/src/main/java/com/skcraft/launcher/model/modpack/ManifestInfo.java b/launcher/src/main/java/com/skcraft/launcher/model/modpack/ManifestInfo.java index e035579..6d63f48 100644 --- a/launcher/src/main/java/com/skcraft/launcher/model/modpack/ManifestInfo.java +++ b/launcher/src/main/java/com/skcraft/launcher/model/modpack/ManifestInfo.java @@ -11,9 +11,20 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) -public class ManifestInfo extends BaseManifest { +public class ManifestInfo extends BaseManifest implements Comparable { private String location; private int priority; + @Override + public int compareTo(ManifestInfo o) { + if (priority > o.getPriority()) { + return -1; + } else if (priority < o.getPriority()) { + return 1; + } else { + return 0; + } + } + } diff --git a/launcher/src/main/java/com/skcraft/launcher/model/modpack/PackageList.java b/launcher/src/main/java/com/skcraft/launcher/model/modpack/PackageList.java index 8385ff3..4268d9e 100644 --- a/launcher/src/main/java/com/skcraft/launcher/model/modpack/PackageList.java +++ b/launcher/src/main/java/com/skcraft/launcher/model/modpack/PackageList.java @@ -13,6 +13,8 @@ import java.util.List; @Data public class PackageList { + public static final int MIN_VERSION = 1; + private int minimumVersion; private List packages; diff --git a/launcher/src/main/java/com/skcraft/launcher/persistence/Persistence.java b/launcher/src/main/java/com/skcraft/launcher/persistence/Persistence.java index 58d5646..8f1e264 100644 --- a/launcher/src/main/java/com/skcraft/launcher/persistence/Persistence.java +++ b/launcher/src/main/java/com/skcraft/launcher/persistence/Persistence.java @@ -7,6 +7,8 @@ package com.skcraft.launcher.persistence; import com.fasterxml.jackson.core.PrettyPrinter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter.Lf2SpacesIndenter; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.io.ByteSink; import com.google.common.io.ByteSource; @@ -36,8 +38,13 @@ import java.util.logging.Level; public final class Persistence { private static final ObjectMapper mapper = new ObjectMapper(); - private static final WeakHashMap bound = - new WeakHashMap(); + private static final WeakHashMap bound = new WeakHashMap(); + public static final DefaultPrettyPrinter L2F_LIST_PRETTY_PRINTER; + + static { + L2F_LIST_PRETTY_PRINTER = new DefaultPrettyPrinter(); + L2F_LIST_PRETTY_PRINTER.indentArraysWith(Lf2SpacesIndenter.instance); + } private Persistence() { } @@ -227,4 +234,19 @@ public final class Persistence { } } + /** + * Write an object to a string. + * + * @param object the object + * @param prettyPrinter a pretty printer to use, or null + * @throws java.io.IOException on I/O error + */ + public static String writeValueAsString(Object object, PrettyPrinter prettyPrinter) throws IOException { + if (prettyPrinter != null) { + return mapper.writer(prettyPrinter).writeValueAsString(object); + } else { + return mapper.writeValueAsString(object); + } + } + } diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/CheckboxTable.java b/launcher/src/main/java/com/skcraft/launcher/swing/CheckboxTable.java index 797ff05..40b91df 100644 --- a/launcher/src/main/java/com/skcraft/launcher/swing/CheckboxTable.java +++ b/launcher/src/main/java/com/skcraft/launcher/swing/CheckboxTable.java @@ -8,17 +8,8 @@ package com.skcraft.launcher.swing; import javax.swing.*; import javax.swing.table.TableModel; -import java.awt.*; -public class CheckboxTable extends JTable { - - public CheckboxTable() { - setShowGrid(false); - setRowHeight((int) (Math.max(getRowHeight(), new JCheckBox().getPreferredSize().getHeight() - 2))); - setIntercellSpacing(new Dimension(0, 0)); - setFillsViewportHeight(true); - setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - } +public class CheckboxTable extends DefaultTable { @Override public void setModel(TableModel dataModel) { @@ -28,4 +19,5 @@ public class CheckboxTable extends JTable { } catch (ArrayIndexOutOfBoundsException e) { } } + } diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/DefaultTable.java b/launcher/src/main/java/com/skcraft/launcher/swing/DefaultTable.java new file mode 100644 index 0000000..01b7fef --- /dev/null +++ b/launcher/src/main/java/com/skcraft/launcher/swing/DefaultTable.java @@ -0,0 +1,25 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.swing; + +import javax.swing.*; +import java.awt.*; + +/** + * The default table style used throughout the launcher. + */ +public class DefaultTable extends JTable { + + public DefaultTable() { + setShowGrid(false); + setRowHeight((int) (Math.max(getRowHeight(), new JCheckBox().getPreferredSize().getHeight() - 2))); + setIntercellSpacing(new Dimension(0, 0)); + setFillsViewportHeight(true); + setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + } + +} diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/DirectoryField.java b/launcher/src/main/java/com/skcraft/launcher/swing/DirectoryField.java index 2feadad..55f8864 100644 --- a/launcher/src/main/java/com/skcraft/launcher/swing/DirectoryField.java +++ b/launcher/src/main/java/com/skcraft/launcher/swing/DirectoryField.java @@ -41,6 +41,8 @@ public class DirectoryField extends JPanel { browse(); } }); + + textField.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE); } public JTextField getTextField() { diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/EventQueueExecutor.java b/launcher/src/main/java/com/skcraft/launcher/swing/EventQueueExecutor.java new file mode 100644 index 0000000..3aa66f0 --- /dev/null +++ b/launcher/src/main/java/com/skcraft/launcher/swing/EventQueueExecutor.java @@ -0,0 +1,24 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.swing; + +import java.awt.*; +import java.util.concurrent.Executor; + +public class EventQueueExecutor implements Executor { + + public static final EventQueueExecutor INSTANCE = new EventQueueExecutor(); + + private EventQueueExecutor() { + } + + @Override + public void execute(Runnable runnable) { + EventQueue.invokeLater(runnable); + } + +} diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/InstanceTable.java b/launcher/src/main/java/com/skcraft/launcher/swing/InstanceTable.java index 878ab9e..63643ed 100644 --- a/launcher/src/main/java/com/skcraft/launcher/swing/InstanceTable.java +++ b/launcher/src/main/java/com/skcraft/launcher/swing/InstanceTable.java @@ -6,19 +6,13 @@ package com.skcraft.launcher.swing; -import javax.swing.*; import javax.swing.table.TableModel; -import java.awt.*; -public class InstanceTable extends JTable { +public class InstanceTable extends DefaultTable { public InstanceTable() { - setShowGrid(false); - setRowHeight(Math.max(getRowHeight() + 4, 20)); - setIntercellSpacing(new Dimension(0, 0)); - setFillsViewportHeight(true); + super(); setTableHeader(null); - setSelectionMode(ListSelectionModel.SINGLE_SELECTION); } @Override diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/SwingHelper.java b/launcher/src/main/java/com/skcraft/launcher/swing/SwingHelper.java index 01f2998..f0ef9fd 100644 --- a/launcher/src/main/java/com/skcraft/launcher/swing/SwingHelper.java +++ b/launcher/src/main/java/com/skcraft/launcher/swing/SwingHelper.java @@ -6,6 +6,7 @@ package com.skcraft.launcher.swing; +import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; @@ -27,6 +28,7 @@ import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; +import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.*; import java.lang.reflect.InvocationTargetException; @@ -54,6 +56,8 @@ public final class SwingHelper { } }; + private static final Joiner NEW_LINE_JOINER = Joiner.on("\n"); + private SwingHelper() { } @@ -300,6 +304,15 @@ public final class SwingHelper { return null; } + public static Image readIconImageScaled(Class clazz, String path, int w, int h) { + BufferedImage image = readIconImage(clazz, path); + if (image != null) { + return image.getScaledInstance(w, h, Image.SCALE_SMOOTH); + } else { + return null; + } + } + public static void setIconImage(JFrame frame, Class clazz, String path) { BufferedImage image = readIconImage(clazz, path); if (image != null) { @@ -316,6 +329,15 @@ public final class SwingHelper { } } + public static ImageIcon readImageIconScaled(Class clazz, String path, int w, int h) { + Image image = readIconImageScaled(clazz, path, w, h); + if (image != null) { + return new ImageIcon(image); + } else { + return null; + } + } + /** * Focus a component. * @@ -399,6 +421,10 @@ public final class SwingHelper { return scrollPane; } + public static String listToLines(List lines) { + return SwingHelper.NEW_LINE_JOINER.join(lines); + } + public static List linesToList(String text) { String[] tokens = text.replace("\r", "\n").split("\n"); List values = Lists.newArrayList(); @@ -411,6 +437,12 @@ public final class SwingHelper { return values; } + public static void addActionListeners(AbstractButton button, ActionListener[] listeners) { + for (ActionListener listener : listeners) { + button.addActionListener(listener); + } + } + public static boolean setLookAndFeel(String lookAndFeel) { try { UIManager.setLookAndFeel(lookAndFeel); diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/TableColumnAdjuster.java b/launcher/src/main/java/com/skcraft/launcher/swing/TableColumnAdjuster.java new file mode 100644 index 0000000..1a71276 --- /dev/null +++ b/launcher/src/main/java/com/skcraft/launcher/swing/TableColumnAdjuster.java @@ -0,0 +1,326 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.swing; + +import lombok.Getter; +import lombok.Setter; + +import javax.swing.*; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; +import javax.swing.table.TableModel; +import java.awt.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.HashMap; +import java.util.Map; + +/* + * Class to manage the widths of colunmns in a table. + * + * Various properties control how the width of the column is calculated. + * Another property controls whether column width calculation should be dynamic. + * Finally, various Actions will be added to the table to allow the user + * to customize the functionality. + * + * This class was designed to be used with tables that use an auto resize mode + * of AUTO_RESIZE_OFF. With all other modes you are constrained as the width + * of the columns must fit inside the table. So if you increase one column, one + * or more of the other columns must decrease. Because of this the resize mode + * of RESIZE_ALL_COLUMNS will work the best. + * + *

From https://tips4java.wordpress.com/2008/11/10/table-column-adjuster/

+ */ +public class TableColumnAdjuster implements PropertyChangeListener, TableModelListener { + private JTable table; + private int spacing; + private boolean isColumnHeaderIncluded; + private boolean isColumnDataIncluded; + private boolean isOnlyAdjustLarger; + private boolean isDynamicAdjustment; + @Getter @Setter + private int imageIconWidth = 25; + private int checkBoxWidth; + private Map columnSizes = new HashMap(); + + /* + * Specify the table and use default spacing + */ + public TableColumnAdjuster(JTable table) { + this(table, 16); + checkBoxWidth = (int) new JCheckBox().getPreferredSize().getWidth(); + } + + /* + * Specify the table and spacing + */ + public TableColumnAdjuster(JTable table, int spacing) { + this.table = table; + this.spacing = spacing; + setColumnHeaderIncluded(true); + setColumnDataIncluded(true); + setOnlyAdjustLarger(false); + setDynamicAdjustment(false); + } + + /** + * Set default column properties. + */ + public void setColumnProperties() { + TableModel tm = table.getModel(); + TableColumnModel tcm = table.getColumnModel(); + + for (int i = 0; i < tm.getColumnCount(); i++) { + TableColumn column = tcm.getColumn(i); + Class columnClass = tm.getColumnClass(i); + if (columnClass == ImageIcon.class) { + column.setWidth(imageIconWidth); + column.setPreferredWidth(imageIconWidth); + column.setMaxWidth(imageIconWidth); + column.setResizable(false); + } else if (columnClass == Boolean.class) { + column.setWidth(checkBoxWidth); + column.setPreferredWidth(checkBoxWidth); + column.setMaxWidth(checkBoxWidth); + column.setResizable(false); + } + } + } + + /* + * Adjust the widths of all the columns in the table + */ + public void adjustColumns() { + TableColumnModel tcm = table.getColumnModel(); + + for (int i = 0; i < tcm.getColumnCount(); i++) { + adjustColumn(i); + } + } + + /* + * Adjust the width of the specified column in the table + */ + public void adjustColumn(final int column) { + TableColumn tableColumn = table.getColumnModel().getColumn(column); + + if (!tableColumn.getResizable()) return; + + int columnHeaderWidth = getColumnHeaderWidth(column); + int columnDataWidth = getColumnDataWidth(column); + int preferredWidth = Math.max(columnHeaderWidth, columnDataWidth); + + updateTableColumn(column, preferredWidth); + } + + /* + * Calculated the width based on the column name + */ + private int getColumnHeaderWidth(int column) { + if (!isColumnHeaderIncluded) return 0; + + TableColumn tableColumn = table.getColumnModel().getColumn(column); + Object value = tableColumn.getHeaderValue(); + TableCellRenderer renderer = tableColumn.getHeaderRenderer(); + + if (renderer == null) { + renderer = table.getTableHeader().getDefaultRenderer(); + } + + Component c = renderer.getTableCellRendererComponent(table, value, false, false, -1, column); + return c.getPreferredSize().width; + } + + /* + * Calculate the width based on the widest cell renderer for the + * given column. + */ + private int getColumnDataWidth(int column) { + if (!isColumnDataIncluded) return 0; + + int preferredWidth = 0; + int maxWidth = table.getColumnModel().getColumn(column).getMaxWidth(); + + for (int row = 0; row < table.getRowCount(); row++) { + preferredWidth = Math.max(preferredWidth, getCellDataWidth(row, column)); + + // We've exceeded the maximum width, no need to check other rows + + if (preferredWidth >= maxWidth) + break; + } + + return preferredWidth; + } + + /* + * Get the preferred width for the specified cell + */ + private int getCellDataWidth(int row, int column) { + // Inovke the renderer for the cell to calculate the preferred width + + TableCellRenderer cellRenderer = table.getCellRenderer(row, column); + Component c = table.prepareRenderer(cellRenderer, row, column); + int width = c.getPreferredSize().width + table.getIntercellSpacing().width; + + return width; + } + + /* + * Update the TableColumn with the newly calculated width + */ + private void updateTableColumn(int column, int width) { + final TableColumn tableColumn = table.getColumnModel().getColumn(column); + + if (!tableColumn.getResizable()) return; + + width += spacing; + + // Don't shrink the column width + + if (isOnlyAdjustLarger) { + width = Math.max(width, tableColumn.getPreferredWidth()); + } + + columnSizes.put(tableColumn, tableColumn.getWidth()); + + table.getTableHeader().setResizingColumn(tableColumn); + tableColumn.setWidth(width); + } + + /* + * Restore the widths of the columns in the table to its previous width + */ + public void restoreColumns() { + TableColumnModel tcm = table.getColumnModel(); + + for (int i = 0; i < tcm.getColumnCount(); i++) { + restoreColumn(i); + } + } + + /* + * Restore the width of the specified column to its previous width + */ + private void restoreColumn(int column) { + TableColumn tableColumn = table.getColumnModel().getColumn(column); + Integer width = columnSizes.get(tableColumn); + + if (width != null) { + table.getTableHeader().setResizingColumn(tableColumn); + tableColumn.setWidth(width.intValue()); + } + } + + /* + * Indicates whether to include the header in the width calculation + */ + public void setColumnHeaderIncluded(boolean isColumnHeaderIncluded) { + this.isColumnHeaderIncluded = isColumnHeaderIncluded; + } + + /* + * Indicates whether to include the model data in the width calculation + */ + public void setColumnDataIncluded(boolean isColumnDataIncluded) { + this.isColumnDataIncluded = isColumnDataIncluded; + } + + /* + * Indicates whether columns can only be increased in size + */ + public void setOnlyAdjustLarger(boolean isOnlyAdjustLarger) { + this.isOnlyAdjustLarger = isOnlyAdjustLarger; + } + + /* + * Indicate whether changes to the model should cause the width to be + * dynamically recalculated. + */ + public void setDynamicAdjustment(boolean isDynamicAdjustment) { + // May need to add or remove the TableModelListener when changed + + if (this.isDynamicAdjustment != isDynamicAdjustment) { + if (isDynamicAdjustment) { + table.addPropertyChangeListener(this); + table.getModel().addTableModelListener(this); + } else { + table.removePropertyChangeListener(this); + table.getModel().removeTableModelListener(this); + } + } + + setColumnProperties(); + + this.isDynamicAdjustment = isDynamicAdjustment; + } + + // +// Implement the PropertyChangeListener +// + public void propertyChange(PropertyChangeEvent e) { + // When the TableModel changes we need to update the listeners + // and column widths + + if ("model".equals(e.getPropertyName())) { + TableModel model = (TableModel) e.getOldValue(); + model.removeTableModelListener(this); + + model = (TableModel) e.getNewValue(); + model.addTableModelListener(this); + + setColumnProperties(); + adjustColumns(); + } + } + + // +// Implement the TableModelListener +// + public void tableChanged(final TableModelEvent e) { + if (!isColumnDataIncluded) return; + + // Needed when table is sorted. + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + // A cell has been updated + + int column = table.convertColumnIndexToView(e.getColumn()); + + if (e.getType() == TableModelEvent.UPDATE && column != -1) { + // Only need to worry about an increase in width for this cell + + if (isOnlyAdjustLarger) { + int row = e.getFirstRow(); + TableColumn tableColumn = table.getColumnModel().getColumn(column); + + if (tableColumn.getResizable()) { + int width = getCellDataWidth(row, column); + updateTableColumn(column, width); + } + } + + // Could be an increase of decrease so check all rows + + else { + adjustColumn(column); + } + } + + // The update affected more than one column so adjust all columns + + else { + adjustColumns(); + } + } + }); + } +} diff --git a/launcher/src/main/java/com/skcraft/launcher/util/MorePaths.java b/launcher/src/main/java/com/skcraft/launcher/util/MorePaths.java new file mode 100644 index 0000000..65b78be --- /dev/null +++ b/launcher/src/main/java/com/skcraft/launcher/util/MorePaths.java @@ -0,0 +1,45 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.util; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +public final class MorePaths { + + private MorePaths() { + } + + public static boolean isSamePath(File a, File b) throws IOException { + return a.getCanonicalPath().equals(b.getCanonicalPath()); + } + + public static boolean isSubDirectory(File base, File child) throws IOException { + base = base.getCanonicalFile(); + child = child.getCanonicalFile(); + + File parentFile = child; + while (parentFile != null) { + if (base.equals(parentFile)) { + return true; + } + + parentFile = parentFile.getParentFile(); + } + + return false; + } + + public static String relativize(File base, File child) { + Path basePath = Paths.get(base.getAbsolutePath()); + Path childPath = Paths.get(child.getAbsolutePath()); + return basePath.relativize(childPath).toString(); + } + +} diff --git a/launcher/src/main/java/com/skcraft/launcher/util/SwingExecutor.java b/launcher/src/main/java/com/skcraft/launcher/util/SwingExecutor.java index d3e24ec..39b9be2 100644 --- a/launcher/src/main/java/com/skcraft/launcher/util/SwingExecutor.java +++ b/launcher/src/main/java/com/skcraft/launcher/util/SwingExecutor.java @@ -6,12 +6,14 @@ package com.skcraft.launcher.util; +import com.google.common.util.concurrent.AbstractListeningExecutorService; + import javax.swing.*; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.TimeUnit; -public final class SwingExecutor extends AbstractExecutorService { +public final class SwingExecutor extends AbstractListeningExecutorService { public static final SwingExecutor INSTANCE = new SwingExecutor(); @@ -23,20 +25,6 @@ public final class SwingExecutor extends AbstractExecutorService { SwingUtilities.invokeLater(runnable); } - @Override - protected RunnableFuture newTaskFor(final Callable callable) { - return new FutureTask(callable) { - @Override - public void run() { - try { - super.run(); - } catch (Throwable e) { - setException(e); - } - } - }; - } - @Override public void shutdown() { } @@ -60,4 +48,4 @@ public final class SwingExecutor extends AbstractExecutorService { public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return false; } -} \ No newline at end of file +} diff --git a/settings.gradle b/settings.gradle index a88f495..18c4ab3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,3 @@ rootProject.name = 'launcher-parent' -include 'launcher', 'launcher-fancy', 'launcher-builder', 'launcher-bootstrap', 'build-tools' +include 'launcher', 'launcher-fancy', 'launcher-builder', 'launcher-bootstrap', 'creator-tools'