diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildDialog.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildDialog.java deleted file mode 100644 index 91ad7e6..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildDialog.java +++ /dev/null @@ -1,105 +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.Getter; -import net.miginfocom.swing.MigLayout; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -public class BuildDialog extends JDialog { - - 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; - - public BuildDialog(Window parent) { - super(parent, "Build Release", ModalityType.DOCUMENT_MODAL); - - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - initComponents(); - setResizable(false); - pack(); - setLocationRelativeTo(null); - } - - private void initComponents() { - JPanel container = new JPanel(); - container.setLayout(new MigLayout("insets dialog")); - - container.add(new JLabel("Version:")); - container.add(versionText, "span"); - - container.add(new JLabel("Manifest Filename:")); - container.add(manifestFilenameText, "span"); - - container.add(cleanCheck, "span, gapbottom 20"); - - JButton buildButton = new JButton("Build..."); - JButton cancelButton = new JButton("Cancel"); - - container.add(buildButton, "tag ok, span, split 2, sizegroup bttn"); - container.add(cancelButton, "tag cancel, sizegroup bttn"); - - add(container, BorderLayout.CENTER); - - buildButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - returnValue(); - } - }); - - cancelButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - dispose(); - } - }); - } - - private void returnValue() { - String version = versionText.getText().trim(); - String manifestFilename = manifestFilenameText.getText().trim(); - - if (version.isEmpty()) { - SwingHelper.showErrorDialog(this, "A version string must be entered.", "Error"); - return; - } - - if (manifestFilename.isEmpty()) { - SwingHelper.showErrorDialog(this, "A manifest filename must be entered.", "Error"); - return; - } - - options = new BuildOptions(version, manifestFilename, cleanCheck.isSelected()); - dispose(); - } - - public static BuildOptions showBuildDialog(Window parent, String version, String manifestName) { - BuildDialog dialog = new BuildDialog(parent); - dialog.versionText.setText(version); - dialog.manifestFilenameText.setText(manifestName); - dialog.setVisible(true); - return dialog.getOptions(); - } - - @Data - public static class BuildOptions { - private final String version; - private final String manifestFilename; - private final boolean clean; - } - -} 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 index 5092985..0c951e1 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildTools.java +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/BuildTools.java @@ -7,7 +7,11 @@ 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; @@ -17,14 +21,22 @@ import com.skcraft.launcher.auth.OfflineSession; import com.skcraft.launcher.auth.Session; import com.skcraft.launcher.builder.BuilderConfig; -import com.skcraft.launcher.buildtools.BuildDialog.BuildOptions; +import com.skcraft.launcher.builder.BuilderOptions; +import com.skcraft.launcher.builder.FnPatternList; +import com.skcraft.launcher.buildtools.build.*; +import com.skcraft.launcher.buildtools.build.BuildDialog.BuildOptions; +import com.skcraft.launcher.buildtools.project.BuilderConfigDialog; +import com.skcraft.launcher.buildtools.http.LocalHttpServerBuilder; +import com.skcraft.launcher.buildtools.build.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; @@ -46,25 +58,39 @@ @Log public class BuildTools { - private static DateFormat VERSION_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); - private static Pattern FILENAME_SANITIZE = Pattern.compile("[^a-z0-9_\\-\\.]+"); + 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; - private String configFilename = "modpack.json"; + @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(); @@ -79,8 +105,12 @@ 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 = new File(inputDir, configFilename); + File file = getConfigFile(); if (file.exists()) { BuilderConfig config = Persistence.read(file, BuilderConfig.class, true); if (config != null) { @@ -98,7 +128,7 @@ } public String getCurrentModpackName() { - File file = new File(inputDir, configFilename); + File file = getConfigFile(); if (file.exists()) { BuilderConfig config = Persistence.read(file, BuilderConfig.class, true); if (config != null) { @@ -109,7 +139,7 @@ return null; } - public Instance findCurrentInstsance(List instances) { + public Instance findCurrentInstance(List instances) { String expected = getCurrentModpackName(); for (Instance instance : instances) { @@ -121,6 +151,21 @@ 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); @@ -135,22 +180,105 @@ 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) { - BuildOptions options = BuildDialog.showBuildDialog(frame, generateVersionFromDate(), generateManifestName()); + final BuildOptions options = BuildDialog.showBuildDialog(frame, generateVersionFromDate(), generateManifestName(), distDir); if (options != null) { ConsoleFrame.showMessages(); - distDir.mkdirs(); - ModpackBuilder runnable = new ModpackBuilder(inputDir, distDir, options.getVersion(), options.getManifestFilename(), options.isClean()); + 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(distDir, frame); + 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 @@ -229,12 +357,18 @@ } }); + 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) { - String expectedName = getCurrentModpackName(); - final InstanceList instanceList = launcher.getInstances(); InstanceList.Enumerator loader = instanceList.createEnumerator(); ObservableFuture future = new ObservableFuture(launcher.getExecutor().submit(loader), loader); @@ -246,7 +380,7 @@ public void onSuccess(InstanceList result) { Session session = new OfflineSession("Player"); - Instance instance = findCurrentInstsance(instanceList.getInstances()); + Instance instance = findCurrentInstance(instanceList.getInstances()); if (instance != null) { LaunchOptions options = new LaunchOptions.Builder() @@ -280,6 +414,7 @@ SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { + UIManager.getDefaults().put("SplitPane.border", BorderFactory.createEmptyBorder()); try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception ignored) { @@ -287,7 +422,14 @@ } }); - final BuildTools main = new BuildTools(options.getDir(), options.getPort()); + 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(); diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/LatestHandler.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/LatestHandler.java deleted file mode 100644 index d4ecc0b..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/LatestHandler.java +++ /dev/null @@ -1,41 +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.fasterxml.jackson.databind.ObjectMapper; -import com.skcraft.launcher.selfupdate.LatestVersionInfo; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.net.URL; - -public class LatestHandler extends AbstractHandler { - - private final ObjectMapper mapper; - - public LatestHandler(ObjectMapper mapper) { - this.mapper = mapper; - } - - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - response.setContentType("text/plain; charset=utf-8"); - response.setStatus(HttpServletResponse.SC_OK); - - LatestVersionInfo info = new LatestVersionInfo(); - info.setVersion("0.0.0"); - info.setUrl(new URL("http://localhost")); - mapper.writeValue(response.getWriter(), info); - - baseRequest.setHandled(true); - } - -} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/LocalHttpServerBuilder.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/LocalHttpServerBuilder.java deleted file mode 100644 index bb78ad3..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/LocalHttpServerBuilder.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.fasterxml.jackson.databind.ObjectMapper; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.server.handler.ResourceHandler; -import org.eclipse.jetty.server.handler.gzip.GzipHandler; - -import java.io.File; - -public class LocalHttpServerBuilder { - - private File baseDir = new File("."); - private int port = 28888; - - public File getBaseDir() { - return baseDir; - } - - public LocalHttpServerBuilder setBaseDir(File baseDir) { - this.baseDir = baseDir; - return this; - } - - public int getPort() { - return port; - } - - public LocalHttpServerBuilder setPort(int port) { - this.port = port; - return this; - } - - public Server build() throws Exception { - Server server = new Server(port); - - ObjectMapper mapper = new ObjectMapper(); - - ResourceHandler resourceHandler = new ResourceHandler(); - resourceHandler.setDirectoriesListed(true); - resourceHandler.setResourceBase(baseDir.getAbsolutePath()); - resourceHandler.setMinMemoryMappedContentLength(-1); // Causes file locking on Windows - - ContextHandler rootContext = new ContextHandler(); - rootContext.setContextPath("/"); - rootContext.setHandler(resourceHandler); - - ContextHandler packagesContext = new ContextHandler("/packages.json"); - packagesContext.setAllowNullPathInfo(true); - packagesContext.setHandler(new PackagesHandler(mapper, baseDir)); - - ContextHandler latestContext = new ContextHandler("/latest.json"); - latestContext.setAllowNullPathInfo(true); - latestContext.setHandler(new LatestHandler(mapper)); - - ContextHandler newsContext = new ContextHandler("/news.html"); - newsContext.setAllowNullPathInfo(true); - newsContext.setHandler(new NewsHandler()); - - ContextHandlerCollection contexts = new ContextHandlerCollection(); - contexts.setHandlers(new Handler[]{packagesContext, latestContext, newsContext, rootContext}); - - GzipHandler gzip = new GzipHandler(); - server.setHandler(gzip); - gzip.setHandler(contexts); - - return server; - } - -} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ModpackBuilder.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/ModpackBuilder.java deleted file mode 100644 index 3f0764a..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ModpackBuilder.java +++ /dev/null @@ -1,76 +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.concurrency.ProgressObservable; -import com.skcraft.launcher.LauncherException; -import com.skcraft.launcher.LauncherUtils; -import com.skcraft.launcher.builder.PackageBuilder; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; - -class ModpackBuilder implements Callable, ProgressObservable { - - private final File inputDir; - 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; - this.outputDir = outputDir; - this.version = version; - this.manifestFilename = manifestFilename; - this.clean = clean; - } - - @Override - public ModpackBuilder call() throws Exception { - if (clean) { - List failures = new ArrayList(); - - try { - LauncherUtils.interruptibleDelete(outputDir, failures); - } catch (IOException e) { - Thread.sleep(1000); - LauncherUtils.interruptibleDelete(outputDir, failures); - } - - if (failures.size() > 0) { - throw new LauncherException(failures.size() + " failed to delete", "There were " + failures.size() + " failures during cleaning."); - } - } - - //noinspection ResultOfMethodCallIgnored - outputDir.mkdirs(); - - String[] args = { - "--version", version, - "--manifest-dest", new File(outputDir, manifestFilename).getAbsolutePath(), - "-i", inputDir.getAbsolutePath(), - "-o", outputDir.getAbsolutePath() - }; - PackageBuilder.main(args); - - return this; - } - - @Override - public double getProgress() { - return -1; - } - - @Override - public String getStatus() { - return "Building modpack..."; - } -} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/NewsHandler.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/NewsHandler.java deleted file mode 100644 index 83e9338..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/NewsHandler.java +++ /dev/null @@ -1,39 +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 org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; - -public class NewsHandler extends AbstractHandler { - - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - response.setContentType("text/html; charset=utf-8"); - response.setStatus(HttpServletResponse.SC_OK); - - PrintWriter writer = response.getWriter(); - writer.write(""); - writer.write(""); - writer.write(""); - writer.write("Staging Tool"); - writer.write(""); - writer.write(""); - writer.write("

Welcome to the staging tool!

"); - writer.write(""); - writer.write(""); - - baseRequest.setHandled(true); - } - -} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/PackagesHandler.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/PackagesHandler.java deleted file mode 100644 index 797b111..0000000 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/PackagesHandler.java +++ /dev/null @@ -1,66 +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.internal.Lists; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.skcraft.launcher.model.modpack.Manifest; -import com.skcraft.launcher.model.modpack.ManifestInfo; -import com.skcraft.launcher.model.modpack.PackageList; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.util.List; - -public class PackagesHandler extends AbstractHandler { - - private final ObjectMapper mapper; - private final File baseDir; - - public PackagesHandler(ObjectMapper mapper, File baseDir) { - this.mapper = mapper; - this.baseDir = baseDir; - } - - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - response.setContentType("text/plain; charset=utf-8"); - response.setStatus(HttpServletResponse.SC_OK); - - List packages = Lists.newArrayList(); - PackageList packageList = new PackageList(); - packageList.setPackages(packages); - - File[] files = baseDir.listFiles(new PackageFileFilter()); - if (files != null) { - for (File file : files) { - Manifest manifest = mapper.readValue(file, Manifest.class); - ManifestInfo info = new ManifestInfo(); - info.setName(manifest.getName()); - info.setTitle(manifest.getTitle()); - info.setVersion(manifest.getVersion()); - info.setLocation(file.getName()); - packages.add(info); - } - } - - mapper.writeValue(response.getWriter(), packageList); - baseRequest.setHandled(true); - } - - private static class PackageFileFilter implements FileFilter { - @Override - public boolean accept(File pathname) { - return pathname.getName().toLowerCase().endsWith(".json"); - } - } -} 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 new file mode 100644 index 0000000..f5c9a90 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/ProjectDirectoryChooser.java @@ -0,0 +1,44 @@ +/* + * 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 new file mode 100644 index 0000000..87e2493 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/ProjectDirectoryDialog.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.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 index 1a73d69..29adc35 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolArguments.java +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolArguments.java @@ -12,10 +12,10 @@ import java.io.File; @Data -public class ToolArguments { +class ToolArguments { @Parameter(names = "--dir") - private File dir = new File("."); + 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 index a638d1a..c7ffd25 100644 --- a/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolsFrame.java +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/ToolsFrame.java @@ -19,13 +19,18 @@ @Data public class ToolsFrame extends JFrame { - private final JButton buildButton = new JButton("Build for Release", SwingHelper.readImageIcon(ToolsFrame.class, "build.png")); + 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("Re-open Console", SwingHelper.readImageIcon(ToolsFrame.class, "log.png")); - private final JButton docsButton = new JButton("View Documentation", SwingHelper.readImageIcon(ToolsFrame.class, "help.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"); @@ -40,22 +45,60 @@ private void initComponents() { JPanel container = new JPanel(); - container.setLayout(new MigLayout("fill, insets dialog, wrap 1", "", "")); + 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); } - container.add(buildButton, "grow, tag ok"); + 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"); - container.add(openConsoleButton, "grow, tag ok"); - container.add(docsButton, "grow, tag ok"); - add(container, BorderLayout.CENTER); + 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/java/com/skcraft/launcher/buildtools/http/LatestHandler.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LatestHandler.java new file mode 100644 index 0000000..19a805d --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LatestHandler.java @@ -0,0 +1,41 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.http; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.skcraft.launcher.selfupdate.LatestVersionInfo; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URL; + +class LatestHandler extends AbstractHandler { + + private final ObjectMapper mapper; + + public LatestHandler(ObjectMapper mapper) { + this.mapper = mapper; + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + response.setContentType("text/plain; charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + + LatestVersionInfo info = new LatestVersionInfo(); + info.setVersion("0.0.0"); + info.setUrl(new URL("http://localhost")); + mapper.writeValue(response.getWriter(), info); + + baseRequest.setHandled(true); + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LocalHttpServerBuilder.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LocalHttpServerBuilder.java new file mode 100644 index 0000000..ee10495 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/LocalHttpServerBuilder.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.buildtools.http; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.server.handler.ResourceHandler; +import org.eclipse.jetty.server.handler.gzip.GzipHandler; + +import java.io.File; + +public class LocalHttpServerBuilder { + + private File baseDir = new File("."); + private int port = 28888; + + public File getBaseDir() { + return baseDir; + } + + public LocalHttpServerBuilder setBaseDir(File baseDir) { + this.baseDir = baseDir; + return this; + } + + public int getPort() { + return port; + } + + public LocalHttpServerBuilder setPort(int port) { + this.port = port; + return this; + } + + public Server build() throws Exception { + Server server = new Server(port); + + ObjectMapper mapper = new ObjectMapper(); + + ResourceHandler resourceHandler = new ResourceHandler(); + resourceHandler.setDirectoriesListed(true); + resourceHandler.setResourceBase(baseDir.getAbsolutePath()); + resourceHandler.setMinMemoryMappedContentLength(-1); // Causes file locking on Windows + + ContextHandler rootContext = new ContextHandler(); + rootContext.setContextPath("/"); + rootContext.setHandler(resourceHandler); + + ContextHandler packagesContext = new ContextHandler("/packages.json"); + packagesContext.setAllowNullPathInfo(true); + packagesContext.setHandler(new PackagesHandler(mapper, baseDir)); + + ContextHandler latestContext = new ContextHandler("/latest.json"); + latestContext.setAllowNullPathInfo(true); + latestContext.setHandler(new LatestHandler(mapper)); + + ContextHandler newsContext = new ContextHandler("/news.html"); + newsContext.setAllowNullPathInfo(true); + newsContext.setHandler(new NewsHandler()); + + ContextHandlerCollection contexts = new ContextHandlerCollection(); + contexts.setHandlers(new Handler[]{packagesContext, latestContext, newsContext, rootContext}); + + GzipHandler gzip = new GzipHandler(); + server.setHandler(gzip); + gzip.setHandler(contexts); + + return server; + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/NewsHandler.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/NewsHandler.java new file mode 100644 index 0000000..763c5b2 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/NewsHandler.java @@ -0,0 +1,39 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.http; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +class NewsHandler extends AbstractHandler { + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + response.setContentType("text/html; charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + + PrintWriter writer = response.getWriter(); + writer.write(""); + writer.write(""); + writer.write(""); + writer.write("Staging Tool"); + writer.write(""); + writer.write(""); + writer.write("

Welcome to the staging tool!

"); + writer.write(""); + writer.write(""); + + baseRequest.setHandled(true); + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/PackagesHandler.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/PackagesHandler.java new file mode 100644 index 0000000..4ea72b6 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/http/PackagesHandler.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.buildtools.http; + +import com.beust.jcommander.internal.Lists; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.skcraft.launcher.model.modpack.Manifest; +import com.skcraft.launcher.model.modpack.ManifestInfo; +import com.skcraft.launcher.model.modpack.PackageList; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.List; + +class PackagesHandler extends AbstractHandler { + + private final ObjectMapper mapper; + private final File baseDir; + + public PackagesHandler(ObjectMapper mapper, File baseDir) { + this.mapper = mapper; + this.baseDir = baseDir; + } + + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + response.setContentType("text/plain; charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + + List packages = Lists.newArrayList(); + PackageList packageList = new PackageList(); + packageList.setPackages(packages); + + File[] files = baseDir.listFiles(new PackageFileFilter()); + if (files != null) { + for (File file : files) { + Manifest manifest = mapper.readValue(file, Manifest.class); + ManifestInfo info = new ManifestInfo(); + info.setName(manifest.getName()); + info.setTitle(manifest.getTitle()); + info.setVersion(manifest.getVersion()); + info.setLocation(file.getName()); + packages.add(info); + } + } + + mapper.writeValue(response.getWriter(), packageList); + baseRequest.setHandled(true); + } + + private static class PackageFileFilter implements FileFilter { + @Override + public boolean accept(File pathname) { + return pathname.getName().toLowerCase().endsWith(".json"); + } + } +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/BuilderConfigDialog.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/BuilderConfigDialog.java new file mode 100644 index 0000000..56193d0 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/BuilderConfigDialog.java @@ -0,0 +1,233 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.project; + +import com.google.common.base.Joiner; +import com.skcraft.launcher.builder.BuilderConfig; +import com.skcraft.launcher.builder.FeaturePattern; +import com.skcraft.launcher.builder.FnPatternList; +import com.skcraft.launcher.model.modpack.LaunchModifier; +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; + +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); + private final JTextArea launchFlagsArea = new JTextArea(10, 40); + private final JTextArea userFilesIncludeArea = new JTextArea(15, 40); + private final JTextArea userFilesExcludeArea = new JTextArea(8, 40); + private final FeaturePatternTable featuresTable = new FeaturePatternTable(); + private FeaturePatternTableModel featuresModel; + + private final BuilderConfig config; + private boolean saved = false; + + public BuilderConfigDialog(Window parent, BuilderConfig config) { + super(parent, "Edit modpack.json", ModalityType.DOCUMENT_MODAL); + + this.config = config; + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + setResizable(false); + pack(); + setLocationRelativeTo(parent); + + copyFrom(); + } + + private void initComponents() { + launchFlagsArea.setFont(nameText.getFont()); + userFilesIncludeArea.setFont(nameText.getFont()); + userFilesExcludeArea.setFont(nameText.getFont()); + + JTabbedPane tabbedPane = new JTabbedPane(); + + JPanel container = new JPanel(); + container.setLayout(new MigLayout("fill, insets dialog")); + + tabbedPane.addTab("Modpack", null, createMainPanel()); + tabbedPane.addTab("Launch", null, createLaunchPanel()); + tabbedPane.addTab("User Files", null, createUserFilesPanel()); + tabbedPane.addTab("Optional Features", null, createFeaturesPanel()); + + container.add(tabbedPane, "span, grow, gapbottom unrel"); + + JButton saveButton = new JButton("Save"); + JButton cancelButton = new JButton("Cancel"); + + container.add(saveButton, "tag ok, span, split 2, sizegroup bttn"); + container.add(cancelButton, "tag cancel, sizegroup bttn"); + + 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(); + } + }); + + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + } + + private JPanel createMainPanel() { + JPanel container = new JPanel(); + SwingHelper.removeOpaqueness(container); + container.setLayout(new MigLayout("insets dialog")); + + container.add(new JLabel("Name:")); + container.add(nameText, "span"); + + container.add(new JLabel("Title:")); + container.add(titleText, "span"); + + container.add(new JLabel("Game Version:")); + container.add(gameVersionText, "span"); + + return container; + } + + private JPanel createLaunchPanel() { + JPanel container = new JPanel(); + SwingHelper.removeOpaqueness(container); + container.setLayout(new MigLayout("insets dialog")); + + container.add(new JLabel("Launch Flags:"), "wrap"); + container.add(SwingHelper.wrapScrollPane(launchFlagsArea), "span"); + + return container; + } + + private JPanel createUserFilesPanel() { + JPanel container = new JPanel(); + SwingHelper.removeOpaqueness(container); + container.setLayout(new MigLayout("insets dialog")); + + container.add(new JLabel("Include Patterns:"), "wrap"); + container.add(SwingHelper.wrapScrollPane(userFilesIncludeArea), "span, gapbottom unrel"); + + container.add(new JLabel("Exclude Patterns:"), "wrap"); + container.add(SwingHelper.wrapScrollPane(userFilesExcludeArea), "span"); + + return container; + } + + private JPanel createFeaturesPanel() { + JPanel container = new JPanel(); + SwingHelper.removeOpaqueness(container); + container.setLayout(new MigLayout("fill, insets dialog")); + + JButton newButton = new JButton("New..."); + JButton editButton = new JButton("Edit..."); + JButton deleteButton = new JButton("Delete..."); + + container.add(newButton, "span, split 3, sizegroup bttn"); + container.add(editButton, "sizegroup bttn"); + container.add(deleteButton, "sizegroup bttn"); + + 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); + } + } + }); + + 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"); + } + } + }); + + 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"); + } + } + }); + + return container; + } + + private void copyFrom() { + 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())); + featuresModel = new FeaturePatternTableModel(config.getFeatures()); + featuresTable.setModel(featuresModel); + } + + private void copyTo() { + config.setName(nameText.getText().trim()); + config.setTitle(titleText.getText().trim()); + config.setGameVersion(gameVersionText.getText().trim()); + + LaunchModifier launchModifier = config.getLaunchModifier(); + FnPatternList userFiles = config.getUserFiles(); + + launchModifier.setFlags(SwingHelper.linesToList(launchFlagsArea.getText())); + userFiles.setInclude(SwingHelper.linesToList(userFilesIncludeArea.getText())); + userFiles.setExclude(SwingHelper.linesToList(userFilesExcludeArea.getText())); + } + + public static boolean showEditor(Window window, BuilderConfig config) { + BuilderConfigDialog dialog = new BuilderConfigDialog(window, config); + dialog.setVisible(true); + return dialog.saved; + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternDialog.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternDialog.java new file mode 100644 index 0000000..8c3a682 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternDialog.java @@ -0,0 +1,147 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.project; + +import com.google.common.base.Joiner; +import com.skcraft.launcher.builder.FeaturePattern; +import com.skcraft.launcher.builder.FnPatternList; +import com.skcraft.launcher.model.modpack.Feature; +import com.skcraft.launcher.model.modpack.Feature.Recommendation; +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; + +public class FeaturePatternDialog extends JDialog { + + private static final Joiner NEW_LINE_JOINER = Joiner.on("\n"); + + private final JTextField nameText = new JTextField(20); + private final JTextArea descArea = new JTextArea(3, 40); + private final JComboBox recommendationCombo = new JComboBox(new RecommendationComboBoxModel()); + private final JCheckBox selectedCheck = new JCheckBox("Selected by default"); + private final JTextArea includeArea = new JTextArea(8, 40); + private final JTextArea excludeArea = new JTextArea(3, 40); + + private final FeaturePattern pattern; + private boolean saved = false; + + public FeaturePatternDialog(Window parent, FeaturePattern pattern) { + super(parent, "Configure Feature", ModalityType.DOCUMENT_MODAL); + + this.pattern = pattern; + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + initComponents(); + setResizable(false); + pack(); + setLocationRelativeTo(parent); + + copyFrom(); + } + + private void initComponents() { + descArea.setFont(nameText.getFont()); + includeArea.setFont(nameText.getFont()); + excludeArea.setFont(nameText.getFont()); + + JPanel container = new JPanel(); + container.setLayout(new MigLayout("insets dialog")); + + container.add(new JLabel("Feature Name:")); + container.add(nameText, "span"); + + container.add(new JLabel("Recommendation:")); + container.add(recommendationCombo, "span"); + + container.add(selectedCheck, "span"); + + container.add(new JLabel("Description:"), "wrap"); + container.add(SwingHelper.wrapScrollPane(descArea), "span"); + + container.add(new JLabel("Include Patterns:"), "wrap"); + container.add(SwingHelper.wrapScrollPane(includeArea), "span"); + + container.add(new JLabel("Exclude Patterns:"), "wrap"); + container.add(SwingHelper.wrapScrollPane(excludeArea), "span, gapbottom unrel"); + + JButton okButton = new JButton("OK"); + JButton cancelButton = new JButton("Cancel"); + + container.add(okButton, "tag ok, span, split 2, sizegroup bttn"); + container.add(cancelButton, "tag cancel, sizegroup bttn"); + + 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(); + } + }); + + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + } + + private void copyFrom() { + if (pattern.getFeature() == null) { + pattern.setFeature(new Feature()); + } + + if (pattern.getFilePatterns() == null) { + pattern.setFilePatterns(new FnPatternList()); + } + + SwingHelper.setTextAndResetCaret(nameText, pattern.getFeature().getName()); + SwingHelper.setTextAndResetCaret(descArea, pattern.getFeature().getDescription()); + recommendationCombo.setSelectedItem(pattern.getFeature().getRecommendation()); + selectedCheck.setSelected(pattern.getFeature().isSelected()); + SwingHelper.setTextAndResetCaret(includeArea, NEW_LINE_JOINER.join(pattern.getFilePatterns().getInclude())); + SwingHelper.setTextAndResetCaret(excludeArea, NEW_LINE_JOINER.join(pattern.getFilePatterns().getExclude())); + } + + private void copyTo() { + pattern.getFeature().setName(nameText.getText().trim()); + pattern.getFeature().setDescription(descArea.getText().trim()); + pattern.getFeature().setRecommendation((Recommendation) recommendationCombo.getSelectedItem()); + pattern.getFeature().setSelected(selectedCheck.isSelected()); + pattern.getFilePatterns().setInclude(SwingHelper.linesToList(includeArea.getText())); + pattern.getFilePatterns().setExclude(SwingHelper.linesToList(excludeArea.getText())); + } + + public static boolean showEditor(Window window, FeaturePattern pattern) { + FeaturePatternDialog dialog = new FeaturePatternDialog(window, pattern); + dialog.setVisible(true); + return dialog.saved; + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTable.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTable.java new file mode 100644 index 0000000..9e69caf --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTable.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.buildtools.project; + +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); + } + + @Override + public void setModel(TableModel dataModel) { + super.setModel(dataModel); + try { + getColumnModel().getColumn(1).setMaxWidth(80); + getColumnModel().getColumn(2).setMaxWidth(80); + } catch (ArrayIndexOutOfBoundsException ignored) { + } + } +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTableModel.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTableModel.java new file mode 100644 index 0000000..bf84cb3 --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/FeaturePatternTableModel.java @@ -0,0 +1,97 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.project; + +import com.skcraft.launcher.builder.FeaturePattern; + +import javax.swing.table.AbstractTableModel; +import java.util.List; + +class FeaturePatternTableModel extends AbstractTableModel { + + private final List features; + + public FeaturePatternTableModel(List features) { + this.features = features; + } + + @Override + public String getColumnName(int columnIndex) { + switch (columnIndex) { + case 0: + return "Feature"; + case 1: + return "Recommendation"; + case 2: + return "Default?"; + default: + return null; + } + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case 0: + return String.class; + case 1: + return String.class; + case 2: + return String.class; + default: + return null; + } + } + + @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 features.size(); + } + + @Override + public int getColumnCount() { + return 3; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + return features.get(rowIndex).getFeature().getName(); + case 1: + return features.get(rowIndex).getFeature().getRecommendation(); + case 2: + return features.get(rowIndex).getFeature().isSelected() ? "Yes" : ""; + default: + return null; + } + } + + public FeaturePattern getFeature(int index) { + return features.get(index); + } + + public void addFeature(FeaturePattern pattern) { + features.add(pattern); + fireTableDataChanged(); + } + + public void removeFeature(int index) { + features.remove(index); + fireTableDataChanged(); + } + +} diff --git a/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/RecommendationComboBoxModel.java b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/RecommendationComboBoxModel.java new file mode 100644 index 0000000..04bbd5f --- /dev/null +++ b/build-tools/src/main/java/com/skcraft/launcher/buildtools/project/RecommendationComboBoxModel.java @@ -0,0 +1,40 @@ +/* + * SK's Minecraft Launcher + * Copyright (C) 2010-2014 Albert Pham and contributors + * Please see LICENSE.txt for license information. + */ + +package com.skcraft.launcher.buildtools.project; + +import com.skcraft.launcher.model.modpack.Feature.Recommendation; + +import javax.swing.*; + +class RecommendationComboBoxModel extends AbstractListModel implements ComboBoxModel { + + private Recommendation selection; + + @Override + public void setSelectedItem(Object anItem) { + selection = (Recommendation) anItem; + } + + @Override + public Object getSelectedItem() { + return selection; + } + + @Override + public int getSize() { + return Recommendation.values().length + 1; + } + + @Override + public Object getElementAt(int index) { + if (index == 0) { + return null; + } else { + return Recommendation.values()[index - 1]; + } + } +} diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/check.png b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/check.png new file mode 100644 index 0000000..aab0b96 --- /dev/null +++ b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/check.png Binary files differ diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/edit.png b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/edit.png new file mode 100644 index 0000000..6997784 --- /dev/null +++ b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/edit.png Binary files differ diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/open_folder.png b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/open_folder.png new file mode 100644 index 0000000..3d11f52 --- /dev/null +++ b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/open_folder.png Binary files differ diff --git a/build-tools/src/main/resources/com/skcraft/launcher/buildtools/server.png b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/server.png new file mode 100644 index 0000000..0c2c232 --- /dev/null +++ b/build-tools/src/main/resources/com/skcraft/launcher/buildtools/server.png Binary files differ diff --git a/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderConfig.java b/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderConfig.java index 658d619..5101417 100644 --- a/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderConfig.java +++ b/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderConfig.java @@ -7,6 +7,7 @@ package com.skcraft.launcher.builder; import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.Lists; import com.skcraft.launcher.model.modpack.LaunchModifier; import com.skcraft.launcher.model.modpack.Manifest; import lombok.Data; @@ -23,9 +24,21 @@ private String title; private String gameVersion; @JsonProperty("launch") - private LaunchModifier launchModifier; - private List features; - private FnPatternList userFiles; + private LaunchModifier launchModifier = new LaunchModifier(); + private List features = Lists.newArrayList(); + private FnPatternList userFiles = new FnPatternList(); + + public void setLaunchModifier(LaunchModifier launchModifier) { + this.launchModifier = launchModifier != null ? launchModifier : new LaunchModifier(); + } + + public void setFeatures(List features) { + this.features = features != null ? features : Lists.newArrayList(); + } + + public void setUserFiles(FnPatternList userFiles) { + this.userFiles = userFiles != null ? userFiles : new FnPatternList(); + } public void update(Manifest manifest) { manifest.updateName(getName()); diff --git a/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderOptions.java b/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderOptions.java index 793312e..8a62b86 100644 --- a/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderOptions.java +++ b/launcher-builder/src/main/java/com/skcraft/launcher/builder/BuilderOptions.java @@ -15,6 +15,11 @@ @Data public class BuilderOptions { + public static final String DEFAULT_CONFIG_FILENAME = "modpack.json"; + public static final String DEFAULT_VERSION_FILENAME = "version.json"; + public static final String DEFAULT_SRC_DIRNAME = "src"; + public static final String DEFAULT_LOADERS_DIRNAME = "loaders"; + // Configuration // Override config @@ -65,22 +70,22 @@ public void choosePaths() throws ParameterException { if (configPath == null) { requireInputPath("--config"); - configPath = new File(inputPath, "modpack.json"); + configPath = new File(inputPath, DEFAULT_CONFIG_FILENAME); } if (versionManifestPath == null) { requireInputPath("--version"); - versionManifestPath = new File(inputPath, "version.json"); + versionManifestPath = new File(inputPath, DEFAULT_VERSION_FILENAME); } if (filesDir == null) { requireInputPath("--files"); - filesDir = new File(inputPath, "src"); + filesDir = new File(inputPath, DEFAULT_SRC_DIRNAME); } if (loadersDir == null) { requireInputPath("--loaders"); - loadersDir = new File(inputPath, "loaders"); + loadersDir = new File(inputPath, DEFAULT_LOADERS_DIRNAME); } if (objectsDir == null) { diff --git a/launcher-builder/src/main/java/com/skcraft/launcher/builder/FeaturePattern.java b/launcher-builder/src/main/java/com/skcraft/launcher/builder/FeaturePattern.java index 01cbf93..13a2e71 100644 --- a/launcher-builder/src/main/java/com/skcraft/launcher/builder/FeaturePattern.java +++ b/launcher-builder/src/main/java/com/skcraft/launcher/builder/FeaturePattern.java @@ -16,7 +16,7 @@ @JsonProperty("properties") private Feature feature; @JsonProperty("files") - private FnPatternList filePatterns; + private FnPatternList filePatterns = new FnPatternList(); public boolean matches(String path) { return filePatterns != null && filePatterns.matches(path); diff --git a/launcher-builder/src/main/java/com/skcraft/launcher/builder/FnPatternList.java b/launcher-builder/src/main/java/com/skcraft/launcher/builder/FnPatternList.java index dd9c3b0..b800f8f 100644 --- a/launcher-builder/src/main/java/com/skcraft/launcher/builder/FnPatternList.java +++ b/launcher-builder/src/main/java/com/skcraft/launcher/builder/FnPatternList.java @@ -7,6 +7,7 @@ package com.skcraft.launcher.builder; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.google.common.collect.Lists; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -21,11 +22,19 @@ private static final EnumSet DEFAULT_FLAGS = EnumSet.of( FnMatch.Flag.CASEFOLD, FnMatch.Flag.PERIOD); - private List include; - private List exclude; + private List include = Lists.newArrayList(); + private List exclude = Lists.newArrayList(); @Getter @Setter @JsonIgnore private EnumSet flags = DEFAULT_FLAGS; + public void setInclude(List include) { + this.include = include != null ? include : Lists.newArrayList(); + } + + public void setExclude(List exclude) { + this.exclude = exclude != null ? exclude : Lists.newArrayList(); + } + public boolean matches(String path) { return include != null && matches(path, include) && (exclude == null || !matches(path, exclude)); } diff --git a/launcher/src/main/java/com/skcraft/launcher/model/modpack/LaunchModifier.java b/launcher/src/main/java/com/skcraft/launcher/model/modpack/LaunchModifier.java index e8b961a..5ad0226 100644 --- a/launcher/src/main/java/com/skcraft/launcher/model/modpack/LaunchModifier.java +++ b/launcher/src/main/java/com/skcraft/launcher/model/modpack/LaunchModifier.java @@ -6,6 +6,7 @@ package com.skcraft.launcher.model.modpack; +import com.google.common.collect.Lists; import com.skcraft.launcher.launch.JavaProcessBuilder; import lombok.Data; @@ -14,7 +15,11 @@ @Data public class LaunchModifier { - private List flags; + private List flags = Lists.newArrayList(); + + public void setFlags(List flags) { + this.flags = flags != null ? flags : Lists.newArrayList(); + } public void modify(JavaProcessBuilder builder) { if (flags != null) { 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 c6580a8..58d5646 100644 --- a/launcher/src/main/java/com/skcraft/launcher/persistence/Persistence.java +++ b/launcher/src/main/java/com/skcraft/launcher/persistence/Persistence.java @@ -6,6 +6,7 @@ package com.skcraft.launcher.persistence; +import com.fasterxml.jackson.core.PrettyPrinter; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.io.ByteSink; import com.google.common.io.ByteSource; @@ -14,7 +15,10 @@ import lombok.NonNull; import lombok.extern.java.Log; -import java.io.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; import java.util.WeakHashMap; import java.util.logging.Level; @@ -203,8 +207,24 @@ * @throws java.io.IOException on I/O error */ public static void write(File file, Object object) throws IOException { + write(file, object, null); + } + + /** + * Write an object to file. + * + * @param file the file + * @param object the object + * @param prettyPrinter a pretty printer to use, or null + * @throws java.io.IOException on I/O error + */ + public static void write(File file, Object object, PrettyPrinter prettyPrinter) throws IOException { file.getParentFile().mkdirs(); - mapper.writeValue(file, object); + if (prettyPrinter != null) { + mapper.writer(prettyPrinter).writeValue(file, object); + } else { + mapper.writeValue(file, object); + } } } diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/DirectoryField.java b/launcher/src/main/java/com/skcraft/launcher/swing/DirectoryField.java new file mode 100644 index 0000000..2feadad --- /dev/null +++ b/launcher/src/main/java/com/skcraft/launcher/swing/DirectoryField.java @@ -0,0 +1,104 @@ +/* + * 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 javax.swing.filechooser.FileFilter; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; + +public class DirectoryField extends JPanel { + + private static final long serialVersionUID = 5706210803738919578L; + + private final JTextField textField; + private final JButton browseButton; + + public DirectoryField() { + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + + textField = new JTextField(30); + textField.setMaximumSize(textField.getPreferredSize()); + add(textField); + + add(Box.createHorizontalStrut(3)); + + browseButton = new JButton("Browse..."); + browseButton.setPreferredSize(new Dimension( + browseButton.getPreferredSize().width, + textField.getPreferredSize().height)); + add(browseButton); + + browseButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + browse(); + } + }); + } + + public JTextField getTextField() { + return textField; + } + + public JButton getBrowseButton() { + return browseButton; + } + + public void setPath(String path) { + getTextField().setText(path); + } + + public String getPath() { + return getTextField().getText(); + } + + protected JFileChooser getFileChooser() { + JFileChooser chooser = new JFileChooser(); + chooser.setDialogTitle("Select folder"); + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + chooser.setFileFilter(new FileFilter() { + @Override + public boolean accept(File pathname) { + if (pathname.isDirectory()) return true; + return false; + } + + @Override + public String getDescription() { + return "Directories"; + } + }); + + return chooser; + } + + public void browse() { + JFileChooser chooser = getFileChooser(); + File f = new File(getPath()); + if (f.exists() && f.isFile()) { + f = f.getParentFile(); + } + chooser.setCurrentDirectory(f); + + int returnVal = chooser.showOpenDialog(this); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + setPath(chooser.getSelectedFile().getPath()); + } + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + getTextField().setEnabled(enabled); + getBrowseButton().setEnabled(enabled); + } + +} diff --git a/launcher/src/main/java/com/skcraft/launcher/swing/FileField.java b/launcher/src/main/java/com/skcraft/launcher/swing/FileField.java new file mode 100644 index 0000000..273852e --- /dev/null +++ b/launcher/src/main/java/com/skcraft/launcher/swing/FileField.java @@ -0,0 +1,44 @@ +/* + * 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.io.File; + +import javax.swing.JFileChooser; +import javax.swing.filechooser.FileFilter; + +public class FileField extends DirectoryField { + + private final String title; + private final String description; + + public FileField(String title, String description) { + this.title = title; + this.description = description; + } + + @Override + protected JFileChooser getFileChooser() { + JFileChooser chooser = new JFileChooser(); + chooser.setDialogTitle(title); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + chooser.setFileFilter(new FileFilter() { + @Override + public boolean accept(File pathname) { + return true; + } + + @Override + public String getDescription() { + return description; + } + }); + + return chooser; + } + +} 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 500a684..01f2998 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.collect.Lists; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -32,6 +33,7 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; +import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; @@ -386,6 +388,29 @@ return container; } + public static void setTextAndResetCaret(JTextComponent component, String text) { + component.setText(text); + component.setCaretPosition(0); + } + + public static JScrollPane wrapScrollPane(Component component) { + JScrollPane scrollPane = new JScrollPane(component); + scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + return scrollPane; + } + + public static List linesToList(String text) { + String[] tokens = text.replace("\r", "\n").split("\n"); + List values = Lists.newArrayList(); + for (String token : tokens) { + String value = token.trim(); + if (!value.isEmpty()) { + values.add(value); + } + } + return values; + } + public static boolean setLookAndFeel(String lookAndFeel) { try { UIManager.setLookAndFeel(lookAndFeel); @@ -395,5 +420,4 @@ return false; } } - }