Fixed handshake failed connecting with minecraft asset site

This commit is contained in:
huangyuhui 2017-01-26 15:07:57 +08:00
parent 574532f10c
commit 627e632120
19 changed files with 225 additions and 245 deletions

View File

@ -25,7 +25,7 @@ install: echo "skip 'gradle assemble' step"
script: gradle build --continue script: gradle build --continue
before_cache: before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
cache: #cache:
directories: # directories:
- "$HOME/.gradle/caches/" # - "$HOME/.gradle/caches/"
- "$HOME/.gradle/wrapper/" # - "$HOME/.gradle/wrapper/"

View File

@ -64,7 +64,7 @@ public class MojangDownloadProvider extends IDownloadProvider {
@Override @Override
public String getAssetsDownloadURL() { public String getAssetsDownloadURL() {
return "https://resources.download.minecraft.net/"; return "http://resources.download.minecraft.net/";
} }
@Override @Override

View File

@ -94,17 +94,23 @@ public class MinecraftModService extends IMinecraftModService {
} }
@Override @Override
public void removeMod(String id, Object[] rows) { public boolean removeMod(String id, Object[] rows) {
if (rows.length == 0) if (rows.length == 0)
return; return true;
boolean flag = true;
for (Object r : rows) for (Object r : rows)
if (r instanceof ModInfo) { if (r instanceof ModInfo) {
if (!((ModInfo) r).location.delete()) if (!((ModInfo) r).location.delete()) {
HMCLog.warn("Failed to delete mod" + r); HMCLog.warn("Failed to delete mod" + r);
flag = false;
}
} else if (r instanceof Number) } else if (r instanceof Number)
if (!getMods(id).get(((Number) r).intValue()).location.delete()) if (!getMods(id).get(((Number) r).intValue()).location.delete()) {
HMCLog.warn("Failed to delete mod " + r + ", maybe not a file?"); HMCLog.warn("Failed to delete mod " + r + ", maybe not a file?");
flag = false;
}
recacheMods(id); recacheMods(id);
return flag;
} }
public String[] checkMd5s(String id) throws IOException { public String[] checkMd5s(String id) throws IOException {

View File

@ -37,5 +37,5 @@ public abstract class IMinecraftModService extends IMinecraftBasicService {
public abstract boolean addMod(String id, File f); public abstract boolean addMod(String id, File f);
public abstract void removeMod(String id, Object[] mods); public abstract boolean removeMod(String id, Object[] mods);
} }

View File

@ -113,16 +113,16 @@ public class MinecraftVersionManager extends IMinecraftProvider {
try { try {
mcVersion = C.GSON.fromJson(FileUtils.read(jsonFile), MinecraftVersion.class); mcVersion = C.GSON.fromJson(FileUtils.read(jsonFile), MinecraftVersion.class);
if (mcVersion == null) if (mcVersion == null)
throw new GameException("Wrong json format, got null."); throw new JsonSyntaxException("Wrong json format, got null.");
} catch (JsonSyntaxException | IOException | GameException e) { } catch (JsonSyntaxException | IOException e) {
HMCLog.warn("Found wrong format json, try to fix it.", e); HMCLog.warn("Found wrong format json, try to fix it.", e);
if (MessageBox.show(C.i18n("launcher.versions_json_not_formatted", id), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION) { if (MessageBox.show(C.i18n("launcher.versions_json_not_formatted", id), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION) {
service.download().downloadMinecraftVersionJson(id); service.download().downloadMinecraftVersionJson(id);
try { try {
mcVersion = C.GSON.fromJson(FileUtils.read(jsonFile), MinecraftVersion.class); mcVersion = C.GSON.fromJson(FileUtils.read(jsonFile), MinecraftVersion.class);
if (mcVersion == null) if (mcVersion == null)
throw new GameException("Wrong json format, got null."); throw new JsonSyntaxException("Wrong json format, got null.");
} catch (IOException | GameException | JsonSyntaxException ex) { } catch (IOException | JsonSyntaxException ex) {
HMCLog.warn("Ignoring: " + dir + ", the json of this Minecraft is malformed.", ex); HMCLog.warn("Ignoring: " + dir + ", the json of this Minecraft is malformed.", ex);
continue; continue;
} }

View File

@ -129,7 +129,7 @@ public final class Main implements Runnable {
try { try {
File file = new File("hmcl.log"); File file = new File("hmcl.log");
if (!file.exists() && !file.createNewFile()) if (!file.exists() && !file.createNewFile())
HMCLog.warn("Failed to create log file " + file); LOGGER.log(Level.WARNING, "Failed to create log file {0}", file);
Configuration.DEFAULT.appenders.add(new ConsoleAppender("File", new DefaultLayout(), true, new FileOutputStream(file), true)); Configuration.DEFAULT.appenders.add(new ConsoleAppender("File", new DefaultLayout(), true, new FileOutputStream(file), true));
} catch (IOException ex) { } catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Failed to add log appender File because an error occurred while creating or opening hmcl.log", ex); LOGGER.log(Level.SEVERE, "Failed to add log appender File because an error occurred while creating or opening hmcl.log", ex);
@ -144,9 +144,6 @@ public final class Main implements Runnable {
Locale.setDefault(sl.self); Locale.setDefault(sl.self);
} }
LogWindow.INSTANCE.clean();
LogWindow.INSTANCE.setTerminateGame(GameLauncher.PROCESS_MANAGER::stopAllProcesses);
try { try {
LOOK_AND_FEEL = new HelloMinecraftLookAndFeel(Settings.getInstance().getTheme().settings); LOOK_AND_FEEL = new HelloMinecraftLookAndFeel(Settings.getInstance().getTheme().settings);
UIManager.setLookAndFeel(LOOK_AND_FEEL); UIManager.setLookAndFeel(LOOK_AND_FEEL);
@ -154,6 +151,9 @@ public final class Main implements Runnable {
} catch (ParseException | UnsupportedLookAndFeelException ex) { } catch (ParseException | UnsupportedLookAndFeelException ex) {
HMCLog.warn("Failed to set look and feel...", ex); HMCLog.warn("Failed to set look and feel...", ex);
} }
LogWindow.INSTANCE.clean();
LogWindow.INSTANCE.setTerminateGame(GameLauncher.PROCESS_MANAGER::stopAllProcesses);
Settings.UPDATE_CHECKER.outOfDateEvent.register(IUpgrader.NOW_UPGRADER); Settings.UPDATE_CHECKER.outOfDateEvent.register(IUpgrader.NOW_UPGRADER);
Settings.UPDATE_CHECKER.process(false).reg(t -> Main.invokeUpdate()).execute(); Settings.UPDATE_CHECKER.process(false).reg(t -> Main.invokeUpdate()).execute();

View File

@ -132,7 +132,7 @@ public class CrashReporter implements Thread.UncaughtExceptionHandler {
private static final HashSet<String> THROWABLE_SET = new HashSet<>(); private static final HashSet<String> THROWABLE_SET = new HashSet<>();
void reportToServer(final String text, String stacktrace) { void reportToServer(final String text, String stacktrace) {
if (THROWABLE_SET.contains(stacktrace) || stacktrace.contains("Font")) if (THROWABLE_SET.contains(stacktrace) || stacktrace.contains("Font") || stacktrace.contains("InternalError"))
return; return;
THROWABLE_SET.add(stacktrace); THROWABLE_SET.add(stacktrace);
Thread t = new Thread(() -> { Thread t = new Thread(() -> {

View File

@ -19,6 +19,7 @@ package org.jackhuang.hellominecraft.lookandfeel;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import org.jackhuang.hellominecraft.util.C; import org.jackhuang.hellominecraft.util.C;
/** /**
@ -85,9 +86,7 @@ public enum Theme {
public final Map<String, String> settings; public final Map<String, String> settings;
private Theme(String localizedName, Map<String, String> settings) { private Theme(String localizedName, Map<String, String> settings) {
if (settings == null)
throw new NullPointerException("Theme settings map should not be null.");
this.localizedName = localizedName; this.localizedName = localizedName;
this.settings = settings; this.settings = Objects.requireNonNull(settings, "Theme settings map may not be null.");
} }
} }

View File

@ -48,14 +48,12 @@ public abstract class AbstractSwingWorker<T> extends SwingWorker<Void, T> {
} }
public AbstractSwingWorker reg(Consumer<T> c) { public AbstractSwingWorker reg(Consumer<T> c) {
Objects.requireNonNull(c); processListeners.add(Objects.requireNonNull(c));
processListeners.add(c);
return this; return this;
} }
public AbstractSwingWorker regDone(Runnable c) { public AbstractSwingWorker regDone(Runnable c) {
Objects.requireNonNull(c); doneListeners.add(Objects.requireNonNull(c));
doneListeners.add(c);
return this; return this;
} }

View File

@ -28,6 +28,7 @@ import java.nio.file.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import org.jackhuang.hellominecraft.util.logging.HMCLog; import org.jackhuang.hellominecraft.util.logging.HMCLog;
/** /**
@ -121,8 +122,7 @@ public final class FileUtils {
public static boolean isSymlink(File file) public static boolean isSymlink(File file)
throws IOException { throws IOException {
if (file == null) Objects.requireNonNull(file, "File must not be null");
throw new NullPointerException("File must not be null");
if (File.separatorChar == '\\') if (File.separatorChar == '\\')
return false; return false;
File fileInCanonicalDir; File fileInCanonicalDir;
@ -143,10 +143,8 @@ public final class FileUtils {
public static void copyDirectory(File srcDir, File destDir, FileFilter filter) public static void copyDirectory(File srcDir, File destDir, FileFilter filter)
throws IOException { throws IOException {
if (srcDir == null) Objects.requireNonNull(srcDir, "Source must not be null");
throw new NullPointerException("Source must not be null"); Objects.requireNonNull(destDir, "Destination must not be null");
if (destDir == null)
throw new NullPointerException("Destination must not be null");
if (!srcDir.exists()) if (!srcDir.exists())
throw new FileNotFoundException("Source '" + srcDir + "' does not exist"); throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
if (!srcDir.isDirectory()) if (!srcDir.isDirectory())
@ -230,10 +228,8 @@ public final class FileUtils {
public static void copyFile(File srcFile, File destFile) public static void copyFile(File srcFile, File destFile)
throws IOException { throws IOException {
if (srcFile == null) Objects.requireNonNull(srcFile, "Source must not be null");
throw new NullPointerException("Source must not be null"); Objects.requireNonNull(destFile, "Destination must not be null");
if (destFile == null)
throw new NullPointerException("Destination must not be null");
if (!srcFile.exists()) if (!srcFile.exists())
throw new FileNotFoundException("Source '" + srcFile + "' does not exist"); throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
if (srcFile.isDirectory()) if (srcFile.isDirectory())

View File

@ -36,10 +36,8 @@ public class LogWindowOutputStream extends OutputStream {
private final Level sas; private final Level sas;
public LogWindowOutputStream(LogWindow logWindow, Level l) { public LogWindowOutputStream(LogWindow logWindow, Level l) {
Objects.requireNonNull(logWindow); txt = Objects.requireNonNull(logWindow);
Objects.requireNonNull(l); sas = Objects.requireNonNull(l);
txt = logWindow;
sas = l;
} }
@Override @Override

View File

@ -19,6 +19,7 @@ package org.jackhuang.hellominecraft.util.ui.wizard.spi;
import javax.swing.*; import javax.swing.*;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.Objects;
/** /**
* A Wizard with indeterminate branches. The actual branch decision-making is * A Wizard with indeterminate branches. The actual branch decision-making is
@ -105,8 +106,7 @@ final class BranchingWizard extends AbstractWizard {
if (activeWizard == wizard) if (activeWizard == wizard)
return; return;
if (wizard == null) Objects.requireNonNull(wizard, "Can't set current wizard to null");
throw new NullPointerException("Can't set current wizard to null");
if ((activeWizard != null) && (wl != null)) if ((activeWizard != null) && (wl != null))
activeWizard.removeWizardObserver(wl); activeWizard.removeWizardObserver(wl);
@ -260,15 +260,10 @@ final class BranchingWizard extends AbstractWizard {
@Override @Override
public final JComponent navigatingTo(String id, Map settings) { public final JComponent navigatingTo(String id, Map settings) {
if (id == null) currStep = Objects.requireNonNull(id);
throw new NullPointerException();
currStep = id;
wizardData = settings; wizardData = settings;
WizardImplementation impl = ownerOf(id); WizardImplementation impl = Objects.requireNonNull(ownerOf(id), "No owning WizardImplementation for id " + id);
if (impl == null)
throw new NullPointerException("No owning WizardImplementation for"
+ " id " + id);
setCurrent(impl); setCurrent(impl);
return activeWizard.navigatingTo(id, settings); return activeWizard.navigatingTo(id, settings);

View File

@ -25,6 +25,7 @@ import java.lang.ref.WeakReference;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
@ -59,12 +60,8 @@ public final class SimpleWizardInfo implements WizardControllerImplementation {
* and descriptions. * and descriptions.
*/ */
protected SimpleWizardInfo(String title, String[] steps, String[] descriptions, WizardPanelProvider provider) { protected SimpleWizardInfo(String title, String[] steps, String[] descriptions, WizardPanelProvider provider) {
if (steps == null) this.steps = Objects.requireNonNull(steps, "Null steps");
throw new NullPointerException("Null steps"); this.descriptions = Objects.requireNonNull(descriptions, "Null descriptions");
if (descriptions == null)
throw new NullPointerException("Null descriptions");
this.steps = steps;
this.descriptions = descriptions;
if (new HashSet(Arrays.asList(steps)).size() < steps.length) if (new HashSet(Arrays.asList(steps)).size() < steps.length)
throw new IllegalArgumentException("Duplicate ID: " + Arrays.asList(steps)); throw new IllegalArgumentException("Duplicate ID: " + Arrays.asList(steps));
if (descriptions.length != steps.length) if (descriptions.length != steps.length)
@ -132,16 +129,6 @@ public final class SimpleWizardInfo implements WizardControllerImplementation {
* gathered data. * gathered data.
*/ */
protected Object finish(Map settings) throws WizardException { protected Object finish(Map settings) throws WizardException {
//XXX fixme
// assert canFinish();
// SKNUTSON: the "canFinish" behavior is not working
// instead, panels must implement the WizardPanel interface
// and have allowFinish return false
// if ( ! canFinish())
// {
// throw new RuntimeException ("Can't finish right now");
// }
return provider.finish(settings); return provider.finish(settings);
} }

View File

@ -20,10 +20,13 @@ package org.jackhuang.hellominecraft.util.ui.wizard.spi;
import java.awt.Component; import java.awt.Component;
import java.awt.Font; import java.awt.Font;
import java.util.Objects;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.UIManager; import javax.swing.UIManager;
import org.jackhuang.hellominecraft.util.ArrayUtils;
import org.jackhuang.hellominecraft.util.StrUtils;
/** /**
* Object which may be returned from * Object which may be returned from
@ -56,9 +59,7 @@ public class Summary {
public Summary(String text, Object result) { public Summary(String text, Object result) {
//XXX this is creating components off the AWT thread - needs to change //XXX this is creating components off the AWT thread - needs to change
//to use invokeAndWait where appropriate //to use invokeAndWait where appropriate
if (text == null) if (StrUtils.isBlank(text))
throw new NullPointerException("Text is null");
if (text.trim().length() == 0)
throw new IllegalArgumentException("Text is empty or all whitespace"); throw new IllegalArgumentException("Text is empty or all whitespace");
this.result = result; this.result = result;
JTextArea jta = new JTextArea(); JTextArea jta = new JTextArea();
@ -85,9 +86,7 @@ public class Summary {
* @return the requested <code>Summary</code> object * @return the requested <code>Summary</code> object
*/ */
public Summary(String[] items, Object result) { public Summary(String[] items, Object result) {
if (items == null) if (ArrayUtils.isEmpty(items))
throw new NullPointerException("Items array null");
if (items.length == 0)
throw new IllegalArgumentException("Items array empty"); throw new IllegalArgumentException("Items array empty");
this.result = result; this.result = result;
JList list = new JList(items); JList list = new JList(items);
@ -108,9 +107,7 @@ public class Summary {
*/ */
public Summary(Component comp, Object result) { public Summary(Component comp, Object result) {
this.result = result; this.result = result;
this.comp = comp; this.comp = Objects.requireNonNull(comp, "Null component");
if (comp == null)
throw new NullPointerException("Null component");
} }
/** /**

View File

@ -10,6 +10,7 @@ import java.lang.reflect.Modifier;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects;
import java.util.Set; import java.util.Set;
/** /**
@ -71,10 +72,8 @@ final class Util {
try { try {
Method m = clazz.getDeclaredMethod("getStep", new Class[]{}); Method m = clazz.getDeclaredMethod("getStep", new Class[]{});
// assert m.getReturnType() == String.class; // assert m.getReturnType() == String.class;
result = (String) m.invoke(clazz, (Object[]) null); result = Objects.requireNonNull((String) m.invoke(clazz, (Object[]) null), "getStep may not return null");
if (result == null) } catch (Exception ex) {
throw new NullPointerException("getStep may not return null");
} catch (IllegalAccessException | IllegalArgumentException | NoSuchMethodException | NullPointerException | SecurityException | InvocationTargetException ex) {
//do nothing //do nothing
} }
return result == null ? clazz.getName() : result; return result == null ? clazz.getName() : result;
@ -85,16 +84,13 @@ final class Util {
* class object passed * class object passed
*/ */
static String[] getSteps(Class[] pages) { static String[] getSteps(Class[] pages) {
if (pages == null) Objects.requireNonNull(pages, "Null array of classes");
throw new NullPointerException("Null array of classes");
String[] result = new String[pages.length]; String[] result = new String[pages.length];
Set used = new HashSet(pages.length); Set used = new HashSet(pages.length);
for (int i = 0; i < pages.length; i++) { for (int i = 0; i < pages.length; i++) {
if (pages[i] == null) Objects.requireNonNull(pages[i], "Null at " + i + " in array of panel classes");
throw new NullPointerException("Null at " + i + " in array "
+ "of panel classes");
if (!WizardPage.class.isAssignableFrom(pages[i])) if (!WizardPage.class.isAssignableFrom(pages[i]))
throw new IllegalArgumentException(pages[i] throw new IllegalArgumentException(pages[i]

View File

@ -15,6 +15,7 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.JComponent; import javax.swing.JComponent;
import org.jackhuang.hellominecraft.util.ui.wizard.api.WizardDisplayer; import org.jackhuang.hellominecraft.util.ui.wizard.api.WizardDisplayer;
@ -121,9 +122,7 @@ public final class Wizard {
* Creates a new instance of Wizard * Creates a new instance of Wizard
*/ */
Wizard(WizardImplementation impl) { Wizard(WizardImplementation impl) {
this.impl = impl; this.impl = Objects.requireNonNull(impl);
if (impl == null)
throw new NullPointerException();
} }
/** /**
@ -321,6 +320,7 @@ public final class Wizard {
private class ImplL implements WizardObserver { private class ImplL implements WizardObserver {
@Override
public void stepsChanged(Wizard wizard) { public void stepsChanged(Wizard wizard) {
WizardObserver[] l = (WizardObserver[]) listeners.toArray( WizardObserver[] l = (WizardObserver[]) listeners.toArray(
new WizardObserver[listeners.size()]); new WizardObserver[listeners.size()]);
@ -328,6 +328,7 @@ public final class Wizard {
l1.stepsChanged(Wizard.this); l1.stepsChanged(Wizard.this);
} }
@Override
public void navigabilityChanged(Wizard wizard) { public void navigabilityChanged(Wizard wizard) {
WizardObserver[] l = (WizardObserver[]) listeners.toArray( WizardObserver[] l = (WizardObserver[]) listeners.toArray(
new WizardObserver[listeners.size()]); new WizardObserver[listeners.size()]);
@ -335,6 +336,7 @@ public final class Wizard {
l1.navigabilityChanged(Wizard.this); l1.navigabilityChanged(Wizard.this);
} }
@Override
public void selectionChanged(Wizard wizard) { public void selectionChanged(Wizard wizard) {
WizardObserver[] l = (WizardObserver[]) listeners.toArray( WizardObserver[] l = (WizardObserver[]) listeners.toArray(
new WizardObserver[listeners.size()]); new WizardObserver[listeners.size()]);
@ -343,10 +345,12 @@ public final class Wizard {
} }
} }
@Override
public int hashCode() { public int hashCode() {
return impl.hashCode() * 17; return impl.hashCode() * 17;
} }
@Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == this) if (o == this)
return true; return true;

View File

@ -16,6 +16,7 @@ enclosed by brackets [] replaced by your own identifying information:
package org.jackhuang.hellominecraft.util.ui.wizard.spi; package org.jackhuang.hellominecraft.util.ui.wizard.spi;
import java.util.Map; import java.util.Map;
import java.util.Objects;
/** /**
* Extend this class to create wizards which have branch points in them - * Extend this class to create wizards which have branch points in them -
@ -93,9 +94,7 @@ public abstract class WizardBranchController {
* for the initial panes of the wizard. * for the initial panes of the wizard.
*/ */
WizardBranchController(SimpleWizardInfo base) { WizardBranchController(SimpleWizardInfo base) {
if (base == null) this.base = Objects.requireNonNull(base, "No base");
throw new NullPointerException("No base");
this.base = base;
} }
/** /**

View File

@ -165,10 +165,6 @@ public class WizardPage extends JPanel implements WizardPanel {
throw new IllegalStateException("CustomComponentListener " throw new IllegalStateException("CustomComponentListener "
+ "will never be called if the autoListen parameter is " + "will never be called if the autoListen parameter is "
+ "false"); + "false");
// if (getClass() == WizardPage.class && stepId == null ||
// description == null) {
// throw new NullPointerException ("Step or ID is null");
// }
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); //XXX setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); //XXX
} }
@ -339,6 +335,7 @@ public class WizardPage extends JPanel implements WizardPanel {
this.page = page; //Slightly smaller footprint a nested, not inner class this.page = page; //Slightly smaller footprint a nested, not inner class
} }
@Override
public void userInputReceived(Component c, Object event) { public void userInputReceived(Component c, Object event) {
if (!page.ccl.accept(c)) if (!page.ccl.accept(c))
return; return;
@ -362,6 +359,7 @@ public class WizardPage extends JPanel implements WizardPanel {
return description; return description;
} }
@Override
public void addNotify() { public void addNotify() {
super.addNotify(); super.addNotify();
if (!listening) if (!listening)
@ -376,14 +374,17 @@ public class WizardPage extends JPanel implements WizardPanel {
} }
} }
@Override
public WizardPanelNavResult allowBack(String stepName, Map settings, Wizard wizard) { public WizardPanelNavResult allowBack(String stepName, Map settings, Wizard wizard) {
return WizardPanelNavResult.PROCEED; return WizardPanelNavResult.PROCEED;
} }
@Override
public WizardPanelNavResult allowFinish(String stepName, Map settings, Wizard wizard) { public WizardPanelNavResult allowFinish(String stepName, Map settings, Wizard wizard) {
return WizardPanelNavResult.PROCEED; return WizardPanelNavResult.PROCEED;
} }
@Override
public WizardPanelNavResult allowNext(String stepName, Map settings, Wizard wizard) { public WizardPanelNavResult allowNext(String stepName, Map settings, Wizard wizard) {
return WizardPanelNavResult.PROCEED; return WizardPanelNavResult.PROCEED;
} }
@ -830,7 +831,7 @@ public class WizardPage extends JPanel implements WizardPanel {
} }
static WizardPanelProvider createWizardPanelProvider(WizardPage page) { static WizardPanelProvider createWizardPanelProvider(WizardPage page) {
return new WPP(new WizardPage[]{page}, WizardResultProducer.NO_OP); return new WPP(new WizardPage[] { page }, WizardResultProducer.NO_OP);
} }
static WizardPanelProvider createWizardPanelProvider(WizardPage[] page) { static WizardPanelProvider createWizardPanelProvider(WizardPage[] page) {
@ -879,6 +880,7 @@ public class WizardPage extends JPanel implements WizardPanel {
this.finish = finish; this.finish = finish;
} }
@Override
protected JComponent createPanel(WizardController controller, String id, protected JComponent createPanel(WizardController controller, String id,
Map wizardData) { Map wizardData) {
int idx = indexOfStep(id); int idx = indexOfStep(id);
@ -907,14 +909,17 @@ public class WizardPage extends JPanel implements WizardPanel {
return null; return null;
} }
@Override
protected Object finish(Map settings) throws WizardException { protected Object finish(Map settings) throws WizardException {
return finish.finish(settings); return finish.finish(settings);
} }
@Override
public boolean cancel(Map settings) { public boolean cancel(Map settings) {
return finish.cancel(settings); return finish.cancel(settings);
} }
@Override
public String getLongDescription(String stepId) { public String getLongDescription(String stepId) {
for (WizardPage wizardPage : pages) for (WizardPage wizardPage : pages)
if (stepId.equals(wizardPage.getID())) if (stepId.equals(wizardPage.getID()))
@ -974,6 +979,7 @@ public class WizardPage extends JPanel implements WizardPanel {
this.finish = finish; this.finish = finish;
} }
@Override
protected JComponent createPanel(WizardController controller, String id, Map wizardData) { protected JComponent createPanel(WizardController controller, String id, Map wizardData) {
int idx = indexOfStep(id); int idx = indexOfStep(id);
@ -995,18 +1001,22 @@ public class WizardPage extends JPanel implements WizardPanel {
} }
} }
@Override
protected Object finish(Map settings) throws WizardException { protected Object finish(Map settings) throws WizardException {
return finish.finish(settings); return finish.finish(settings);
} }
@Override
public boolean cancel(Map settings) { public boolean cancel(Map settings) {
return finish.cancel(settings); return finish.cancel(settings);
} }
@Override
public String toString() { public String toString() {
return super.toString() + " for " + finish; return super.toString() + " for " + finish;
} }
@Override
public String getLongDescription(String stepId) { public String getLongDescription(String stepId) {
int idx = indexOfStep(stepId); int idx = indexOfStep(stepId);
if (idx != -1) if (idx != -1)
@ -1027,10 +1037,12 @@ public class WizardPage extends JPanel implements WizardPanel {
private int canFinish = -1; private int canFinish = -1;
private Boolean busy = null; private Boolean busy = null;
@Override
public void setProblem(String value) { public void setProblem(String value) {
this.problem = value; this.problem = value;
} }
@Override
public void setForwardNavigationMode(int value) { public void setForwardNavigationMode(int value) {
switch (value) { switch (value) {
case WizardController.MODE_CAN_CONTINUE: case WizardController.MODE_CAN_CONTINUE:
@ -1044,6 +1056,7 @@ public class WizardPage extends JPanel implements WizardPanel {
canFinish = value; canFinish = value;
} }
@Override
public void setBusy(boolean busy) { public void setBusy(boolean busy) {
this.busy = busy ? Boolean.TRUE : Boolean.FALSE; this.busy = busy ? Boolean.TRUE : Boolean.FALSE;
} }
@ -1106,14 +1119,17 @@ public class WizardPage extends JPanel implements WizardPanel {
* A no-op WizardResultProducer that returns null. * A no-op WizardResultProducer that returns null.
*/ */
WizardResultProducer NO_OP = new WizardResultProducer() { WizardResultProducer NO_OP = new WizardResultProducer() {
@Override
public Object finish(Map wizardData) { public Object finish(Map wizardData) {
return wizardData; return wizardData;
} }
@Override
public boolean cancel(Map settings) { public boolean cancel(Map settings) {
return true; return true;
} }
@Override
public String toString() { public String toString() {
return "NO_OP WizardResultProducer"; return "NO_OP WizardResultProducer";
} }

View File

@ -8,44 +8,44 @@ and include the License file at http://www.netbeans.org/cddl.txt.
If applicable, add the following below the CDDL Header, with the fields If applicable, add the following below the CDDL Header, with the fields
enclosed by brackets [] replaced by your own identifying information: enclosed by brackets [] replaced by your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]" */ "Portions Copyrighted [year] [name of copyright owner]" */
/* /*
* PanelProvider.java * PanelProvider.java
* *
* Created on March 5, 2005, 7:25 PM * Created on March 5, 2005, 7:25 PM
*/ */
package org.jackhuang.hellominecraft.util.ui.wizard.spi; package org.jackhuang.hellominecraft.util.ui.wizard.spi;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import javax.swing.JComponent; import javax.swing.JComponent;
/** /**
* (Note: <code>WizardPage</code> offers somewhat simpler functionality for * (Note: <code>WizardPage</code> offers somewhat simpler functionality for
* creating a wizard than does WizardPanelProvider; the only advantage of * creating a wizard than does WizardPanelProvider; the only advantage of
* <code>WizardPanelProvider</code> is that it does not require one to * <code>WizardPanelProvider</code> is that it does not require one to subclass
* subclass a panel component). * a panel component).
* <p> * <p>
* A simple interface for providing a fixed set of panels for a wizard. * A simple interface for providing a fixed set of panels for a wizard. To use,
* To use, simply implement <code>createPanel()</code> to create the * simply implement <code>createPanel()</code> to create the appropriate UI
* appropriate UI component for a given step (a unique String ID - one of the ones passed * component for a given step (a unique String ID - one of the ones passed in
* in the constructor in the <code>steps</code> array), and implement * the constructor in the <code>steps</code> array), and implement
* <code>finish()</code> to do whatever should be done when the wizard is * <code>finish()</code> to do whatever should be done when the wizard is
* finished. * finished.
* <p> * <p>
* To control whether the Next/Finish buttons are enabled, components * To control whether the Next/Finish buttons are enabled, components created in
* created in <code>createPanel()</code> should call methods on the <code> * <code>createPanel()</code> should call methods on the <code>
* WizardController</code> passed. The created panels should listen on the * WizardController</code> passed. The created panels should listen on the UI
* UI components they create, updating the settings Map when the user changes * components they create, updating the settings Map when the user changes their
* their input. * input.
* <p> * <p>
* Super-simple one-pane wizard example - if the checkbox is checked, the user * Super-simple one-pane wizard example - if the checkbox is checked, the user
* can continue: * can continue:
* <pre> * <pre>
* public class MyProvider extends WizardPanelProvider { * public class MyProvider extends WizardPanelProvider {
* public MyProvider() { * public MyProvider() {
* <font color="gray">//here we pass a localized title for the wizard, * <font color="gray">//here we pass a localized title for the wizard,
* //the ID of the one step it will have, and a localized description * //the ID of the one step it will have, and a localized description
* //the wizard can show for that one step</font> * //the wizard can show for that one step</font>
* super ("Click the box", "click", "Click the checkbox"); * super ("Click the box", "click", "Click the checkbox");
@ -57,7 +57,7 @@ import javax.swing.JComponent;
* final JCheckBox result = new JCheckBox(); * final JCheckBox result = new JCheckBox();
* result.addActionListener (new ActionListener() { * result.addActionListener (new ActionListener() {
* public void actionPerformed (ActionEvent ae) { * public void actionPerformed (ActionEvent ae) {
* <font color="gray">//Typically you want to write the result of some user * <font color="gray">//Typically you want to write the result of some user
* //action into the settings map as soon as they do it </font> * //action into the settings map as soon as they do it </font>
* settings.put ("boxSelected", result.isSelected() ? Boolean.TRUE : Boolean.FALSE); * settings.put ("boxSelected", result.isSelected() ? Boolean.TRUE : Boolean.FALSE);
* if (result.isSelected()) { * if (result.isSelected()) {
@ -72,7 +72,7 @@ import javax.swing.JComponent;
* } * }
* *
* protected Object finish (Map settings) throws WizardException { * protected Object finish (Map settings) throws WizardException {
* <font color="gray">//if we had some interesting information (Strings a user put in a * <font color="gray">//if we had some interesting information (Strings a user put in a
* //text field or something, we'd generate some interesting object or * //text field or something, we'd generate some interesting object or
* //create some files or something here</font> * //create some files or something here</font>
* return null; * return null;
@ -83,240 +83,229 @@ import javax.swing.JComponent;
* @author Tim Boudreau * @author Tim Boudreau
*/ */
public abstract class WizardPanelProvider { public abstract class WizardPanelProvider {
final String title; final String title;
final String[] descriptions; final String[] descriptions;
final String[] steps; final String[] steps;
final String[] knownProblems; final String[] knownProblems;
/** /**
* Create a WizardPanelProvider. The passed array of steps and descriptions * Create a WizardPanelProvider. The passed array of steps and descriptions
* will be used as IDs and localized descriptions of the various steps in * will be used as IDs and localized descriptions of the various steps in
* the wizard. Use this constructor (which passes not title) for sub-wizards * the wizard. Use this constructor (which passes not title) for sub-wizards
* used in a <code>WizardBranchController</code>, where the first pane * used in a <code>WizardBranchController</code>, where the first pane will
* will determine the title, and the titles of the sub-wizards will never be * determine the title, and the titles of the sub-wizards will never be
* shown. * shown.
* @param steps A set of unique IDs identifying each step of this wizard. Each *
* ID must occur only once in the array of steps. * @param steps A set of unique IDs identifying each step of this wizard.
* * Each ID must occur only once in the array of steps.
*
* @param descriptions A set of human-readable descriptions corresponding * @param descriptions A set of human-readable descriptions corresponding
* 1:1 with the unique IDs passed as the <code>steps</code> parameter * 1:1 with the unique IDs passed as the <code>steps</code> parameter
*/ */
protected WizardPanelProvider (String[] steps, String[] descriptions) { protected WizardPanelProvider(String[] steps, String[] descriptions) {
this (null, steps, descriptions); this(null, steps, descriptions);
} }
/** /**
* Create a WizardPanelProvider with the provided title, steps and * Create a WizardPanelProvider with the provided title, steps and
* descriptions. The <code>steps</code> parameter are unique IDs of * descriptions. The <code>steps</code> parameter are unique IDs of panels,
* panels, which will be passed to <code>createPanel</code> to create * which will be passed to <code>createPanel</code> to create panels for
* panels for various steps in the wizard, as the user navigates it. * various steps in the wizard, as the user navigates it. The
* The <code>descriptions</code> parameter is a set of localized descriptions * <code>descriptions</code> parameter is a set of localized descriptions
* that can appear in the Wizard to describe each step. * that can appear in the Wizard to describe each step.
*
* @param title A human readable title for the wizard dialog * @param title A human readable title for the wizard dialog
* @param steps An array of unique IDs for the various panels of this * @param steps An array of unique IDs for the various panels of this wizard
* wizard
* @param descriptions An array of descriptions corresponding 1:1 with the * @param descriptions An array of descriptions corresponding 1:1 with the
* unique IDs. These must be human readable, localized strings. * unique IDs. These must be human readable, localized strings.
*/ */
protected WizardPanelProvider (String title, String[] steps, String[] descriptions) { protected WizardPanelProvider(String title, String[] steps, String[] descriptions) {
this.title = title; this.title = title;
this.steps = steps; this.steps = steps;
this.descriptions = descriptions; this.descriptions = descriptions;
knownProblems = new String[steps.length]; knownProblems = new String[steps.length];
if (steps.length != descriptions.length) { if (steps.length != descriptions.length)
throw new IllegalArgumentException ("Length of steps and" + throw new IllegalArgumentException("Length of steps and"
" descriptions arrays do not match"); + " descriptions arrays do not match");
}
// assert validData (steps, descriptions) == null : validData (steps, descriptions); // assert validData (steps, descriptions) == null : validData (steps, descriptions);
String v = validData (steps, descriptions); String v = validData(steps, descriptions);
if (v != null) if (v != null)
{ throw new RuntimeException(v);
throw new RuntimeException (v);
}
} }
private String validData(String[] steps, String[] descriptions) {
private String validData (String[] steps, String[] descriptions) { if (steps.length != descriptions.length)
if (steps.length != descriptions.length) { return steps.length + " steps but " + descriptions.length
return steps.length + " steps but " + descriptions.length + + " descriptions";
" descriptions"; for (int i = 0; i < steps.length; i++) {
Objects.requireNonNull(steps[i], "Step id " + i + " is null");
Objects.requireNonNull(descriptions[i], "Description " + i + " is null");
} }
for (int i=0; i < steps.length; i++) { if (new HashSet(Arrays.asList(steps)).size() != steps.length)
if (steps[i] == null) {
throw new NullPointerException ("Step id " + i + " is null");
}
if (descriptions[i] == null) {
throw new NullPointerException ("Description " + i + " is null");
}
}
if (new HashSet(Arrays.asList(steps)).size() != steps.length) {
return "Duplicate step ids: " + Arrays.asList(steps); return "Duplicate step ids: " + Arrays.asList(steps);
}
return null; return null;
} }
/** /**
* Convenience constructor to create a WizardPanelProvider which has only * Convenience constructor to create a WizardPanelProvider which has only
* one step to it. Mainly useful for initial steps in a <code>WizardBranchController</code>. * one step to it. Mainly useful for initial steps in a
* <code>WizardBranchController</code>.
*
* @param title A human readable title for the wizard dialog * @param title A human readable title for the wizard dialog
* @param singleStep The unique ID of the only step this wizard has * @param singleStep The unique ID of the only step this wizard has
* @param singleDescription The human-readable description of what the user * @param singleDescription The human-readable description of what the user
* should do in the one step of this one-step wizard or sub-wizard * should do in the one step of this one-step wizard or sub-wizard
*/ */
protected WizardPanelProvider (String title, String singleStep, String singleDescription) { protected WizardPanelProvider(String title, String singleStep, String singleDescription) {
this (title, new String[] {singleStep}, new String[] {singleDescription}); this(title, new String[] { singleStep }, new String[] { singleDescription });
} }
/** /**
* Create a panel that represents a named step in the wizard. * Create a panel that represents a named step in the wizard. This method
* This method will be called exactly <i>once</i> in the life of * will be called exactly <i>once</i> in the life of a wizard. The panel
* a wizard. The panel should retain the passed settings Map, and * should retain the passed settings Map, and add/remove values from it as
* add/remove values from it as the user enters information, calling * the user enters information, calling <code>setProblem()</code> and
* <code>setProblem()</code> and <code>setCanFinish()</code> as * <code>setCanFinish()</code> as appropriate in response to user input.
* appropriate in response to user input. *
* * @param controller - the object which controls whether the Next/Finish
* @param controller - the object which controls whether the * buttons in the wizard are enabled, and what instructions are displayed to
* Next/Finish buttons in the wizard are enabled, and what instructions * the user if they are not
* are displayed to the user if they are not * @param id The name of the step, one of the array of steps passed in the
* @param id The name of the step, one of the array of steps passed in * constructor
* the constructor * @param settings A Map containing settings from earlier steps in the
* @param settings A Map containing settings from earlier steps in * wizard. It is safe to retain a reference to this map and put values in it
* the wizard. It is safe to retain a reference to this map and put * as the user manipulates the UI; the reference should be refreshed
* values in it as the user manipulates the UI; the reference should * whenever this method is called again.
* be refreshed whenever this method is called again. * @return A JComponent that should be displayed in the center of the wizard
* @return A JComponent that should be displayed in the center of the
* wizard
*/ */
protected abstract JComponent createPanel (WizardController controller, String id, Map settings); protected abstract JComponent createPanel(WizardController controller, String id, Map settings);
/** /**
* Instantiate whatever object (if any) the wizard creates from its * Instantiate whatever object (if any) the wizard creates from its gathered
* gathered data. The default implementation is a no-op that returns * data. The default implementation is a no-op that returns null.
* null.
* <p> * <p>
* If an instance of <code>Summary</code> is returned from this method, the * If an instance of <code>Summary</code> is returned from this method, the
* UI shall display it on a final page and disable all navigation buttons * UI shall display it on a final page and disable all navigation buttons
* except the Close/Cancel button. * except the Close/Cancel button.
* <p> * <p>
* If an instance of <code>DeferredWizardResult</code> is returned from this * If an instance of <code>DeferredWizardResult</code> is returned from this
* method, the UI shall display some sort of progress bar while the result * method, the UI shall display some sort of progress bar while the result
* is computed in the background. If that <code>DeferredWizardResult</code> * is computed in the background. If that <code>DeferredWizardResult</code>
* produces a <code>Summary</code> object, that summary shall be displayed * produces a <code>Summary</code> object, that summary shall be displayed
* as described above. * as described above.
* <p> * <p>
* The default implementation returns the settings map it is passed. * The default implementation returns the settings map it is passed.
* *
* @param settings The settings map, now fully populated with all settings needed * @param settings The settings map, now fully populated with all settings
* to complete the wizard (this method will only be called if * needed to complete the wizard (this method will only be called if
* <code>setProblem(null)</code> and <code>setCanFinish(true)</code> have * <code>setProblem(null)</code> and <code>setCanFinish(true)</code> have
* been called on the <code>WizardController</code> passed to * been called on the <code>WizardController</code> passed to
* <code>createPanel()</code>. * <code>createPanel()</code>.
* @return an object composed based on what the user entered in the wizard - * @return an object composed based on what the user entered in the wizard -
* somethingmeaningful to whatever code invoked the wizard, or null. Note * somethingmeaningful to whatever code invoked the wizard, or null. Note
* special handling if an instance of <code>DeferredWizardResult</code> * special handling if an instance of <code>DeferredWizardResult</code> or
* or <code>Summary</code> is returned from this method. * <code>Summary</code> is returned from this method.
*/ */
protected Object finish (Map settings) throws WizardException { protected Object finish(Map settings) throws WizardException {
return settings; return settings;
} }
/** /**
* The method provides a chance to call setProblem() or setCanFinish() when * The method provides a chance to call setProblem() or setCanFinish() when
* the user re-navigates to a panel they've already seen - in the case * the user re-navigates to a panel they've already seen - in the case that
* that the user pressed the Previous button and then the Next button. * the user pressed the Previous button and then the Next button.
* <p> * <p>
* The default implementation does nothing, which is sufficient for most * The default implementation does nothing, which is sufficient for most
* cases. * cases. If whether this panel is valid or not could have changed because
* If whether this panel is valid or not could * of changed data from a previous panel, or it displays data entered on
* have changed because of changed data from a previous panel, or it * previous panes which may have changed, you may want to override this
* displays data entered on previous panes which may have changed, * method to ensure validity and canFinish are set correctly, and that the
* you may want to override this method to ensure validity and canFinish * components have the correct text.
* are set correctly, and that the components have the correct text.
* <p> * <p>
* This method will <i>not</i> be called when a panel is first instantiated - * This method will <i>not</i> be called when a panel is first instantiated
* <code>createPanel()</code> is expected to set validity and canFinish * - <code>createPanel()</code> is expected to set validity and canFinish
* appropriately. * appropriately.
* <p> * <p>
* The settings Map passed to this method will always be the same * The settings Map passed to this method will always be the same Settings
* Settings map instance that was passed to <code>createPanel()</code> * map instance that was passed to <code>createPanel()</code> when the panel
* when the panel was created. * was created.
* <p> * <p>
* If you are implementing WizardPanelProvider and some of the pages are * If you are implementing WizardPanelProvider and some of the pages are
* <code>WizardPage</code>s, you should call the super implementation if * <code>WizardPage</code>s, you should call the super implementation if you
* you override this method. * override this method.
*/ */
protected void recycleExistingPanel (String id, WizardController controller, Map wizardData, JComponent panel) { protected void recycleExistingPanel(String id, WizardController controller, Map wizardData, JComponent panel) {
//do nothing //do nothing
} }
void recycle (String id, WizardController controller, Map wizardData, JComponent panel) { void recycle(String id, WizardController controller, Map wizardData, JComponent panel) {
if (panel instanceof WizardPage) { if (panel instanceof WizardPage) {
WizardPage page = (WizardPage) panel; WizardPage page = (WizardPage) panel;
page.setController(controller); page.setController(controller);
page.setWizardDataMap(wizardData); page.setWizardDataMap(wizardData);
page.recycle(); page.recycle();
} }
recycleExistingPanel (id, controller, wizardData, panel); recycleExistingPanel(id, controller, wizardData, panel);
} }
private Wizard wizard; private Wizard wizard;
/** /**
* Create a Wizard for this PanelProvider. The instance created by this * Create a Wizard for this PanelProvider. The instance created by this
* method is cached and the same instance will be returned on subsequent * method is cached and the same instance will be returned on subsequent
* calls. * calls.
*/ */
public final Wizard createWizard() { public final Wizard createWizard() {
if (wizard == null) { if (wizard == null)
wizard = new Wizard (new SimpleWizard (this)); wizard = new Wizard(new SimpleWizard(this));
}
return wizard; return wizard;
} }
/** /**
* This method can optionally be overridden to provide a longer * This method can optionally be overridden to provide a longer description
* description of a step to be shown in the top of its panel. * of a step to be shown in the top of its panel. The default implementation
* The default implementation returns null, indicating that the * returns null, indicating that the short description should be used.
* short description should be used. *
*
* @param stepId a unique id for one step of the wizard * @param stepId a unique id for one step of the wizard
* @return An alternate description for use in the top of the wizard * @return An alternate description for use in the top of the wizard page
* page when this page is the current one, or null * when this page is the current one, or null
*/ */
public String getLongDescription (String stepId) { public String getLongDescription(String stepId) {
return null; return null;
} }
/** /**
* Convenience method to get the index into the array of steps passed to * Convenience method to get the index into the array of steps passed to the
* the constructor of a specific step id. * constructor of a specific step id.
*/ */
protected final int indexOfStep (String id) { protected final int indexOfStep(String id) {
return Arrays.asList(steps).indexOf(id); return Arrays.asList(steps).indexOf(id);
} }
void setKnownProblem (String problem, int idx) { void setKnownProblem(String problem, int idx) {
//Record a problem message so we can put it back if the user does //Record a problem message so we can put it back if the user does
//prev and then next //prev and then next
if (idx >= 0) { //setProblem() can be called during initialization if (idx >= 0) //setProblem() can be called during initialization
knownProblems[idx] = problem; knownProblems[idx] = problem;
}
} }
String getKnownProblem(int idx) { String getKnownProblem(int idx) {
return knownProblems[idx]; return knownProblems[idx];
} }
/** /**
* Called if the user invokes cancel. The default impl returns * Called if the user invokes cancel. The default impl returns true.
* true. *
* @return false to abort cancellation (almost all implementations will * @return false to abort cancellation (almost all implementations will want
* want to return true - this is really only applicable in cases such * to return true - this is really only applicable in cases such as an OS
* as an OS installer or such). * installer or such).
*/ */
public boolean cancel(Map settings) { public boolean cancel(Map settings) {
return true; return true;
} }
@Override
public String toString() { public String toString() {
return super.toString() + " with wizard " + wizard; return super.toString() + " with wizard " + wizard;
} }