Add new creator tools.
@ -1,462 +0,0 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<Instance> 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.<String>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<List<Problem>> future = new ObservableFuture<List<Problem>>(launcher.getExecutor().submit(runnable), runnable);
|
||||
ProgressDialog.showProgress(frame, future, "Checking for problems...", "Checking for problems...");
|
||||
|
||||
Futures.addCallback(future, new FutureCallback<List<Problem>>() {
|
||||
@Override
|
||||
public void onSuccess(List<Problem> 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<ModpackBuilder> future = new ObservableFuture<ModpackBuilder>(launcher.getExecutor().submit(runnable), runnable);
|
||||
ProgressDialog.showProgress(frame, future, "Building modpack...", "Building modpack for release...");
|
||||
|
||||
Futures.addCallback(future, new FutureCallback<ModpackBuilder>() {
|
||||
@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<ServerDeployer> future = new ObservableFuture<ServerDeployer>(launcher.getExecutor().submit(runnable), runnable);
|
||||
ProgressDialog.showProgress(frame, future, "Deploying files...", "Deploying server files...");
|
||||
|
||||
Futures.addCallback(future, new FutureCallback<ServerDeployer>() {
|
||||
@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<ModpackBuilder> future = new ObservableFuture<ModpackBuilder>(launcher.getExecutor().submit(runnable), runnable);
|
||||
ProgressDialog.showProgress(frame, future, "Preparing files...", "Preparing files for launch...");
|
||||
SwingHelper.addErrorDialogCallback(frame, future);
|
||||
|
||||
Futures.addCallback(future, new FutureCallback<ModpackBuilder>() {
|
||||
@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<DirectoryRemover> future = new ObservableFuture<DirectoryRemover>(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<DirectoryRemover> future = new ObservableFuture<DirectoryRemover>(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<InstanceList> future = new ObservableFuture<InstanceList>(launcher.getExecutor().submit(loader), loader);
|
||||
ProgressDialog.showProgress(window, future, "Loading modpacks...", "Loading modpacks...");
|
||||
SwingHelper.addErrorDialogCallback(window, future);
|
||||
|
||||
Futures.addCallback(future, new FutureCallback<InstanceList>() {
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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;
|
||||
}
|
||||
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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("<html>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;
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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;
|
||||
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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;
|
||||
}
|
||||
|
||||
}
|
Before Width: | Height: | Size: 3.4 KiB |
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<RecentEntry> recentEntries = config.getRecentEntries();
|
||||
Iterator<RecentEntry> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<ManifestEntry> manifestEntries;
|
||||
private final ListeningExecutorService executor;
|
||||
private final ManifestEntryTableModel manifestTableModel;
|
||||
|
||||
public GenerateListingController(GenerateListingDialog dialog, Workspace workspace, List<ManifestEntry> 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<ManifestEntry> getManifestFromIndex(int selectedIndex) {
|
||||
if (selectedIndex >= 0) {
|
||||
ManifestEntry manifest = manifestEntries.get(selectedIndex);
|
||||
if (manifest != null) {
|
||||
return Optional.fromNullable(manifest);
|
||||
}
|
||||
}
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
public Optional<ManifestEntry> 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<ManifestEntry> 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<ManifestEntry> 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<ManifestEntry> 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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,752 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<Pack> 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<Pack> 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<Pack> 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<Pack> 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.<String>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<Pack> 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<Pack> 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<Pack> 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<Pack> 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<Pack> 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<Pack> 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<Pack> optional = getSelectedPack(true);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
SwingHelper.browseDir(optional.get().getDirectory(), frame);
|
||||
}
|
||||
});
|
||||
|
||||
frame.getCheckProblemsMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> 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<Pack> 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<Pack> optional = getSelectedPack(true);
|
||||
|
||||
if (optional.isPresent()) {
|
||||
Pack pack = optional.get();
|
||||
buildPack(pack);
|
||||
}
|
||||
});
|
||||
|
||||
frame.getDeployServerMenuItem().addActionListener(e -> {
|
||||
Optional<Pack> 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<ManifestEntry> 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<Problem> 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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<RecentEntry> 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<RecentEntry> getSelectedRecentEntry() {
|
||||
int selectedIndex = dialog.getRecentList().getSelectedIndex();
|
||||
if (selectedIndex >= 0) {
|
||||
return Optional.fromNullable(creator.getConfig().getRecentEntries().get(selectedIndex));
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<File> 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<RecentEntry> table = (JList<RecentEntry>) e.getSource();
|
||||
Point point = e.getPoint();
|
||||
int selectedIndex = table.locationToIndex(point);
|
||||
if (selectedIndex >= 0) {
|
||||
table.setSelectedIndex(selectedIndex);
|
||||
Optional<RecentEntry> optional = getSelectedRecentEntry();
|
||||
if (optional.isPresent()) {
|
||||
if (openWorkspace(optional.get().getPath())) {
|
||||
dialog.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.getRecentList().addMouseListener(new PopupMouseAdapter() {
|
||||
@Override
|
||||
protected void showPopup(MouseEvent e) {
|
||||
JList<RecentEntry> table = (JList<RecentEntry>) e.getSource();
|
||||
Point point = e.getPoint();
|
||||
int selectedIndex = table.locationToIndex(point);
|
||||
if (selectedIndex >= 0) {
|
||||
table.setSelectedIndex(selectedIndex);
|
||||
Optional<RecentEntry> optional = getSelectedRecentEntry();
|
||||
if (optional.isPresent()) {
|
||||
popupRecentWorkspaceMenu(e.getComponent(), e.getX(), e.getY(), optional.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.getNewButton().addActionListener(e -> {
|
||||
Optional<File> 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<File> 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);
|
||||
}
|
||||
|
||||
}
|
@ -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<DirectoryRemover>, ProgressObservable {
|
||||
public class DirectoryDeleter implements Callable<File>, 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<File> failures = new ArrayList<File>();
|
||||
|
||||
@ -42,10 +38,10 @@ public class DirectoryRemover implements Callable<DirectoryRemover>, 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<DirectoryRemover>, ProgressObs
|
||||
|
||||
@Override
|
||||
public String getStatus() {
|
||||
return "Removing files...";
|
||||
return "Deleting files...";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<ManifestEntry>, List<ManifestEntry>> {
|
||||
|
||||
private final File searchDir;
|
||||
|
||||
public ManifestInfoEnumerator(File searchDir) {
|
||||
this.searchDir = searchDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ManifestEntry> apply(List<ManifestEntry> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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<ModpackBuilder>, ProgressObservable {
|
||||
public class PackBuilder implements Callable<PackBuilder>, 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<ModpackBuilder>, ProgressObserva
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModpackBuilder call() throws Exception {
|
||||
public PackBuilder call() throws Exception {
|
||||
if (clean) {
|
||||
List<File> failures = new ArrayList<File>();
|
||||
|
||||
@ -56,7 +57,7 @@ public class ModpackBuilder implements Callable<ModpackBuilder>, 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);
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<Workspace, List<Pack>> {
|
||||
|
||||
private int index;
|
||||
private int size = 0;
|
||||
private Pack lastPack;
|
||||
|
||||
@Override
|
||||
public List<Pack> apply(Workspace workspace) {
|
||||
List<Pack> 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...";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<List<Problem>>, 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<Problem> call() throws Exception {
|
||||
List<Problem> 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<List<Problem>>, ProgressObservab
|
||||
|
||||
@Override
|
||||
public String getStatus() {
|
||||
return status;
|
||||
return "Checking for problems...";
|
||||
}
|
||||
|
||||
private static boolean hasFiles(File dir) {
|
@ -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<ServerDeployer>, ProgressObservable {
|
||||
public class ServerDeploy implements Callable<ServerDeploy>, 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()) {
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<InstanceList, Instance>, 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<Instance> findInstance(List<Instance> instances) {
|
||||
for (Instance instance : instances) {
|
||||
if (instance.getName().equals(id)) {
|
||||
return Optional.fromNullable(instance);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instance apply(InstanceList instanceList) {
|
||||
Optional<Instance> 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...";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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("<html>Version " + version), "wrap");
|
||||
container.add(new JLabel("<html>Licensed under GNU General Public License, version 3."), "wrap, gapbottom unrel");
|
||||
container.add(new JLabel("<html>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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
@ -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();
|
||||
}
|
@ -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() {
|
@ -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) {
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<ListingType> 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("<html>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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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());
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<RecentEntry> 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<RecentEntry> recentEntries = Lists.newArrayList();
|
||||
|
||||
public void setRecentEntries(List<RecentEntry> 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();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<ManifestEntry> {
|
||||
|
||||
private boolean selected = false;
|
||||
private ManifestInfo manifestInfo;
|
||||
private List<String> gameKeys = Lists.newArrayList();
|
||||
|
||||
@Override
|
||||
public int compareTo(ManifestEntry o) {
|
||||
return manifestInfo.compareTo(o.getManifestInfo());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<Pack> packs = Lists.newArrayList();
|
||||
private List<ManifestEntry> packageListingEntries = Lists.newArrayList();
|
||||
private ListingType packageListingType = ListingType.STATIC;
|
||||
|
||||
public void setPacks(List<Pack> packs) {
|
||||
this.packs = packs != null ? packs : Lists.<Pack>newArrayList();
|
||||
}
|
||||
|
||||
public void setPackageListingEntries(List<ManifestEntry> 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);
|
||||
}
|
||||
|
||||
}
|
@ -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<FeaturePattern> features;
|
||||
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<ManifestEntry> 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<ManifestEntry> entries) throws IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<?php\r\n");
|
||||
builder.append("$keys = isset($_GET['key']) ? array_map('trim', explode(',', strtolower($_GET['key']))) : [];\r\n");
|
||||
builder.append("$packages = [];\r\n\r\n");
|
||||
|
||||
for (ManifestEntry entry : entries) {
|
||||
ManifestInfo info = entry.getManifestInfo();
|
||||
List<String> 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<String> 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<ManifestEntry> entries) throws IOException;
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.launcher.creator.model.swing;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class ListingTypeComboBoxModel extends AbstractListModel<ListingType> implements ComboBoxModel<ListingType> {
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<ManifestEntry> entries;
|
||||
|
||||
public ManifestEntryTableModel(List<ManifestEntry> 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<String> gameKeys = entry.getGameKeys();
|
||||
return gameKeys != null ? GAME_KEY_JOINER.join(gameKeys) : "";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<Pack> packs;
|
||||
|
||||
public PackTableModel(List<Pack> 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() : "<Moved or Deleted>";
|
||||
case 2:
|
||||
return config != null ? config.getTitle() : "?";
|
||||
case 3:
|
||||
return config != null ? config.getGameVersion() : "?";
|
||||
case 4:
|
||||
return pack.getLocation();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<Problem> problems;
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<RecentEntry> {
|
||||
|
||||
private final List<RecentEntry> recentEntries;
|
||||
|
||||
public RecentListModel(List<RecentEntry> 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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";
|
||||
}
|
||||
|
||||
}
|
After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 601 B After Width: | Height: | Size: 601 B |
Before Width: | Height: | Size: 861 B After Width: | Height: | Size: 861 B |
Before Width: | Height: | Size: 899 B After Width: | Height: | Size: 899 B |
@ -0,0 +1,7 @@
|
||||
#
|
||||
# SK's Minecraft Launcher
|
||||
# Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
# Please see LICENSE.txt for license information.
|
||||
#
|
||||
|
||||
version=${project.version}
|
Before Width: | Height: | Size: 620 B After Width: | Height: | Size: 620 B |
Before Width: | Height: | Size: 792 B After Width: | Height: | Size: 792 B |
Before Width: | Height: | Size: 647 B After Width: | Height: | Size: 647 B |
After Width: | Height: | Size: 540 B |
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
After Width: | Height: | Size: 685 B |
Before Width: | Height: | Size: 431 B After Width: | Height: | Size: 431 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 541 B After Width: | Height: | Size: 541 B |
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 752 B |
Before Width: | Height: | Size: 534 B After Width: | Height: | Size: 534 B |
After Width: | Height: | Size: 14 KiB |
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
13
launcher/src/main/java/com/skcraft/concurrency/Callback.java
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors
|
||||
* Please see LICENSE.txt for license information.
|
||||
*/
|
||||
|
||||
package com.skcraft.concurrency;
|
||||
|
||||
public interface Callback<T> {
|
||||
|
||||
void handle(T value);
|
||||
|
||||
}
|
142
launcher/src/main/java/com/skcraft/concurrency/Deferred.java
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @param <I> The type returned
|
||||
*/
|
||||
public interface Deferred<I> extends ListenableFuture<I> {
|
||||
|
||||
/**
|
||||
* 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 <O> The return type of the task
|
||||
* @return The new Deferred
|
||||
*/
|
||||
<O> Deferred<O> thenRun(Callable<O> 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 <O> The return type of the task
|
||||
* @return The new Deferred
|
||||
*/
|
||||
<O> Deferred<O> thenRunAsync(Callable<O> 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<Void> 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<Void> 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.
|
||||
*
|
||||
* <p>The given action is only executed in the default executor upon the
|
||||
* normal completion of this Deferred.</p>
|
||||
*
|
||||
* @param task The task
|
||||
* @return The new Deferred
|
||||
*/
|
||||
Deferred<I> 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.
|
||||
*
|
||||
* <p>The given action is only executed in the provided executor upon the
|
||||
* normal completion of this Deferred.</p>
|
||||
*
|
||||
* @param task The task
|
||||
* @return The new Deferred
|
||||
*/
|
||||
Deferred<I> 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.
|
||||
*
|
||||
* <p>The given action is only executed in the default executor upon the
|
||||
* normal completion of this Deferred.</p>
|
||||
*
|
||||
* @param function The function
|
||||
* @return The new Deferred
|
||||
*/
|
||||
<O> Deferred<O> thenApply(Function<I, O> 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.
|
||||
*
|
||||
* <p>The given action is only executed in the provided executor upon the
|
||||
* normal completion of this Deferred.</p>
|
||||
*
|
||||
* @param function The function
|
||||
* @return The new Deferred
|
||||
*/
|
||||
<O> Deferred<O> thenApplyAsync(Function<I, O> 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<I> handle(Callback<I> onSuccess, Callback<Throwable> 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<I> handleAsync(Callback<I> onSuccess, Callback<Throwable> onFailure, ListeningExecutorService executor);
|
||||
|
||||
}
|
140
launcher/src/main/java/com/skcraft/concurrency/DeferredImpl.java
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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<I> implements Deferred<I> {
|
||||
|
||||
private final ListenableFuture<I> future;
|
||||
private final ListeningExecutorService defaultExecutor;
|
||||
|
||||
DeferredImpl(ListenableFuture<I> future, ListeningExecutorService defaultExecutor) {
|
||||
this.future = future;
|
||||
this.defaultExecutor = defaultExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <O> Deferred<O> thenRun(Callable<O> task) {
|
||||
return thenRunAsync(task, defaultExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <O> Deferred<O> thenRunAsync(final Callable<O> task, ListeningExecutorService executor) {
|
||||
return new DeferredImpl<O>(Futures.transform(future, new Function<I, O>() {
|
||||
@Override
|
||||
public O apply(I input) {
|
||||
try {
|
||||
return task.call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}, executor), defaultExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Void> thenRun(Runnable task) {
|
||||
return thenRunAsync(task, defaultExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Void> thenRunAsync(final Runnable task, ListeningExecutorService executor) {
|
||||
return new DeferredImpl<Void>(Futures.transform(future, new Function<I, Void>() {
|
||||
@Override
|
||||
public Void apply(I input) {
|
||||
task.run();
|
||||
return null;
|
||||
}
|
||||
}), defaultExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<I> thenTap(Runnable task) {
|
||||
return thenTapAsync(task, defaultExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<I> thenTapAsync(final Runnable task, ListeningExecutorService executor) {
|
||||
return thenApplyAsync(new Function<I, I>() {
|
||||
@Override
|
||||
public I apply(I input) {
|
||||
task.run();
|
||||
return input;
|
||||
}
|
||||
}, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <O> Deferred<O> thenApply(Function<I, O> function) {
|
||||
return thenApplyAsync(function, defaultExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <O> Deferred<O> thenApplyAsync(Function<I, O> function, ListeningExecutorService executor) {
|
||||
return new DeferredImpl<O>(Futures.transform(future, function, executor), defaultExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<I> handle(Callback<I> onSuccess, Callback<Throwable> onFailure) {
|
||||
return handleAsync(onSuccess, onFailure, defaultExecutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<I> handleAsync(final Callback<I> onSuccess, final Callback<Throwable> onFailure, ListeningExecutorService executor) {
|
||||
Futures.addCallback(future, new FutureCallback<I>() {
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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 <V> The type returned by the future
|
||||
* @return A new Deferred
|
||||
*/
|
||||
public static <V> Deferred<V> makeDeferred(ListenableFuture<V> future) {
|
||||
return makeDeferred(future, MoreExecutors.sameThreadExecutor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new Deferred from the given future.
|
||||
*
|
||||
* @param future The future
|
||||
* @param executor The default executor
|
||||
* @param <V> The type returned by the future
|
||||
* @return A new Deferred
|
||||
*/
|
||||
public static <V> Deferred<V> makeDeferred(ListenableFuture<V> future, ListeningExecutorService executor) {
|
||||
return new DeferredImpl<V>(future, executor);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
@ -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<ProgressDialog>(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<Object>() {
|
||||
@Override
|
||||
|
@ -11,9 +11,20 @@ import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ManifestInfo extends BaseManifest {
|
||||
public class ManifestInfo extends BaseManifest implements Comparable<ManifestInfo> {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ import java.util.List;
|
||||
@Data
|
||||
public class PackageList {
|
||||
|
||||
public static final int MIN_VERSION = 1;
|
||||
|
||||
private int minimumVersion;
|
||||
private List<ManifestInfo> packages;
|
||||
|
||||
|
@ -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<Object, ByteSink> bound =
|
||||
new WeakHashMap<Object, ByteSink>();
|
||||
private static final WeakHashMap<Object, ByteSink> bound = new WeakHashMap<Object, ByteSink>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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);
|
||||
}
|
||||
|
||||
}
|
@ -41,6 +41,8 @@ public class DirectoryField extends JPanel {
|
||||
browse();
|
||||
}
|
||||
});
|
||||
|
||||
textField.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
|
||||
}
|
||||
|
||||
public JTextField getTextField() {
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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<String> lines) {
|
||||
return SwingHelper.NEW_LINE_JOINER.join(lines);
|
||||
}
|
||||
|
||||
public static List<String> linesToList(String text) {
|
||||
String[] tokens = text.replace("\r", "\n").split("\n");
|
||||
List<String> 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);
|
||||
|
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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.
|
||||
*
|
||||
* <p>From https://tips4java.wordpress.com/2008/11/10/table-column-adjuster/</p>
|
||||
*/
|
||||
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<TableColumn, Integer> columnSizes = new HashMap<TableColumn, Integer>();
|
||||
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SK's Minecraft Launcher
|
||||
* Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> 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();
|
||||
}
|
||||
|
||||
}
|
@ -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 <T> RunnableFuture<T> newTaskFor(final Callable<T> callable) {
|
||||
return new FutureTask<T>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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'
|
||||
|