1
0
mirror of https://github.com/SKCraft/Launcher.git synced 2025-01-20 21:21:19 +01:00

Add new creator tools.

This commit is contained in:
sk89q 2015-07-23 23:46:18 -07:00
parent c87fae842b
commit 0cc95225dd
91 changed files with 3835 additions and 986 deletions

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -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")
}
}

View File

@ -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);
}
});
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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...";
}
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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...";
}
}
}

View File

@ -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) {

View File

@ -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()) {

View File

@ -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...";
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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() {

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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];
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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";
}
}

View File

@ -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";
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -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}

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -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);
}
}

View 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);
}

View 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);
}

View 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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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) {
}
}
}

View File

@ -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);
}
}

View File

@ -41,6 +41,8 @@ public class DirectoryField extends JPanel {
browse();
}
});
textField.setComponentPopupMenu(TextFieldPopupMenu.INSTANCE);
}
public JTextField getTextField() {

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);

View File

@ -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();
}
}
});
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}
}

View File

@ -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'