Added Gaussion Blur

This commit is contained in:
unknown
2017-01-19 20:33:24 +08:00
parent b36c194f67
commit ed7c52f09f
138 changed files with 1792 additions and 2063 deletions

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hellominecraft.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -26,7 +25,10 @@ import java.util.Map;
*
* @author huangyuhui
*/
public class ArrayUtils {
public final class ArrayUtils {
private ArrayUtils() {
}
public static <T> boolean isEmpty(T[] array) {
return array == null || array.length <= 0;
@@ -72,42 +74,20 @@ public class ArrayUtils {
return -1;
}
public static ArrayList merge(List a, List b) {
public static <T> ArrayList<T> merge(List<T> a, List<T> b) {
ArrayList al = new ArrayList(a.size() + b.size());
al.addAll(a);
al.addAll(b);
return al;
}
public static <K> K getEnd(K[] k) {
if (k == null)
return null;
else
return k[k.length - 1];
}
public static List tryGetMapWithList(Map map, String key) {
List l = (List) map.get(key);
if (l == null)
map.put(key, l = new ArrayList());
return l;
}
public static <T> int matchArray(T[] a, T[] b) {
for (int i = 0; i < a.length - b.length; i++) {
int j = 1;
for (int k = 0; k < b.length; k++) {
if (b[k].equals(a[(i + k)]))
continue;
j = 0;
break;
}
if (j != 0)
return i;
}
return -1;
}
public static <T> int matchArray(byte[] a, byte[] b) {
for (int i = 0; i < a.length - b.length; i++) {
int j = 1;
@@ -122,19 +102,4 @@ public class ArrayUtils {
}
return -1;
}
public static <T> boolean equals(T[] a, T[] b) {
if (a == null && b == null)
return true;
if (a == null || b == null)
return false;
if (a.length != b.length)
return false;
Arrays.sort(a);
Arrays.sort(b);
for (int i = 0; i < a.length; i++)
if (a[i] == null && b[i] != null || a[i] != null && b[i] == null || !a[i].equals(b[i]))
return false;
return true;
}
}

View File

@@ -28,6 +28,9 @@ import java.util.Iterator;
*/
public final class CollectionUtils {
private CollectionUtils() {
}
public static <T> ArrayList<T> map(Collection<T> coll, Predicate<T> p) {
ArrayList<T> newColl = new ArrayList<>();
for (T t : coll)

View File

@@ -21,7 +21,10 @@ package org.jackhuang.hellominecraft.util;
*
* @author huang
*/
public class MathUtils {
public final class MathUtils {
private MathUtils() {
}
public static int parseInt(String s, int def) {
try {

View File

@@ -92,7 +92,7 @@ public class MessageBox {
*
* @return user operation.
*/
public static int Show(String Msg, String Title, int Option) {
public static int show(String Msg, String Title, int Option) {
switch (Option) {
case YES_NO_OPTION:
case YES_NO_CANCEL_OPTION:
@@ -112,8 +112,8 @@ public class MessageBox {
*
* @return User Operation
*/
public static int Show(String Msg, int Option) {
return Show(Msg, TITLE, Option);
public static int show(String Msg, int Option) {
return show(Msg, TITLE, Option);
}
/**
@@ -123,11 +123,11 @@ public class MessageBox {
*
* @return User Operation
*/
public static int Show(String Msg) {
return Show(Msg, TITLE, INFORMATION_MESSAGE);
public static int show(String Msg) {
return show(Msg, TITLE, INFORMATION_MESSAGE);
}
public static int ShowLocalized(String msg) {
return Show(C.i18n(msg));
public static int showLocalized(String msg) {
return show(C.i18n(msg));
}
}

View File

@@ -22,15 +22,15 @@ import java.io.IOException;
import java.io.Serializable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.ArrayUtils;
import org.jackhuang.hellominecraft.util.NetUtils;
import org.jackhuang.hellominecraft.util.system.IOUtils;
/**
* @author huangyuhui
*/
public class MinecraftVersionRequest implements Serializable {
private static final long serialVersionUID = 1L;
public static final int UNKOWN = 0, INVALID = 1, INVALID_JAR = 2,
MODIFIED = 3, OK = 4, NOT_FOUND = 5, UNREADABLE = 6, NOT_FILE = 7;
@@ -38,34 +38,25 @@ public class MinecraftVersionRequest implements Serializable {
public String version;
public static String getResponse(MinecraftVersionRequest minecraftVersion) {
String text = "";
switch (minecraftVersion.type) {
case MinecraftVersionRequest.INVALID:
text = C.i18n("minecraft.invalid");
break;
return C.i18n("minecraft.invalid");
case MinecraftVersionRequest.INVALID_JAR:
text = C.i18n("minecraft.invalid_jar");
break;
return C.i18n("minecraft.invalid_jar");
case MinecraftVersionRequest.NOT_FILE:
text = C.i18n("minecraft.not_a_file");
break;
return C.i18n("minecraft.not_a_file");
case MinecraftVersionRequest.NOT_FOUND:
text = C.i18n("minecraft.not_found");
break;
return C.i18n("minecraft.not_found");
case MinecraftVersionRequest.UNREADABLE:
text = C.i18n("minecraft.not_readable");
break;
return C.i18n("minecraft.not_readable");
case MinecraftVersionRequest.MODIFIED:
text = C.i18n("minecraft.modified") + " ";
return C.i18n("minecraft.modified") + ' ' + minecraftVersion.version;
case MinecraftVersionRequest.OK:
text += minecraftVersion.version;
break;
return minecraftVersion.version;
case MinecraftVersionRequest.UNKOWN:
default:
text = "???";
break;
return "???";
}
return text;
}
private static int lessThan32(byte[] b, int x) {
@@ -77,11 +68,11 @@ public class MinecraftVersionRequest implements Serializable {
private static MinecraftVersionRequest getVersionOfOldMinecraft(ZipFile file, ZipEntry entry) throws IOException {
MinecraftVersionRequest r = new MinecraftVersionRequest();
byte[] tmp = NetUtils.getBytesFromStream(file.getInputStream(entry));
byte[] tmp = IOUtils.getBytesFromStream(file.getInputStream(entry));
byte[] bytes = "Minecraft Minecraft ".getBytes("ASCII");
int j;
if ((j = ArrayUtils.matchArray(tmp, bytes)) < 0) {
int j = ArrayUtils.matchArray(tmp, bytes);
if (j < 0) {
r.type = MinecraftVersionRequest.UNKOWN;
return r;
}
@@ -101,7 +92,7 @@ public class MinecraftVersionRequest implements Serializable {
private static MinecraftVersionRequest getVersionOfNewMinecraft(ZipFile file, ZipEntry entry) throws IOException {
MinecraftVersionRequest r = new MinecraftVersionRequest();
byte[] tmp = NetUtils.getBytesFromStream(file.getInputStream(entry));
byte[] tmp = IOUtils.getBytesFromStream(file.getInputStream(entry));
byte[] str = "-server.txt".getBytes("ASCII");
int j = ArrayUtils.matchArray(tmp, str);
@@ -145,7 +136,7 @@ public class MinecraftVersionRequest implements Serializable {
while (tmp[k] >= 48 && tmp[k] <= 57 || tmp[k] == (int) '-' || tmp[k] == (int) '.' || tmp[k] >= 97 && tmp[k] <= (int) 'z')
k--;
k++;
r.version = new String(tmp, k, i - k + 1);
r.version = new String(tmp, k, i - k + 1, "ASCII");
}
r.type = file.getEntry("META-INF/MANIFEST.MF") == null
? MinecraftVersionRequest.MODIFIED : MinecraftVersionRequest.OK;
@@ -166,27 +157,27 @@ public class MinecraftVersionRequest implements Serializable {
r.type = MinecraftVersionRequest.UNREADABLE;
return r;
}
ZipFile localZipFile = null;
ZipFile f = null;
try {
localZipFile = new ZipFile(file);
ZipEntry minecraft = localZipFile
f = new ZipFile(file);
ZipEntry minecraft = f
.getEntry("net/minecraft/client/Minecraft.class");
if (minecraft != null)
return getVersionOfOldMinecraft(localZipFile, minecraft);
ZipEntry main = localZipFile.getEntry("net/minecraft/client/main/Main.class");
ZipEntry minecraftserver = localZipFile.getEntry("net/minecraft/server/MinecraftServer.class");
return getVersionOfOldMinecraft(f, minecraft);
ZipEntry main = f.getEntry("net/minecraft/client/main/Main.class");
ZipEntry minecraftserver = f.getEntry("net/minecraft/server/MinecraftServer.class");
if ((main != null) && (minecraftserver != null))
return getVersionOfNewMinecraft(localZipFile, minecraftserver);
return getVersionOfNewMinecraft(f, minecraftserver);
r.type = MinecraftVersionRequest.INVALID;
return r;
} catch (IOException localException) {
HMCLog.warn("Zip file is invalid", localException);
} catch (IOException e) {
HMCLog.warn("Zip file is invalid", e);
r.type = MinecraftVersionRequest.INVALID_JAR;
return r;
} finally {
if (localZipFile != null)
if (f != null)
try {
localZipFile.close();
f.close();
} catch (IOException ex) {
HMCLog.warn("Failed to close zip file", ex);
}

View File

@@ -18,10 +18,8 @@
package org.jackhuang.hellominecraft.util;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
@@ -35,38 +33,16 @@ import org.jackhuang.hellominecraft.util.system.IOUtils;
* @author huang
*/
public final class NetUtils {
public static byte[] getBytesFromStream(InputStream is) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
IOUtils.copyStream(is, out);
is.close();
return out.toByteArray();
}
public static String getStreamContent(InputStream is) throws IOException {
return getStreamContent(is, DEFAULT_CHARSET);
}
public static String getStreamContent(InputStream is, String encoding)
throws IOException {
if (is == null)
return null;
StringBuilder sb = new StringBuilder();
try (InputStreamReader br = new InputStreamReader(is, encoding)) {
int len;
char[] buf = new char[16384];
while ((len = br.read(buf)) != -1)
sb.append(buf, 0, len);
}
return sb.toString();
private NetUtils() {
}
public static String get(String url, String encoding) throws IOException {
return getStreamContent(new URL(url).openConnection().getInputStream());
return IOUtils.getStreamContent(new URL(url).openConnection().getInputStream());
}
public static String get(String url) throws IOException {
return get(url, DEFAULT_CHARSET);
return get(url, IOUtils.DEFAULT_CHARSET);
}
public static String get(URL url) throws IOException {
@@ -74,7 +50,7 @@ public final class NetUtils {
}
public static String get(URL url, Proxy proxy) throws IOException {
return getStreamContent(url.openConnection(proxy).getInputStream());
return IOUtils.getStreamContent(url.openConnection(proxy).getInputStream());
}
public static String post(URL u, Map<String, String> params) throws IOException {
@@ -104,7 +80,7 @@ public final class NetUtils {
con.setConnectTimeout(30000);
con.setReadTimeout(30000);
con.setRequestProperty("Content-Type", contentType + "; charset=utf-8");
byte[] bytes = post.getBytes(DEFAULT_CHARSET);
byte[] bytes = post.getBytes(IOUtils.DEFAULT_CHARSET);
con.setRequestProperty("Content-Length", "" + bytes.length);
con.connect();
OutputStream os = null;
@@ -119,19 +95,17 @@ public final class NetUtils {
InputStream is = null;
try {
is = con.getInputStream();
result = getStreamContent(is);
result = IOUtils.getStreamContent(is);
} catch (IOException ex) {
IOUtils.closeQuietly(is);
is = con.getErrorStream();
result = getStreamContent(is);
result = IOUtils.getStreamContent(is);
}
con.disconnect();
return result;
}
private static final String DEFAULT_CHARSET = "UTF-8";
public static URL constantURL(String url) {
try {
return new URL(url);

View File

@@ -20,6 +20,7 @@ package org.jackhuang.hellominecraft.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import javax.swing.SwingWorker;
import org.jackhuang.hellominecraft.util.func.Consumer;
@@ -47,13 +48,13 @@ public abstract class OverridableSwingWorker<T> extends SwingWorker<Void, T> {
}
public OverridableSwingWorker reg(Consumer<T> c) {
Utils.requireNonNull(c);
Objects.requireNonNull(c);
processListeners.add(c);
return this;
}
public OverridableSwingWorker regDone(Runnable c) {
Utils.requireNonNull(c);
Objects.requireNonNull(c);
doneListeners.add(c);
return this;
}

View File

@@ -33,6 +33,9 @@ import org.jackhuang.hellominecraft.util.func.Predicate;
* @author huang
*/
public final class StrUtils {
private StrUtils() {
}
public static String substring(String src, int start_idx, int end_idx) {
byte[] b = src.getBytes();

View File

@@ -17,6 +17,8 @@
*/
package org.jackhuang.hellominecraft.util;
import com.google.gson.JsonSyntaxException;
import java.io.IOException;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import java.util.Map;
@@ -52,7 +54,7 @@ public final class UpdateChecker implements IUpdateChecker {
if (value == null) {
HMCLog.warn("Failed to check update...");
if (showMessage)
MessageBox.Show(C.i18n("update.failed"));
MessageBox.show(C.i18n("update.failed"));
} else if (VersionNumber.isOlder(base, value))
OUT_DATED = true;
if (OUT_DATED)
@@ -74,7 +76,7 @@ public final class UpdateChecker implements IUpdateChecker {
if (download_link == null)
try {
download_link = C.GSON.fromJson(NetUtils.get("http://huangyuhui.duapp.com/update_link.php?type=" + type), Map.class);
} catch (Exception e) {
} catch (JsonSyntaxException | IOException e) {
HMCLog.warn("Failed to get update link.", e);
}
publish(download_link);

View File

@@ -17,49 +17,32 @@
*/
package org.jackhuang.hellominecraft.util;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import com.sun.management.OperatingSystemMXBean;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
/**
* @author huangyuhui
*/
public final class Utils {
@SuppressWarnings("ResultOfObjectAllocationIgnored")
public static boolean isURL(String s) {
try {
new URL(s);
return true;
} catch (MalformedURLException ex) {
return false;
}
private Utils() {
}
public static URL[] getURL() {
return ((URLClassLoader) Utils.class.getClassLoader()).getURLs();
}
public static int getSuggestedMemorySize() {
try {
OperatingSystemMXBean osmb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
int memory = (int) (osmb.getTotalPhysicalMemorySize() / 1024 / 1024) / 4;
memory = Math.round((float) memory / 128.0f) * 128;
return memory;
} catch (Throwable t) {
HMCLog.warn("Failed to get total memory size, use 1024MB.", t);
return 1024;
}
}
public static void setClipborad(String text) {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), null);
try {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), null);
} catch(HeadlessException ignored) {
}
}
/**
@@ -68,21 +51,12 @@ public final class Utils {
* @param status exit code
*/
public static void shutdownForcely(int status) throws Exception {
Class z = Class.forName("java.lang.Shutdown");
Method exit = z.getDeclaredMethod("exit", int.class);
exit.setAccessible(true);
exit.invoke(z, status);
}
public static void requireNonNull(Object o) {
if (o == null)
throw new NullPointerException("Oh dear, there is a problem...");
}
public static Object firstNonNull(Object... o) {
for (Object s : o)
if (s != null)
return s;
return null;
AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> {
Class z = Class.forName("java.lang.Shutdown");
Method exit = z.getDeclaredMethod("exit", int.class);
exit.setAccessible(true);
exit.invoke(z, status);
return null;
});
}
}

View File

@@ -78,6 +78,33 @@ public final class VersionNumber implements Comparable<VersionNumber> {
return false;
}
@Override
public int hashCode() {
int hash = 3;
hash = 83 * hash + this.firstVer;
hash = 83 * hash + this.secondVer;
hash = 83 * hash + this.thirdVer;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final VersionNumber other = (VersionNumber) obj;
if (this.firstVer != other.firstVer)
return false;
if (this.secondVer != other.secondVer)
return false;
if (this.thirdVer != other.thirdVer)
return false;
return true;
}
@Override
public int compareTo(VersionNumber o) {
if (isOlder(this, o))

View File

@@ -17,13 +17,14 @@
*/
package org.jackhuang.hellominecraft.util.code;
import java.io.UnsupportedEncodingException;
/**
*
* @author huangyuhui
*/
public class Base64 {
public final class Base64 {
private Base64() {
}
public static char[] encode(byte[] data) {
char[] out = new char[((data.length + 2) / 3) * 4];
@@ -52,12 +53,8 @@ public class Base64 {
return out;
}
public static char[] encode(String s, String charset) throws UnsupportedEncodingException {
return encode(s.getBytes(charset));
}
public static char[] encode(String s) {
return encode(s.getBytes());
return encode(s.getBytes(Charsets.UTF_8));
}
public static byte[] decode(char[] data) {

View File

@@ -19,7 +19,10 @@ package org.jackhuang.hellominecraft.util.code;
import java.nio.charset.Charset;
public class Charsets {
public final class Charsets {
private Charsets() {
}
public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");

View File

@@ -26,7 +26,10 @@ import java.security.NoSuchAlgorithmException;
*
* @author huangyuhui
*/
public class DigestUtils {
public final class DigestUtils {
private DigestUtils() {
}
private static final int STREAM_BUFFER_LENGTH = 1024;

View File

@@ -19,7 +19,7 @@ package org.jackhuang.hellominecraft.util.code;
import java.nio.charset.Charset;
public class Hex {
public final class Hex {
public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
public static final String DEFAULT_CHARSET_NAME = "UTF-8";

View File

@@ -29,7 +29,7 @@ import org.jackhuang.hellominecraft.util.system.IOUtils;
*
* @author huangyuhui
*/
public class Localization {
public final class Localization {
private static final String ROOT_LOCATION = "/org/jackhuang/hellominecraft/lang/I18N%s.lang";
@@ -51,7 +51,7 @@ public class Localization {
String[] strings = IOUtils.readFully(is).toString("UTF-8").split("\n");
for (String s : strings)
if (!s.isEmpty() && s.charAt(0) != 35) {
int i = s.indexOf("=");
int i = s.indexOf('=');
if (i == -1)
continue;
lang.put(s.substring(0, i), s.substring(i + 1));

View File

@@ -36,9 +36,8 @@ public enum SupportedLocales {
bundle = Localization.get(self);
showString = bundle.localize("lang");
this.customized = customized;
} catch (Throwable t) {
} catch (Throwable ignore) {
showString = name();
t.printStackTrace();
}
}
@@ -54,8 +53,7 @@ public enum SupportedLocales {
public String translate(String key, Object... format) {
try {
return String.format(bundle.localize(key), format);
} catch (Exception ex) {
ex.printStackTrace();
} catch (Exception ignore) {
return key;
}
}

View File

@@ -37,8 +37,8 @@ public class AppenderControl {
}
public void callAppender(LogEvent event) {
if ((this.level != null)
&& (this.intLevel < event.level.level))
if (this.level != null
&& this.intLevel < event.level.level)
return;
if (this.recursive.get() != null) {

View File

@@ -17,6 +17,7 @@
*/
package org.jackhuang.hellominecraft.util.logging.layout;
import org.jackhuang.hellominecraft.util.code.Charsets;
import org.jackhuang.hellominecraft.util.logging.LogEvent;
/**
@@ -27,7 +28,7 @@ public abstract class AbstractStringLayout implements ILayout<String> {
@Override
public byte[] toByteArray(LogEvent event) {
return toSerializable(event).getBytes();
return toSerializable(event).getBytes(Charsets.UTF_8);
}
}

View File

@@ -40,7 +40,7 @@ public class SimpleLogger extends AbstractLogger {
super(name, messageFactory);
this.level = defaultLevel;
if (showShortLogName) {
int index = name.lastIndexOf(".");
int index = name.lastIndexOf('.');
if ((index > 0) && (index < name.length()))
this.logName = name.substring(index + 1);
else

View File

@@ -21,7 +21,7 @@ public class ObjectMessage
implements IMessage {
private static final long serialVersionUID = -5903272448334166185L;
private final transient Object obj;
private final Object obj;
public ObjectMessage(Object obj) {
if (obj == null)

View File

@@ -35,7 +35,10 @@ import org.jackhuang.hellominecraft.util.func.BiFunction;
*
* @author huangyuhui
*/
public class Compressor {
public final class CompressingUtils {
private CompressingUtils() {
}
public static void zip(String sourceDir, String zipFile) throws IOException {
zip(new File(sourceDir), new File(zipFile), null);

View File

@@ -29,13 +29,15 @@ import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.NetUtils;
/**
*
* @author huangyuhui
*/
public class FileUtils {
public final class FileUtils {
private FileUtils() {
}
public static void deleteDirectory(File directory)
throws IOException {
@@ -75,7 +77,8 @@ public class FileUtils {
public static void cleanDirectory(File directory)
throws IOException {
if (!directory.exists()) {
directory.mkdirs();
if (!directory.mkdirs() && !directory.isDirectory())
throw new IOException("Failed to create directory: " + directory);
return;
}
@@ -186,17 +189,18 @@ public class FileUtils {
else
doCopyFile(srcFile, dstFile);
}
destDir.setLastModified(srcDir.lastModified());
if (!destDir.setLastModified(srcDir.lastModified()))
HMCLog.warn("Failed to set last modified date of dir: " + destDir);
}
public static String read(File file)
throws IOException {
return NetUtils.getStreamContent(IOUtils.openInputStream(file));
return IOUtils.getStreamContent(IOUtils.openInputStream(file));
}
public static String readQuietly(File file) {
try {
return NetUtils.getStreamContent(IOUtils.openInputStream(file));
return IOUtils.getStreamContent(IOUtils.openInputStream(file));
} catch (IOException ex) {
HMCLog.err("Failed to read file: " + file, ex);
return null;
@@ -205,12 +209,12 @@ public class FileUtils {
public static String read(File file, String charset)
throws IOException {
return NetUtils.getStreamContent(IOUtils.openInputStream(file), charset);
return IOUtils.getStreamContent(IOUtils.openInputStream(file), charset);
}
public static String readIgnoreFileNotFound(File file) throws IOException {
try {
return NetUtils.getStreamContent(IOUtils.openInputStream(file));
return IOUtils.getStreamContent(IOUtils.openInputStream(file));
} catch (FileNotFoundException ex) {
return "";
}
@@ -364,7 +368,8 @@ public class FileUtils {
if ((parent != null)
&& (!parent.mkdirs()) && (!parent.isDirectory()))
throw new IOException("Directory '" + parent + "' could not be created");
file.createNewFile();
if (!file.createNewFile())
throw new IOException("File `" + file + "` cannot be created.");
}
return new FileOutputStream(file, append);
@@ -378,6 +383,6 @@ public class FileUtils {
for (File f : files)
if (f.getName().endsWith(suffix))
al.add(f);
return al.toArray(new File[0]);
return al.toArray(new File[al.size()]);
}
}

View File

@@ -27,22 +27,29 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.jackhuang.hellominecraft.util.func.Consumer;
import org.jackhuang.hellominecraft.util.func.Function;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
/**
*
* @author huang
*/
public class IOUtils {
public final class IOUtils {
private IOUtils() {
}
public static String addSeparator(String path) {
if (path == null || path.trim().length() == 0)
@@ -109,7 +116,7 @@ public class IOUtils {
java.io.File file = new java.io.File(realPath);
realPath = file.getAbsolutePath();
try {
realPath = java.net.URLDecoder.decode(realPath, "utf-8");
realPath = java.net.URLDecoder.decode(realPath, DEFAULT_CHARSET);
} catch (Exception e) {
e.printStackTrace();
}
@@ -119,7 +126,7 @@ public class IOUtils {
public static boolean isAbsolutePath(String path) {
if (path == null)
return true;
return path.startsWith("/") || path.indexOf(":") > 0;
return path.startsWith("/") || path.indexOf(':') > 0;
}
public static String getLocalMAC() {
@@ -205,19 +212,19 @@ public class IOUtils {
}
public static void write(byte[] data, OutputStream output)
throws IOException {
throws IOException {
if (data != null)
output.write(data);
}
public static void write(String data, OutputStream output, String encoding)
throws IOException {
throws IOException {
if (data != null)
output.write(data.getBytes(encoding));
}
public static FileInputStream openInputStream(File file)
throws IOException {
throws IOException {
if (file.exists()) {
if (file.isDirectory())
throw new IOException("File '" + file + "' exists but is a directory");
@@ -266,21 +273,17 @@ public class IOUtils {
}
public static List<String> readProcessByInputStream(String[] cmd) throws IOException, InterruptedException {
JavaProcess jp = new JavaProcess(cmd, new ProcessBuilder(cmd).start(), null);
ArrayList<String> lines = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader(jp.getRawProcess().getInputStream()))) {
jp.getRawProcess().waitFor();
String line;
while ((line = br.readLine()) != null)
lines.add(line);
}
return lines;
return readProcessImpl(cmd, p -> p.getInputStream());
}
public static List<String> readProcessByErrorStream(String[] cmd) throws IOException, InterruptedException {
return readProcessImpl(cmd, p -> p.getErrorStream());
}
private static List<String> readProcessImpl(String[] cmd, Function<Process, InputStream> callback) throws IOException, InterruptedException {
JavaProcess jp = new JavaProcess(cmd, new ProcessBuilder(cmd).start(), null);
ArrayList<String> lines = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader(jp.getRawProcess().getErrorStream()))) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(callback.apply(jp.getRawProcess()), Charset.defaultCharset()))) {
jp.getRawProcess().waitFor();
String line;
while ((line = br.readLine()) != null)
@@ -298,4 +301,39 @@ public class IOUtils {
while ((length = input.read(buf)) != -1)
output.write(buf, 0, length);
}
public static byte[] getBytesFromStream(InputStream is) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
IOUtils.copyStream(is, out);
is.close();
return out.toByteArray();
}
public static String getStreamContent(InputStream is) throws IOException {
return getStreamContent(is, DEFAULT_CHARSET);
}
public static String getStreamContent(InputStream is, String encoding)
throws IOException {
if (is == null)
return null;
StringBuilder sb = new StringBuilder();
try (InputStreamReader br = new InputStreamReader(is, encoding)) {
int len;
char[] buf = new char[16384];
while ((len = br.read(buf)) != -1)
sb.append(buf, 0, len);
}
return sb.toString();
}
public static final String DEFAULT_CHARSET = "UTF-8";
public static PrintStream createPrintStream(OutputStream out, Charset charset) {
try {
return new PrintStream(out, false, charset.name());
} catch (UnsupportedEncodingException ignore) {
return null;
}
}
}

View File

@@ -21,7 +21,9 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
@@ -38,8 +40,8 @@ public class Java {
temp.add(new Java("Default", System.getProperty("java.home")));
temp.add(new Java("Custom", null));
if (OS.os() == OS.WINDOWS)
temp.addAll(Java.queryAllJavaHomeInWindowsByReg());
if (OS.os() == OS.OSX)
temp.addAll(Java.queryAllJavaHomeInWindowsByReg().values());
else if (OS.os() == OS.OSX)
temp.addAll(Java.queryAllJDKInMac());
JAVA = Collections.unmodifiableList(temp);
}
@@ -114,18 +116,18 @@ public class Java {
* WINDOWS
* -----------------------------------
*/
public static List<Java> queryAllJavaHomeInWindowsByReg() {
List<Java> ans = new ArrayList<>();
public static Map<String, Java> queryAllJavaHomeInWindowsByReg() {
Map<String, Java> ans = new HashMap<>();
try {
queryJava(ans, "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment");
queryJava(ans, "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit");
queryJava(ans, "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\");
queryJava(ans, "HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\");
} catch (IOException | InterruptedException ex) {
HMCLog.err("Faield to query java", ex);
}
return ans;
}
private static void queryJava(List<Java> ans, String location) throws IOException, InterruptedException {
private static void queryJava(Map<String, Java> ans, String location) throws IOException, InterruptedException {
for (String java : queryRegSubFolders(location)) {
int s = 0;
for (char c : java.toCharArray())
@@ -133,9 +135,9 @@ public class Java {
++s;
if (s <= 1)
continue;
String javahome = queryRegValue(java, "JavaHome");
if (javahome != null)
ans.add(new Java(java.substring(location.length()), javahome));
String javahome = queryRegValue(java, "JavaHome"), ver = java.substring(location.length());
if (javahome != null && !ans.containsKey(ver))
ans.put(ver, new Java(ver, javahome));
}
}

View File

@@ -59,9 +59,12 @@ public final class JdkVersion implements Cloneable {
if (!(obj instanceof JdkVersion))
return false;
JdkVersion b = (JdkVersion) obj;
if (b.location == null || location == null)
return b.location == location;
return new File(b.location).equals(new File(location));
if (b.location == null && location == null)
return true;
else if (b.location == null || location == null)
return false;
else
return new File(b.location).equals(new File(location));
}
@Override
@@ -175,7 +178,7 @@ public final class JdkVersion implements Cloneable {
private static final Pattern p = Pattern.compile("java version \"[1-9]*\\.[1-9]*\\.[0-9]*(.*?)\"");
public static JdkVersion getJavaVersionFromExecutable(String file) throws IOException {
String[] str = new String[] { file, "-version" };
String[] str = new String[]{file, "-version"};
Platform platform = Platform.BIT_32;
String ver = null;
try {

View File

@@ -24,7 +24,9 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.util.Locale;
import java.util.StringTokenizer;
import org.jackhuang.hellominecraft.util.code.Charsets;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
/**
@@ -46,7 +48,7 @@ public enum OS {
}
public static OS os() {
String str = System.getProperty("os.name").toLowerCase();
String str = System.getProperty("os.name").toLowerCase(Locale.US);
if (str.contains("win"))
return OS.WINDOWS;
if (str.contains("mac"))
@@ -79,33 +81,42 @@ public enum OS {
}
}
public static int getSuggestedMemorySize() {
long total = getTotalPhysicalMemory();
if (total == -1)
return 1024;
int memory = (int) (total / 1024 / 1024) / 4;
memory = Math.round((float) memory / 128.0f) * 128;
return memory;
}
public static long[] memoryInfoForLinux() throws IOException {
File file = new File("/proc/meminfo");
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(file)));
long[] result = new long[4];
String str;
StringTokenizer token;
while ((str = br.readLine()) != null) {
token = new StringTokenizer(str);
if (!token.hasMoreTokens())
continue;
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charsets.UTF_8))) {
long[] result = new long[4];
String str;
StringTokenizer token;
while ((str = br.readLine()) != null) {
token = new StringTokenizer(str);
if (!token.hasMoreTokens())
continue;
str = token.nextToken();
if (!token.hasMoreTokens())
continue;
str = token.nextToken();
if (!token.hasMoreTokens())
continue;
if (str.equalsIgnoreCase("MemTotal:"))
result[0] = Long.parseLong(token.nextToken());
else if (str.equalsIgnoreCase("MemFree:"))
result[1] = Long.parseLong(token.nextToken());
else if (str.equalsIgnoreCase("SwapTotal:"))
result[2] = Long.parseLong(token.nextToken());
else if (str.equalsIgnoreCase("SwapFree:"))
result[3] = Long.parseLong(token.nextToken());
if (str.equalsIgnoreCase("MemTotal:"))
result[0] = Long.parseLong(token.nextToken());
else if (str.equalsIgnoreCase("MemFree:"))
result[1] = Long.parseLong(token.nextToken());
else if (str.equalsIgnoreCase("SwapTotal:"))
result[2] = Long.parseLong(token.nextToken());
else if (str.equalsIgnoreCase("SwapFree:"))
result[3] = Long.parseLong(token.nextToken());
}
return result;
}
return result;
}
public static String getLinuxReleaseVersion() throws IOException {

View File

@@ -17,6 +17,7 @@
*/
package org.jackhuang.hellominecraft.util.system;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
@@ -75,7 +76,7 @@ public class ProcessThread extends Thread {
} else
line += (char) ch;
stopEvent.execute(p);
} catch (Exception e) {
} catch (IOException e) {
HMCLog.err("An error occured when reading process stdout/stderr.", e);
} finally {
IOUtils.closeQuietly(br);

View File

@@ -17,7 +17,6 @@
*/
package org.jackhuang.hellominecraft.util.system;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -61,10 +60,9 @@ public class ZipEngine {
/**
* 功能:把 sourceDir 目录下的所有文件进行 zip 格式的压缩,保存为指定 zip 文件
*
* @param sourceDir 源文件夹
* @param zipFile 压缩生成的zip文件路径。
* @param sourceDir 源文件夹
* @param pathNameCallback callback(pathName, isDirectory) returns your
* modified pathName
* modified pathName
*
* @throws java.io.IOException 压缩失败或无法读取
*/
@@ -75,11 +73,11 @@ public class ZipEngine {
/**
* 将文件压缩成zip文件
*
* @param source zip文件路径
* @param basePath 待压缩文件根目录
* @param zos zip文件的os
* @param source zip文件路径
* @param basePath 待压缩文件根目录
* @param zos zip文件的os
* @param pathNameCallback callback(pathName, isDirectory) returns your
* modified pathName, null if you dont want this file zipped
* modified pathName, null if you dont want this file zipped
*/
private void putDirectoryImpl(File source, String basePath, BiFunction<String, Boolean, String> pathNameCallback) throws IOException {
File[] files;
@@ -95,7 +93,7 @@ public class ZipEngine {
for (File file : files)
if (file.isDirectory()) {
pathName = file.getPath().substring(basePath.length() + 1)
+ "/";
+ "/";
pathName = pathName.replace('\\', '/');
if (pathNameCallback != null)
pathName = pathNameCallback.apply(pathName, true);
@@ -117,14 +115,14 @@ public class ZipEngine {
}
public void putFile(File file, String pathName) throws IOException {
putStream(new FileInputStream(file), pathName);
try (FileInputStream fis = new FileInputStream(file)) {
putStream(fis, pathName);
}
}
public void putStream(InputStream is, String pathName) throws IOException {
try (BufferedInputStream bis = new BufferedInputStream(is)) {
put(new ZipEntry(pathName));
IOUtils.copyStream(bis, zos, buf);
}
put(new ZipEntry(pathName));
IOUtils.copyStream(is, zos, buf);
}
public void putTextFile(String text, String pathName) throws IOException {

View File

@@ -18,7 +18,7 @@
package org.jackhuang.hellominecraft.util.tasks;
import java.io.File;
import org.jackhuang.hellominecraft.util.system.Compressor;
import org.jackhuang.hellominecraft.util.system.CompressingUtils;
/**
*
@@ -34,8 +34,8 @@ public class DecompressTask extends Task {
}
@Override
public void executeTask() throws Throwable {
Compressor.unzip(src, dest);
public void executeTask(boolean areDependTasksSucceeded) throws Throwable {
CompressingUtils.unzip(src, dest);
}
@Override

View File

@@ -18,6 +18,7 @@
package org.jackhuang.hellominecraft.util.tasks;
import java.io.File;
import java.io.IOException;
/**
*
@@ -32,8 +33,8 @@ public class DeleteFileTask extends Task {
}
@Override
public void executeTask() throws Throwable {
f.delete();
public void executeTask(boolean areDependTasksSucceeded) throws Throwable {
if (!f.delete()) throw new IOException("Failed to delete" + f);
}
@Override

View File

@@ -49,7 +49,9 @@ public class DoubleTask extends TaskInfo {
}
@Override
public void executeTask() throws Throwable {
public void executeTask(boolean areDependTasksSucceeded) throws Throwable {
if (!areDependTasksSucceeded)
throw new IllegalStateException("Depend tasks failed.");
}
}

View File

@@ -29,7 +29,7 @@ public class ParallelTask extends Task {
Collection<Task> dependsTask = new HashSet<>();
@Override
public void executeTask() {
public void executeTask(boolean areDependTasksSucceeded) {
}
@Override

View File

@@ -17,7 +17,6 @@
*/
package org.jackhuang.hellominecraft.util.tasks;
import java.util.ArrayList;
import java.util.Collection;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
@@ -29,8 +28,11 @@ public abstract class Task {
/**
* Run in a new thread(packed in TaskList).
*
* @param areDependTasksSucceeded Would be true if all of tasks which this task depends on have succeed.
* @throws java.lang.Throwable If a task throws an exception, this task will be marked as `failed`.
*/
public abstract void executeTask() throws Throwable;
public abstract void executeTask(boolean areDependTasksSucceeded) throws Throwable;
/**
* if this func returns false, TaskList will force abort the thread. run in
@@ -54,37 +56,25 @@ public abstract class Task {
}
protected Throwable failReason = null;
/**
* This method can be only invoked by TaskList.
* @param s what the `executeTask` throws.
*/
protected void setFailReason(Throwable s) {
failReason = s;
}
protected String tag;
protected boolean parallelExecuting;
public String getTag() {
return tag;
}
public Task setTag(String tag) {
this.tag = tag;
return this;
}
public boolean isParallelExecuting() {
return parallelExecuting;
}
public void setParallelExecuting(boolean parallelExecuting) {
this.parallelExecuting = parallelExecuting;
}
ArrayList<DoingDoneListener<Task>> taskListener = new ArrayList();
public Task addTaskListener(DoingDoneListener<Task> l) {
taskListener.add(l);
return this;
}
public ArrayList<DoingDoneListener<Task>> getTaskListeners() {
return taskListener;
}
public abstract String getInfo();
public Collection<Task> getDependTasks() {
@@ -95,8 +85,6 @@ public abstract class Task {
return null;
}
public boolean areDependTasksSucceeded;
protected ProgressProviderListener ppl;
public Task setProgressProviderListener(ProgressProviderListener p) {
@@ -117,7 +105,7 @@ public abstract class Task {
if (c != null)
for (Task t : c)
t.runWithException();
executeTask();
executeTask(true);
c = getAfterTasks();
if (c != null)
for (Task t : c)

View File

@@ -29,6 +29,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jackhuang.hellominecraft.util.EventHandler;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
/**
@@ -38,7 +39,7 @@ import org.jackhuang.hellominecraft.util.logging.HMCLog;
public class TaskList extends Thread {
List<Task> taskQueue = Collections.synchronizedList(new LinkedList<>());
ArrayList<Runnable> allDone = new ArrayList();
public final EventHandler<Object> doneEvent = new EventHandler<>(this);
ArrayList<DoingDoneListener<Task>> taskListener = new ArrayList();
int totTask;
@@ -53,10 +54,6 @@ public class TaskList extends Thread {
taskQueue.clear();
}
public void addAllDoneListener(Runnable l) {
allDone.add(l);
}
public void addTaskListener(DoingDoneListener<Task> l) {
taskListener.add(l);
}
@@ -83,9 +80,12 @@ public class TaskList extends Thread {
@Override
public void run() {
if (!executeTask(task))
bool.set(false);
latch.countDown();
try {
if (!executeTask(task))
bool.set(false);
} finally {
latch.countDown();
}
}
}
@@ -101,9 +101,10 @@ public class TaskList extends Thread {
AtomicBoolean bool = new AtomicBoolean(true);
CountDownLatch counter = new CountDownLatch(c.size());
for (Task t2 : c) {
if (t2 == null)
if (t2 == null) {
counter.countDown();
continue;
t2.setParallelExecuting(true);
}
Invoker thread = new Invoker(t2, counter, bool);
invokers.add(thread);
if (!EXECUTOR_SERVICE.isShutdown() && !EXECUTOR_SERVICE.isTerminated())
@@ -126,15 +127,13 @@ public class TaskList extends Thread {
if (c == null)
c = new HashSet<>();
HMCLog.log("Executing task: " + t.getInfo());
for (DoingDoneListener<Task> d : t.getTaskListeners())
d.onDoing(t, c);
for (DoingDoneListener<Task> d : taskListener)
d.onDoing(t, c);
t.areDependTasksSucceeded = processTasks(c);
boolean areDependTasksSucceeded = processTasks(c);
boolean flag = true;
try {
t.executeTask();
t.executeTask(areDependTasksSucceeded);
} catch (Throwable e) {
t.setFailReason(e);
flag = false;
@@ -144,8 +143,6 @@ public class TaskList extends Thread {
Collection<Task> at = t.getAfterTasks();
if (at == null)
at = new HashSet<>();
for (DoingDoneListener<Task> d : t.getTaskListeners())
d.onDone(t, at);
for (DoingDoneListener<Task> d : taskListener)
d.onDone(t, at);
processTasks(at);
@@ -153,22 +150,21 @@ public class TaskList extends Thread {
HMCLog.err("Task failed: " + t.getInfo(), t.getFailReason());
for (DoingDoneListener<Task> d : taskListener)
d.onFailed(t);
for (DoingDoneListener<Task> d : t.getTaskListeners())
d.onFailed(t);
}
return flag;
}
@Override
public void run() {
Thread.currentThread().setName("TaskList");
Thread.currentThread().setName("Task List");
totTask = taskQueue.size();
while (!taskQueue.isEmpty())
executeTask(taskQueue.remove(0));
if (shouldContinue)
for (Runnable d : allDone)
d.run();
if (shouldContinue) {
HMCLog.log("Tasks are successfully finished.");
doneEvent.execute(null);
}
}
public boolean isEmpty() {

View File

@@ -35,7 +35,7 @@ public class TaskRunnable extends TaskInfo {
}
@Override
public void executeTask() {
public void executeTask(boolean areDependTasksSucceeded) {
r.run();
}

View File

@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumn;
import org.jackhuang.hellominecraft.util.C;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.MessageBox;
@@ -32,16 +33,9 @@ import org.jackhuang.hellominecraft.util.ui.SwingUtils;
* @author huangyuhui
*/
public class TaskWindow extends javax.swing.JDialog
implements ProgressProviderListener, Runnable, DoingDoneListener<Task> {
implements ProgressProviderListener, DoingDoneListener<Task> {
private static volatile TaskWindow INSTANCE = null;
private static synchronized TaskWindow instance() {
if (INSTANCE == null)
INSTANCE = new TaskWindow();
INSTANCE.clean();
return INSTANCE;
}
private static volatile TaskWindow INST = null;
public static TaskWindowFactory factory() {
return new TaskWindowFactory();
@@ -49,7 +43,7 @@ public class TaskWindow extends javax.swing.JDialog
boolean suc = false;
private TaskList taskList;
private transient TaskList taskList;
private final ArrayList<String> failReasons = new ArrayList();
private String stackTrace = null, lastStackTrace = null;
@@ -59,34 +53,34 @@ public class TaskWindow extends javax.swing.JDialog
private TaskWindow() {
initComponents();
setLocationRelativeTo(null);
if (lstDownload.getColumnModel().getColumnCount() > 1) {
int i = 35;
lstDownload.getColumnModel().getColumn(1).setMinWidth(i);
lstDownload.getColumnModel().getColumn(1).setMaxWidth(i);
lstDownload.getColumnModel().getColumn(1).setPreferredWidth(i);
TableColumn c = lstDownload.getColumnModel().getColumn(1);
c.setMinWidth(i);
c.setMaxWidth(i);
c.setPreferredWidth(i);
}
setModal(true);
setLocationRelativeTo(null);
}
public TaskWindow addTask(Task task) {
taskList.addTask(task);
return this;
}
public synchronized void clean() {
private synchronized void clean() {
if (isVisible())
return;
taskList = new TaskList();
taskList.addTaskListener(this);
taskList.addAllDoneListener(this);
taskList.doneEvent.register(() -> {
SwingUtilities.invokeLater(() -> {
dispose();
suc = true;
});
});
}
public static String downloadSource = "";
public boolean start() {
private boolean start() {
if (isVisible() || taskList == null || taskList.isAlive())
return false;
pgsTotal.setValue(0);
@@ -102,7 +96,7 @@ public class TaskWindow extends javax.swing.JDialog
HMCLog.err(stackTrace);
HMCLog.err("There's the stacktrace of the last invoking.");
HMCLog.err(lastStackTrace);
MessageBox.Show(C.i18n("taskwindow.no_more_instance"));
MessageBox.show(C.i18n("taskwindow.no_more_instance"));
return false;
}
setTitle(C.i18n("taskwindow.title") + " - " + C.i18n("download.source") + ": " + downloadSource);
@@ -174,7 +168,7 @@ public class TaskWindow extends javax.swing.JDialog
}// </editor-fold>//GEN-END:initComponents
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
if (MessageBox.Show(C.i18n("operation.confirm_stop"), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
if (MessageBox.show(C.i18n("operation.confirm_stop"), MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION)
this.dispose();
}//GEN-LAST:event_btnCancelActionPerformed
@@ -185,13 +179,12 @@ public class TaskWindow extends javax.swing.JDialog
if (!this.failReasons.isEmpty()) {
String str = StrUtils.parseParams("", failReasons.toArray(), "\n");
SwingUtilities.invokeLater(() -> MessageBox.Show(str, C.i18n("message.error"), MessageBox.ERROR_MESSAGE));
SwingUtilities.invokeLater(() -> MessageBox.show(str, C.i18n("message.error"), MessageBox.ERROR_MESSAGE));
failReasons.clear();
}
if (!suc) {
if (taskList != null)
SwingUtilities.invokeLater(taskList::abort);
SwingUtilities.invokeLater(taskList::abort);
HMCLog.log("Tasks have been canceled by user.");
}
taskList = null;
@@ -223,15 +216,6 @@ public class TaskWindow extends javax.swing.JDialog
});
}
@Override
public void run() {
SwingUtilities.invokeLater(() -> {
dispose();
suc = true;
HMCLog.log("Tasks are finished.");
});
}
@Override
public void onDoing(Task task, Collection<Task> taskCollection) {
if (task == null)
@@ -309,36 +293,33 @@ public class TaskWindow extends javax.swing.JDialog
});
}
public static boolean execute(Task... ts) {
TaskWindowFactory f = factory();
for (Task t : ts)
f.append(t);
return f.create();
}
public static class TaskWindowFactory {
LinkedList<Task> ll = new LinkedList<>();
boolean flag;
public TaskWindowFactory append(Task t) {
if (t != null)
ll.add(t);
public TaskWindowFactory append(Task ts) {
if (ts != null)
ll.add(ts);
return this;
}
public boolean create() {
public boolean execute(Task... ts) {
for (Task t : ts)
append(t);
String stacktrace = StrUtils.getStackTrace(new Throwable());
return SwingUtils.invokeAndWait(() -> {
final TaskWindow tw = instance();
synchronized (tw) {
if (tw.isVisible())
if (INST == null)
INST = new TaskWindow();
INST.clean();
synchronized (INST) {
if (INST.isVisible())
return false;
for (Task t : ll)
tw.addTask(t);
tw.lastStackTrace = tw.stackTrace;
tw.stackTrace = stacktrace;
return tw.start();
INST.taskList.addTask(t);
INST.lastStackTrace = INST.stackTrace;
INST.stackTrace = stacktrace;
return INST.start();
}
});
}

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.util.tasks.communication;
package org.jackhuang.hellominecraft.util.tasks.comm;
/**
*

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.util.tasks.communication;
package org.jackhuang.hellominecraft.util.tasks.comm;
/**
*

View File

@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see {http://www.gnu.org/licenses/}.
*/
package org.jackhuang.hellominecraft.util.tasks.communication;
package org.jackhuang.hellominecraft.util.tasks.comm;
import org.jackhuang.hellominecraft.util.tasks.Task;

View File

@@ -27,21 +27,8 @@ import org.jackhuang.hellominecraft.util.ui.LogWindow;
public class ContentGetAndShowTask extends HTTPGetTask implements Event<String> {
public ContentGetAndShowTask(String info, String changeLogUrl) {
super(changeLogUrl);
this.info = info;
}
@Override
public void executeTask() throws Exception {
super(info, changeLogUrl);
tdtsl.register(this);
super.executeTask();
}
String info;
@Override
public String getInfo() {
return info;
}
@Override

View File

@@ -31,8 +31,8 @@ import org.jackhuang.hellominecraft.util.code.DigestUtils;
import org.jackhuang.hellominecraft.util.func.Function;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.tasks.Task;
import org.jackhuang.hellominecraft.util.tasks.communication.PreviousResult;
import org.jackhuang.hellominecraft.util.tasks.communication.PreviousResultRegistrar;
import org.jackhuang.hellominecraft.util.tasks.comm.PreviousResult;
import org.jackhuang.hellominecraft.util.tasks.comm.PreviousResultRegistrar;
import org.jackhuang.hellominecraft.util.system.IOUtils;
/**
@@ -113,7 +113,7 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
// Download file.
@Override
public void executeTask() throws Throwable {
public void executeTask(boolean areDependTasksSucceeded) throws Throwable {
for (PreviousResult<String> p : al)
this.url = IOUtils.parseURL(p.getResult());
@@ -158,7 +158,7 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
if (!tempFile.exists())
tempFile.createNewFile();
else if (!tempFile.renameTo(tempFile)) // check file lock
throw new RuntimeException("The temp file is locked, maybe there is an application using the file?");
throw new IllegalStateException("The temp file is locked, maybe there is an application using the file?");
// Open file and seek to the end of it.
file = new RandomAccessFile(tempFile, "rw");
@@ -217,7 +217,7 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
if (ppl != null)
ppl.onProgressProviderDone(this);
return;
} catch (Exception e) {
} catch (IOException | IllegalStateException | NetException e) {
setFailReason(new NetException(C.i18n("download.failed") + " " + url, e));
} finally {
closeFiles();
@@ -232,7 +232,7 @@ public class FileDownloadTask extends Task implements PreviousResult<File>, Prev
}
public static void download(String url, File file, DownloadListener dl) throws Throwable {
((Task) new FileDownloadTask(url, file).setProgressProviderListener(dl)).executeTask();
((Task) new FileDownloadTask(url, file).setProgressProviderListener(dl)).executeTask(true);
}
@Override

View File

@@ -18,12 +18,13 @@
package org.jackhuang.hellominecraft.util.tasks.download;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import org.jackhuang.hellominecraft.util.logging.HMCLog;
import org.jackhuang.hellominecraft.util.tasks.TaskInfo;
import org.jackhuang.hellominecraft.util.tasks.communication.PreviousResult;
import org.jackhuang.hellominecraft.util.tasks.comm.PreviousResult;
import org.jackhuang.hellominecraft.util.EventHandler;
/**
@@ -51,11 +52,11 @@ public class HTTPGetTask extends TaskInfo implements PreviousResult<String> {
}
@Override
public void executeTask() throws Exception {
public void executeTask(boolean areDependTasksSucceeded) throws Exception {
Exception t = null;
for (int repeat = 0; repeat < 6; repeat++) {
if (repeat > 0)
HMCLog.warn("Failed to download, repeat: " + repeat);
for (int time = 0; time < 6; time++) {
if (time > 0)
HMCLog.warn("Failed to download, repeat times: " + time);
try {
if (ppl != null)
ppl.setProgress(this, -1, 1);
@@ -76,10 +77,10 @@ public class HTTPGetTask extends TaskInfo implements PreviousResult<String> {
if (!shouldContinue)
return;
}
result = baos.toString();
result = baos.toString(encoding);
tdtsl.execute(result);
return;
} catch (Exception ex) {
} catch (IOException ex) {
t = new NetException("Failed to get " + url, ex);
}
}

View File

@@ -24,8 +24,6 @@ import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
public abstract class AbstractFilter
implements BufferedImageOp {
@@ -55,36 +53,4 @@ public abstract class AbstractFilter
public RenderingHints getRenderingHints() {
return null;
}
protected int[] getPixels(BufferedImage img, int x, int y, int w, int h, int[] pixels) {
if ((w == 0) || (h == 0))
return new int[0];
if (pixels == null)
pixels = new int[w * h];
else if (pixels.length < w * h)
throw new IllegalArgumentException("pixels array must have a length >= w*h");
int imageType = img.getType();
if ((imageType == 2) || (imageType == 1)) {
Raster raster = img.getRaster();
return (int[]) (int[]) raster.getDataElements(x, y, w, h, pixels);
}
return img.getRGB(x, y, w, h, pixels, 0, w);
}
protected void setPixels(BufferedImage img, int x, int y, int w, int h, int[] pixels) {
if ((pixels == null) || (w == 0) || (h == 0))
return;
if (pixels.length < w * h)
throw new IllegalArgumentException("pixels array must have a length >= w*h");
int imageType = img.getType();
if ((imageType == 2) || (imageType == 1)) {
WritableRaster raster = img.getRaster();
raster.setDataElements(x, y, w, h, pixels);
} else
img.setRGB(x, y, w, h, pixels, 0, w);
}
}

View File

@@ -23,8 +23,11 @@ import java.awt.Color;
*
* @author huangyuhui
*/
public class BasicColors {
public final class BasicColors {
private BasicColors() {
}
private static Color getWebColor(String c) {
return new Color(
Integer.parseInt(c.substring(0, 2), 16),
@@ -41,7 +44,7 @@ public class BasicColors {
public static final Color COLOR_WHITE_TEXT = new Color(254, 254, 254);
public static final Color COLOR_CENTRAL_BACK = new Color(25, 30, 34, 160);
public static final Color bgcolors[] = new Color[] {
public static final Color[] BG_COLORS = new Color[] {
COLOR_BLUE,
getWebColor("1ABC9C"),
getWebColor("9B59B6"),
@@ -49,7 +52,8 @@ public class BasicColors {
getWebColor("E67E22"),
getWebColor("E74C3C")
};
public static final Color bgcolors_darker[] = new Color[] {
public static final Color[] BG_COLORS_DARKER = new Color[] {
COLOR_BLUE_DARKER,
getWebColor("16A085"),
getWebColor("8E44AD"),

View File

@@ -68,8 +68,9 @@ public class DropShadowBorder extends AbstractBorder {
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Pair<Integer, Integer> pair = new Pair<>(width, height);
if (CACHE.containsKey(pair))
g.drawImage(CACHE.get(pair), x, y, width, height, null);
BufferedImage list;
int border = this.thickness * 4;
if (CACHE.containsKey(pair)) list = CACHE.get(pair);
else {
BufferedImage shadow = new BufferedImage(width, height, 2);
@@ -82,7 +83,6 @@ public class DropShadowBorder extends AbstractBorder {
g2.fillRect(0, 0, width, height);
g2.setComposite(oldComposite);
g2.setColor(this.color);
int border = (int) (this.thickness * 4);
g2.fillRect(border, border + border / 6, width - border * 2, height - border * 2);
g2.dispose();
@@ -91,9 +91,14 @@ public class DropShadowBorder extends AbstractBorder {
shadow = blur.filter(shadow, null);
shadow = blur.filter(shadow, null);
shadow = blur.filter(shadow, null);
CACHE.put(pair, shadow);
g.drawImage(shadow, x, y, width, height, null);
CACHE.put(pair, list = shadow);
}
g.drawImage(list, 0, 0, width, height, null);
}
void copyFromArray(int[] from, int W, int H, int[] to, int x, int y, int w, int h) {
for (int i = 0; i < h; ++i)
for (int j = 0; j < w; ++j)
to[i * w + j] = from[(i + y) * W + j + x];
}
}

View File

@@ -42,20 +42,22 @@ public class FastBlurFilter extends AbstractFilter {
public BufferedImage filter(BufferedImage src, BufferedImage dst) {
int width = src.getWidth();
int height = src.getHeight();
return filter(src, new int[width * height], dst, new int[width * height]);
}
public BufferedImage filter(BufferedImage src, int[] srcPixels, BufferedImage dst, int[] dstPixels) {
int width = src.getWidth();
int height = src.getHeight();
if (dst == null)
dst = createCompatibleDestImage(src, null);
int[] srcPixels = new int[width * height];
int[] dstPixels = new int[width * height];
getPixels(src, 0, 0, width, height, srcPixels);
GraphicsUtils.getPixels(src, 0, 0, width, height, srcPixels);
blur(srcPixels, dstPixels, width, height, this.radius);
blur(dstPixels, srcPixels, height, width, this.radius);
setPixels(dst, 0, 0, width, height, srcPixels);
GraphicsUtils.setPixels(dst, 0, 0, width, height, srcPixels);
return dst;
}

View File

@@ -6,6 +6,8 @@ import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.plaf.synth.SynthContext;
@@ -203,5 +205,81 @@ public class GraphicsUtils extends SynthGraphicsUtils {
int aMid = aTop + ((aBot - aTop) * percent / 100);
return new Color(rMid, gMid, bMid, aMid);
}
/**
* <p>Returns an array of pixels, stored as integers, from a
* <code>BufferedImage</code>. The pixels are grabbed from a rectangular
* area defined by a location and two dimensions. Calling this method on
* an image of type different from <code>BufferedImage.TYPE_INT_ARGB</code>
* and <code>BufferedImage.TYPE_INT_RGB</code> will unmanage the image.</p>
*
* @param img the source image
* @param x the x location at which to start grabbing pixels
* @param y the y location at which to start grabbing pixels
* @param w the width of the rectangle of pixels to grab
* @param h the height of the rectangle of pixels to grab
* @param pixels a pre-allocated array of pixels of size w*h; can be null
* @return <code>pixels</code> if non-null, a new array of integers
* otherwise
* @throws IllegalArgumentException is <code>pixels</code> is non-null and
* of length &lt; w*h
*/
public static int[] getPixels(BufferedImage img,
int x, int y, int w, int h, int[] pixels) {
if (w == 0 || h == 0) {
return new int[0];
}
if (pixels == null) {
pixels = new int[w * h];
} else if (pixels.length < w * h) {
throw new IllegalArgumentException("pixels array must have a length" +
" >= w*h");
}
int imageType = img.getType();
if (imageType == BufferedImage.TYPE_INT_ARGB ||
imageType == BufferedImage.TYPE_INT_RGB) {
Raster raster = img.getRaster();
return (int[]) raster.getDataElements(x, y, w, h, pixels);
}
// Unmanages the image
return img.getRGB(x, y, w, h, pixels, 0, w);
}
/**
* <p>Writes a rectangular area of pixels in the destination
* <code>BufferedImage</code>. Calling this method on
* an image of type different from <code>BufferedImage.TYPE_INT_ARGB</code>
* and <code>BufferedImage.TYPE_INT_RGB</code> will unmanage the image.</p>
*
* @param img the destination image
* @param x the x location at which to start storing pixels
* @param y the y location at which to start storing pixels
* @param w the width of the rectangle of pixels to store
* @param h the height of the rectangle of pixels to store
* @param pixels an array of pixels, stored as integers
* @throws IllegalArgumentException is <code>pixels</code> is non-null and
* of length &lt; w*h
*/
public static void setPixels(BufferedImage img,
int x, int y, int w, int h, int[] pixels) {
if (pixels == null || w == 0 || h == 0) {
return;
} else if (pixels.length < w * h) {
throw new IllegalArgumentException("pixels array must have a length" +
" >= w*h");
}
int imageType = img.getType();
if (imageType == BufferedImage.TYPE_INT_ARGB ||
imageType == BufferedImage.TYPE_INT_RGB) {
WritableRaster raster = img.getRaster();
raster.setDataElements(x, y, w, h, pixels);
} else {
// Unmanages the image
img.setRGB(x, y, w, h, pixels, 0, w);
}
}
}

View File

@@ -17,6 +17,7 @@
*/
package org.jackhuang.hellominecraft.util.ui;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
@@ -33,7 +34,7 @@ import org.jackhuang.hellominecraft.util.Utils;
* @author huangyuhui
*/
public class LogWindow extends javax.swing.JFrame {
boolean movingEnd;
NonFunction<Boolean> listener;
Runnable terminateGameListener;
@@ -43,17 +44,20 @@ public class LogWindow extends javax.swing.JFrame {
*/
public LogWindow() {
initComponents();
movingEnd = true;
setLocationRelativeTo(null);
txtLog.setEditable(false);
DoubleOutputStream out = new DoubleOutputStream(new LogWindowOutputStream(this, Level.INFO), System.out);
System.setOut(new LauncherPrintStream(out));
DoubleOutputStream err = new DoubleOutputStream(new LogWindowOutputStream(this, Level.ERROR), System.err);
System.setErr(new LauncherPrintStream(err));
SwingUtilities.invokeLater(() -> {
setLocationRelativeTo(null);
txtLog.setEditable(false);
});
}
public static final LogWindow INSTANCE = new LogWindow();
/**
@@ -235,15 +239,15 @@ public class LogWindow extends javax.swing.JFrame {
terminateGameListener.run();
SwingUtils.exitIfNoWindow(this);
}//GEN-LAST:event_formWindowClosing
public void log(String status) {
log(status, Level.INFO);
}
public void warning(String status) {
log(status, Level.WARN);
}
public synchronized void log(String status, Level c) {
status = status.replace("\t", " ");
Document d = txtLog.getStyledDocument();
@@ -254,33 +258,33 @@ public class LogWindow extends javax.swing.JFrame {
} catch (Exception ex) {
HMCLog.err("Failed to insert \"" + status + "\" to " + d.getLength(), ex);
}
if (movingEnd) {
int position = d.getLength();
txtLog.setCaretPosition(position);
}
}
public void setExit(NonFunction<Boolean> exit) {
this.listener = exit;
}
public void setTerminateGame(Runnable l) {
this.terminateGameListener = l;
}
public void clean() {
txtLog.setText("");
}
public boolean getMovingEnd() {
return movingEnd;
}
public void setMovingEnd(boolean b) {
movingEnd = b;
}
@Override
public void setVisible(boolean b) {
lblCrash.setVisible(false);
@@ -289,7 +293,7 @@ public class LogWindow extends javax.swing.JFrame {
btnMCF.setVisible(false);
super.setVisible(b);
}
public void showAsCrashWindow(boolean out_date) {
if (out_date) {
lblCrash.setVisible(false);
@@ -304,7 +308,7 @@ public class LogWindow extends javax.swing.JFrame {
btnMCF.setVisible(true);
lblCrash.setText(C.i18n("ui.label.crashing"));
}
super.setVisible(true);
}

View File

@@ -21,6 +21,7 @@ import java.io.OutputStream;
import java.util.Objects;
import java.util.Timer;
import javax.swing.SwingUtilities;
import org.jackhuang.hellominecraft.util.code.Charsets;
import org.jackhuang.hellominecraft.util.logging.Level;
/**
@@ -35,8 +36,8 @@ public class LogWindowOutputStream extends OutputStream {
private final Level sas;
public LogWindowOutputStream(LogWindow logWindow, Level l) {
Objects.nonNull(logWindow);
Objects.nonNull(l);
Objects.requireNonNull(logWindow);
Objects.requireNonNull(l);
txt = logWindow;
sas = l;
}
@@ -48,7 +49,7 @@ public class LogWindowOutputStream extends OutputStream {
@Override
public final void write(byte[] arr, int off, int len) {
append(new String(arr, off, len));
append(new String(arr, off, len, Charsets.UTF_8));
}
private void append(final String str) {
@@ -56,14 +57,13 @@ public class LogWindowOutputStream extends OutputStream {
SwingUtilities.invokeLater(() -> {
txt.log(str, Level.guessLevel(str, sas));
});
} catch (Throwable e) {
e.printStackTrace();
} catch (Throwable ignore) {
}
}
@Override
public final void write(int i) {
append(new String(new byte[] { (byte) i }));
append(new String(new byte[] { (byte) i }, Charsets.UTF_8));
}
public static void dispose() {

View File

@@ -54,8 +54,11 @@ import org.jackhuang.hellominecraft.util.system.OS;
*
* @author huang
*/
public class SwingUtils {
public final class SwingUtils {
private SwingUtils() {
}
/**
* Make DefaultTableModel by overriding getColumnClass and isCellEditable of
* DefaultTableModel.
@@ -100,7 +103,7 @@ public class SwingUtils {
try {
java.awt.Desktop.getDesktop().open(f);
} catch (Throwable ex) {
MessageBox.Show(C.i18n("message.cannot_open_explorer") + ex.getMessage());
MessageBox.show(C.i18n("message.cannot_open_explorer") + ex.getMessage());
HMCLog.warn("Failed to open " + path + " through java.awt.Desktop.getDesktop().open()", ex);
}
break;
@@ -299,7 +302,7 @@ public class SwingUtils {
try {
Utils.shutdownForcely(0);
} catch (Exception e) {
MessageBox.Show(C.i18n("launcher.exit_failed"));
MessageBox.show(C.i18n("launcher.exit_failed"));
HMCLog.err("Failed to shutdown forcely", e);
}
else

View File

@@ -125,6 +125,7 @@ public class NavButtonManager implements ActionListener {
final boolean aqua = "Aqua".equals(UIManager.getLookAndFeel().getID());
buttons = new JPanel() {
@Override
public void doLayout() {
Insets ins = getInsets();
JButton b = aqua ? finish : cancel;
@@ -221,6 +222,7 @@ public class NavButtonManager implements ActionListener {
}
@Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
@@ -590,10 +592,12 @@ public class NavButtonManager implements ActionListener {
boolean wasBusy = false;
@Override
public void stepsChanged(Wizard wizard) {
// do nothing
}
@Override
public void navigabilityChanged(final Wizard wizard) {
final Runnable runnable = () -> {
if (wizard.isBusy()) {
@@ -618,6 +622,7 @@ public class NavButtonManager implements ActionListener {
EventQueue.invokeLater(runnable);
}
@Override
public void selectionChanged(Wizard wizard) {
// do nothing
}

View File

@@ -48,6 +48,7 @@ public class NavProgress implements ResultProgressHandle {
this.parent = impl;
}
@Override
public void addProgressComponents(Container panel) {
panel.add(lbl);
panel.add(progressBar);
@@ -55,6 +56,7 @@ public class NavProgress implements ResultProgressHandle {
ipanel = panel;
}
@Override
public void setProgress(final String description, final int currentStep, final int totalSteps) {
invoke(() -> {
lbl.setText(description == null ? " " : description);
@@ -62,6 +64,7 @@ public class NavProgress implements ResultProgressHandle {
});
}
@Override
public void setProgress(final int currentStep, final int totalSteps) {
invoke(() -> {
if (totalSteps == -1) {
@@ -82,6 +85,7 @@ public class NavProgress implements ResultProgressHandle {
});
}
@Override
public void setBusy(final String description) {
invoke(() -> {
lbl.setText(description == null ? " " : description);
@@ -101,6 +105,7 @@ public class NavProgress implements ResultProgressHandle {
}
}
@Override
public void finished(final Object o) {
isRunning = false;
Runnable r = () -> {
@@ -118,6 +123,7 @@ public class NavProgress implements ResultProgressHandle {
invoke(r);
}
@Override
public void failed(final String message, final boolean canGoBack) {
failMessage = message;
isRunning = false;
@@ -134,6 +140,7 @@ public class NavProgress implements ResultProgressHandle {
invoke(r);
}
@Override
public boolean isRunning() {
return isRunning;
}

View File

@@ -66,11 +66,10 @@ import org.jackhuang.hellominecraft.util.ui.wizard.spi.WizardPanel;
* <b><i><font color="red">This class is NOT AN API CLASS. There is no
* commitment that it will remain backward compatible or even exist in the
* future. The API of this library is in the packages
* <code>org.netbeans.api.wizard</code>
* and <code>org.netbeans.spi.wizard</code></font></i></b>.
* <code>org.netbeans.api.wizard</code> and
* <code>org.netbeans.spi.wizard</code></font></i></b>.
* <p>
* Use
* <code>WizardDisplayer.showWizard()</code> or its other static methods to
* Use <code>WizardDisplayer.showWizard()</code> or its other static methods to
* display wizards in a way which will continue to work over time.
*
* @author stanley@StanleyKnutson.com
@@ -122,9 +121,10 @@ public class WizardDisplayerImpl extends WizardDisplayer {
protected void buildStepTitle() {
ttlLabel = new JLabel(wizard.getStepDescription(wizard.getAllSteps()[0]));
ttlLabel.setBorder(BorderFactory.createCompoundBorder(BorderFactory
.createEmptyBorder(5, 5, 12, 5), BorderFactory.createMatteBorder(0, 0, 1, 0, UIManager
.getColor("textText"))));
.createEmptyBorder(5, 5, 12, 5), BorderFactory.createMatteBorder(0, 0, 1, 0, UIManager
.getColor("textText"))));
ttlPanel = new JPanel() {
@Override
public void doLayout() {
Dimension d = ttlLabel.getPreferredSize();
if (ttlLabel.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT)
@@ -133,6 +133,7 @@ public class WizardDisplayerImpl extends WizardDisplayer {
ttlLabel.setBounds(0, 0, getWidth(), d.height);
}
@Override
public Dimension getPreferredSize() {
return ttlLabel.getPreferredSize();
}
@@ -151,9 +152,8 @@ public class WizardDisplayerImpl extends WizardDisplayer {
/**
* Show a wizard
*
* @param awizard is the wizard to be displayed
* @param bounds for display, may be null for default of
* 0,0,400,600.
* @param awizard is the wizard to be displayed
* @param bounds for display, may be null for default of 0,0,400,600.
* @param helpAction
* @param initialProperties - initial values for the map
*
@@ -164,7 +164,7 @@ public class WizardDisplayerImpl extends WizardDisplayer {
* java.awt.Rectangle, javax.swing.Action, java.util.Map)
*/
private JPanel createOuterPanel(final Wizard awizard, Rectangle bounds, Action helpAction,
Map initialProperties) {
Map initialProperties) {
this.wizard = awizard;
@@ -181,6 +181,7 @@ public class WizardDisplayerImpl extends WizardDisplayer {
outerPanel.setLayout(new BorderLayout());
Action kbdCancel = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
JButton b = buttonManager.getCancel();
if (b.isEnabled())
@@ -188,7 +189,7 @@ public class WizardDisplayerImpl extends WizardDisplayer {
}
};
outerPanel.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
outerPanel.getActionMap().put("cancel", kbdCancel);
instructions = createInstructionsPanel();
@@ -232,8 +233,9 @@ public class WizardDisplayerImpl extends WizardDisplayer {
return new InstructionsPanelImpl(wizard);
}
@Override
public void install(Container c, Object layoutConstraint, Wizard awizard,
Action helpAction, Map initialProperties, WizardResultReceiver receiver) {
Action helpAction, Map initialProperties, WizardResultReceiver receiver) {
JPanel pnl = createOuterPanel(awizard, new Rectangle(), helpAction, initialProperties);
if (layoutConstraint != null)
if (c instanceof RootPaneContainer)
@@ -249,12 +251,13 @@ public class WizardDisplayerImpl extends WizardDisplayer {
private static boolean warned;
@Override
public Object show(final Wizard awizard, Rectangle bounds, Action helpAction,
Map initialProperties) {
Map initialProperties) {
if (!EventQueue.isDispatchThread() && !warned) {
HMCLog.warn("WizardDisplayerImpl: show() should be called from the AWT Event Thread. This "
+ "call may deadlock - c.f. "
+ "http://java.net/jira/browse/WIZARD-33", new Throwable());
+ "call may deadlock - c.f. "
+ "http://java.net/jira/browse/WIZARD-33", new Throwable());
warned = true;
}
createOuterPanel(awizard, bounds, helpAction, initialProperties);
@@ -291,25 +294,26 @@ public class WizardDisplayerImpl extends WizardDisplayer {
dlg.pack();
dlg.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
dlg.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
if (!(e.getWindow() instanceof JDialog))
return;
JDialog dlg = (JDialog) e.getWindow();
boolean dontClose = false;
if (!wizard.isBusy()) {
DeferredWizardResult defResult;
synchronized (WizardDisplayerImpl.this) {
defResult = deferredResult;
}
try {
if (defResult != null && defResult.canAbort())
defResult.abort();
else if (defResult != null && !defResult.canAbort())
dontClose = true;
} finally {
if (!dontClose && wizard.cancel(settings)) {
dlg.setVisible(false);
dlg.dispose();
if (e.getWindow() instanceof JDialog) {
JDialog dlg = (JDialog) e.getWindow();
boolean dontClose = false;
if (!wizard.isBusy()) {
DeferredWizardResult defResult;
synchronized (WizardDisplayerImpl.this) {
defResult = deferredResult;
}
try {
if (defResult != null && defResult.canAbort())
defResult.abort();
else if (defResult != null && !defResult.canAbort())
dontClose = true;
} finally {
if (!dontClose && wizard.cancel(settings)) {
dlg.setVisible(false);
dlg.dispose();
}
}
}
}
@@ -355,13 +359,13 @@ public class WizardDisplayerImpl extends WizardDisplayer {
// available in the package only
static void checkLegalNavMode(int i) {
switch (i) {
case Wizard.MODE_CAN_CONTINUE:
case Wizard.MODE_CAN_CONTINUE_OR_FINISH:
case Wizard.MODE_CAN_FINISH:
return;
default:
throw new IllegalArgumentException("Illegal forward "
+ "navigation mode: " + i);
case Wizard.MODE_CAN_CONTINUE:
case Wizard.MODE_CAN_CONTINUE_OR_FINISH:
case Wizard.MODE_CAN_FINISH:
return;
default:
throw new IllegalArgumentException("Illegal forward "
+ "navigation mode: " + i);
}
}
@@ -399,7 +403,7 @@ public class WizardDisplayerImpl extends WizardDisplayer {
JComponent summaryComp = (JComponent) summary.getSummaryComponent(); // XXX
if (summaryComp.getBorder() != null) {
CompoundBorder b = new CompoundBorder(new EmptyBorder(5, 5, 5, 5), summaryComp
.getBorder());
.getBorder());
summaryComp.setBorder(b);
}
setCurrentWizardPanel((JComponent) summaryComp); // XXX
@@ -426,6 +430,7 @@ public class WizardDisplayerImpl extends WizardDisplayer {
((JComponent) inst).revalidate();
inst.repaint();
Runnable run = new Runnable() {
@Override
public void run() {
if (!EventQueue.isDispatchThread())
try {
@@ -433,7 +438,7 @@ public class WizardDisplayerImpl extends WizardDisplayer {
r.start(settings, progress);
if (progress.isRunning())
progress.failed("Start method did not inidicate "
+ "failure or finished in " + r, false);
+ "failure or finished in " + r, false);
} finally {
try {
@@ -538,8 +543,8 @@ public class WizardDisplayerImpl extends WizardDisplayer {
/**
* Will only be called if there is a WizardResultReceiver - i.e. if the
* wizard is being displayed in some kind of custom container. Return
* true to indicate we should not try to close the parent window.
* wizard is being displayed in some kind of custom container. Return true
* to indicate we should not try to close the parent window.
*/
boolean cancel() {
boolean result = receiver != null;
@@ -556,10 +561,10 @@ public class WizardDisplayerImpl extends WizardDisplayer {
// showing the error line
prob = null;
Border b = prob == null ? BorderFactory.createEmptyBorder(1, 0, 0, 0) : BorderFactory
.createMatteBorder(1, 0, 0, 0, problem.getForeground());
.createMatteBorder(1, 0, 0, 0, problem.getForeground());
Border b1 = BorderFactory.createCompoundBorder(BorderFactory
.createEmptyBorder(0, 12, 0, 12), b);
.createEmptyBorder(0, 12, 0, 12), b);
problem.setBorder(b1);
}

View File

@@ -50,15 +50,15 @@ import org.jackhuang.hellominecraft.util.ui.wizard.spi.Wizard;
import org.jackhuang.hellominecraft.util.ui.wizard.spi.WizardObserver;
/**
* A panel that displays a background image and optionally instructions
* from a wizard, tracking the selected panel and showing that in bold.
* <p/>
* A panel that displays a background image and optionally instructions from a
* wizard, tracking the selected panel and showing that in bold.
* <br>
* <b><i><font color="red">This class is NOT AN API CLASS. There is no
* commitment that it will remain backward compatible or even exist in the
* future. The API of this library is in the packages
* <code>org.netbeans.api.wizard</code>
* and <code>org.netbeans.spi.wizard</code></font></i></b>.
* <p/>
* <code>org.netbeans.api.wizard</code> and
* <code>org.netbeans.spi.wizard</code></font></i></b>.
* <br>
* There is currently a single use-case for subclassing this - a navigation
* panel that wants to display a different image for each step.
*
@@ -66,8 +66,8 @@ import org.jackhuang.hellominecraft.util.ui.wizard.spi.WizardObserver;
*/
public class InstructionsPanelImpl extends JComponent implements WizardObserver, Accessible, InstructionsPanel {
private final BufferedImage img;
private final Wizard wizard;
private transient final BufferedImage img;
private transient final Wizard wizard;
private static final int MARGIN = 5;
public InstructionsPanelImpl(Wizard wiz) {
@@ -86,6 +86,7 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
return wizard;
}
@Override
public final Container getComponent() {
return this;
}
@@ -93,6 +94,7 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
/**
* Overridden to start listening to the wizard when added to a container
*/
@Override
public void addNotify() {
super.addNotify();
wizard.addWizardObserver(this);
@@ -101,16 +103,16 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
/**
* Overridden to stop listening to the wizard when removed from a container
*/
@Override
public void removeNotify() {
wizard.removeWizardObserver(this);
super.removeNotify();
}
/**
* Get the image to be displayed. Note that unpredictable behavior
* may result if all images returned from this method are not the
* same size. Override to display a different wizard depending on the
* step.
* Get the image to be displayed. Note that unpredictable behavior may
* result if all images returned from this method are not the same size.
* Override to display a different wizard depending on the step.
*
* @return
*/
@@ -122,7 +124,7 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
if (img == null)
try {
img = ImageIO.read(InstructionsPanelImpl.class.getResourceAsStream(
"/org/jackhuang/hellominecraft/wizard.jpg"));
"/org/jackhuang/hellominecraft/wizard.jpg"));
} catch (IOException ioe) {
HMCLog.err("Failed to load wizard.jpg, maybe you fucking modified the launcher", ioe);
}
@@ -130,13 +132,14 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
this.wizard = wizard;
}
@Override
public boolean isOpaque() {
return img != null;
}
/**
* Paints the background image for this component, or fills the
* background with a color if no image present.
* Paints the background image for this component, or fills the background
* with a color if no image present.
*
* @param g A Graphic2D to paint into
* @param x The x coordinate of the area that should contain the image
@@ -158,6 +161,7 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
String[] steps = new String[0];
@Override
public final void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
@@ -193,10 +197,10 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
int underlineY = ins.top + MARGIN + fm.getAscent() + 3;
g.drawLine(x, underlineY, x + (getWidth() - (x + ins.left + MARGIN)),
underlineY);
underlineY);
int bottom = getComponentCount() == 0 ? getHeight() - getInsets().bottom
: getHeight() - getInsets().bottom - getComponents()[0].getPreferredSize().height;
: getHeight() - getInsets().bottom - getComponents()[0].getPreferredSize().height;
y += h + 10;
int first = 0;
@@ -231,7 +235,7 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
for (int i = first; i < stop; i++) {
boolean isUndetermined = Wizard.UNDETERMINED_STEP.equals(steps2[i]);
boolean canOnlyFinish = wizard.getForwardNavigationMode()
== Wizard.MODE_CAN_FINISH;
== Wizard.MODE_CAN_FINISH;
if (isUndetermined && canOnlyFinish)
break;
String curr;
@@ -240,36 +244,35 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
curr = (i + 1) + ". " + steps2[i];
else
curr = (i + 1) + ". " + (isUndetermined
? elipsis
: steps2[i].equals(elipsis) ? elipsis
: wizard.getStepDescription(steps2[i]));
? elipsis
: steps2[i].equals(elipsis) ? elipsis
: wizard.getStepDescription(steps2[i]));
else
curr = elipsis;
if (curr != null) {
boolean selected = (steps2[i].equals(currentStep) && !inSummaryPage)
|| (inSummaryPage && i == steps2.length - 1);
if (selected)
g.setFont(boldFont);
boolean selected = (steps2[i].equals(currentStep) && !inSummaryPage)
|| (inSummaryPage && i == steps2.length - 1);
if (selected)
g.setFont(boldFont);
int width = fm.stringWidth(curr);
while (width > getWidth() - (ins.left + ins.right) && curr.length() > 5)
curr = curr.substring(0, curr.length() - 5) + elipsis;
int width = fm.stringWidth(curr);
while (width > getWidth() - (ins.left + ins.right) && curr.length() > 5)
curr = curr.substring(0, curr.length() - 5) + elipsis;
g.drawString(curr, x, y);
if (selected)
g.setFont(f);
y += h;
}
g.drawString(curr, x, y);
if (selected)
g.setFont(f);
y += h;
}
}
private int historicWidth = Integer.MIN_VALUE;
String elipsis = "...";
private static final String elipsis = "...";
@Override
public final Dimension getPreferredSize() {
Font f = getFont() != null ? getFont()
: UIManager.getFont("controlFont");
: UIManager.getFont("controlFont");
Graphics g = getGraphics();
if (g == null)
@@ -283,10 +286,9 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
int w = Integer.MIN_VALUE;
for (int i = 0; i < steps2.length; i++) {
String desc = i + ". " + (Wizard.UNDETERMINED_STEP.equals(steps2[i])
? elipsis
: wizard.getStepDescription(steps2[i]));
if (desc != null)
w = Math.max(w, fm.stringWidth(desc) + MARGIN);
? elipsis
: wizard.getStepDescription(steps2[i]));
w = Math.max(w, fm.stringWidth(desc) + MARGIN);
}
if (Integer.MIN_VALUE == w)
w = 250;
@@ -301,27 +303,33 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
private boolean inSummaryPage;
@Override
public void setInSummaryPage(boolean val) {
this.inSummaryPage = val;
repaint();
}
@Override
public final Dimension getMinimumSize() {
return getPreferredSize();
}
@Override
public void stepsChanged(Wizard wizard) {
repaint();
}
@Override
public void navigabilityChanged(Wizard wizard) {
//do nothing
}
@Override
public void selectionChanged(Wizard wizard) {
repaint();
}
@Override
public final void doLayout() {
Component[] c = getComponents();
Insets ins = getInsets();
@@ -337,6 +345,7 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
}
}
@Override
public final AccessibleContext getAccessibleContext() {
return new ACI(this);
}
@@ -355,6 +364,7 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
JEditorPane pane;
@Override
public AccessibleText getAccessibleText() {
if (pane == null) {
//Cheat just a bit here - will do for now - the text is
@@ -382,31 +392,37 @@ public class InstructionsPanelImpl extends JComponent implements WizardObserver,
return sb.toString();
}
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.LIST;
}
@Override
public AccessibleStateSet getAccessibleStateSet() {
AccessibleState[] states = new AccessibleState[] {
AccessibleState[] states = new AccessibleState[]{
AccessibleState.VISIBLE,
AccessibleState.OPAQUE,
AccessibleState.SHOWING,
AccessibleState.MULTI_LINE, };
AccessibleState.MULTI_LINE,};
return new AccessibleStateSet(states);
}
@Override
public int getAccessibleIndexInParent() {
return -1;
}
@Override
public int getAccessibleChildrenCount() {
return 0;
}
@Override
public Accessible getAccessibleChild(int i) {
throw new IndexOutOfBoundsException("" + i);
}
@Override
public Locale getLocale() throws IllegalComponentStateException {
return Locale.getDefault();
}

View File

@@ -124,7 +124,6 @@ public class MergeMap implements Map {
//we're removing, and if any of them are in steps lower on the
//stack, change those lower steps values to whatever was written
//into the map we're calving off
Set keysForCurr = curr.keySet();
for (Iterator i = orderIterator(); i.hasNext();) {
Map other = (Map) id2map.get(i.next());
for (Iterator j = curr.keySet().iterator(); j.hasNext();) {
@@ -136,10 +135,12 @@ public class MergeMap implements Map {
return result;
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean containsKey(Object obj) {
for (Iterator i = orderIterator(); i.hasNext();) {
Map curr = (Map) id2map.get(i.next());
@@ -149,6 +150,7 @@ public class MergeMap implements Map {
return false;
}
@Override
public boolean containsValue(Object obj) {
for (Iterator i = orderIterator(); i.hasNext();) {
Map curr = (Map) id2map.get(i.next());
@@ -158,6 +160,7 @@ public class MergeMap implements Map {
return false;
}
@Override
public java.util.Set entrySet() {
HashSet result = new HashSet();
for (Iterator i = orderIterator(); i.hasNext();) {
@@ -167,6 +170,7 @@ public class MergeMap implements Map {
return result;
}
@Override
public Object get(Object obj) {
for (Iterator i = orderIterator(); i.hasNext();) {
String id = (String) i.next();
@@ -178,10 +182,12 @@ public class MergeMap implements Map {
return null;
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public Set keySet() {
HashSet result = new HashSet();
for (Iterator i = orderIterator(); i.hasNext();) {
@@ -191,11 +197,13 @@ public class MergeMap implements Map {
return result;
}
@Override
public Object put(Object obj, Object obj1) {
Map curr = (Map) id2map.get(order.peek());
return curr.put(obj, obj1);
}
@Override
public void putAll(Map map) {
Map curr = (Map) id2map.get(order.peek());
curr.putAll(map);
@@ -214,6 +222,7 @@ public class MergeMap implements Map {
return result;
}
@Override
public Object remove(Object obj) {
//Ensure we remove any duplicates in upper arrays
Object result = get(obj);
@@ -222,11 +231,13 @@ public class MergeMap implements Map {
return result;
}
@Override
public int size() {
//using keySet() prunes duplicates
return keySet().size();
}
@Override
public Collection values() {
HashSet result = new HashSet();
Set keys = keySet();

View File

@@ -18,28 +18,22 @@ package org.jackhuang.hellominecraft.util.ui.wizard.spi;
import javax.swing.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* A Wizard with indeterminate branches. The actual branch decision-making
* is done by the WizardBranchController passed to the constructor.
* A Wizard with indeterminate branches. The actual branch decision-making is
* done by the WizardBranchController passed to the constructor.
* <p/>
* Wizards with arbitrary numbers of branches can be handled by a
* WizardBranchController by returning wizards created by
* another WizardBranchController's <code>createWizard()</code> method.
* WizardBranchController by returning wizards created by another
* WizardBranchController's <code>createWizard()</code> method.
* <p/>
* One important point: There should be no duplicate IDs between steps of
* this wizard.
* One important point: There should be no duplicate IDs between steps of this
* wizard.
*
* @author Tim Boudreau
*/
final class BranchingWizard implements WizardImplementation {
private final List listenerList = Collections.synchronizedList(
new LinkedList());
final class BranchingWizard extends AbstractWizard {
private final WizardBranchController brancher;
final WizardImplementation initialSteps;
@@ -89,8 +83,8 @@ final class BranchingWizard implements WizardImplementation {
private void setSecondary(WizardImplementation newSecondary) {
/* johnflournoy added additional condition: secondary != this */
if ((((subsequentSteps == null) != (newSecondary == null))
|| (subsequentSteps != null && !subsequentSteps.equals(newSecondary)))
&& !this.equals(newSecondary))
|| (subsequentSteps != null && !subsequentSteps.equals(newSecondary)))
&& !this.equals(newSecondary))
/*
* johnflournoy: only set the subsequent steps if it
@@ -102,6 +96,7 @@ final class BranchingWizard implements WizardImplementation {
}
}
@Override
public int getForwardNavigationMode() {
return activeWizard.getForwardNavigationMode();
}
@@ -124,10 +119,12 @@ final class BranchingWizard implements WizardImplementation {
activeWizard.addWizardObserver(wl);
}
@Override
public final boolean isBusy() {
return activeWizard.isBusy();
}
@Override
public final Object finish(Map settings) throws WizardException {
try {
Object result = activeWizard.finish(settings);
@@ -147,6 +144,7 @@ final class BranchingWizard implements WizardImplementation {
}
}
@Override
public final String[] getAllSteps() {
String[] result;
if (subsequentSteps == null) {
@@ -164,10 +162,12 @@ final class BranchingWizard implements WizardImplementation {
return result;
}
@Override
public String getCurrentStep() {
return currStep;
}
@Override
public final String getNextStep() {
String result;
if (currStep == null)
@@ -177,8 +177,8 @@ final class BranchingWizard implements WizardImplementation {
int idx = Arrays.asList(steps).indexOf(currStep);
if (idx == -1)
throw new IllegalStateException("Current step not in"
+ " available steps: " + currStep + " not in "
+ Arrays.asList(steps));
+ " available steps: " + currStep + " not in "
+ Arrays.asList(steps));
else if (idx == steps.length - 1)
if (subsequentSteps == null)
result = UNDETERMINED_STEP;
@@ -199,6 +199,7 @@ final class BranchingWizard implements WizardImplementation {
return getProblem() == null ? result : UNDETERMINED_STEP.equals(result) ? result : null;
}
@Override
public final String getPreviousStep() {
if (activeWizard == subsequentSteps && subsequentSteps.getAllSteps()[0].equals(currStep))
return initialSteps.getAllSteps()[initialSteps.getAllSteps().length - 1];
@@ -206,10 +207,12 @@ final class BranchingWizard implements WizardImplementation {
return activeWizard.getPreviousStep();
}
@Override
public final String getProblem() {
return activeWizard.getProblem();
}
@Override
public final String getStepDescription(String id) {
WizardImplementation w = ownerOf(id);
if (w == null)
@@ -217,6 +220,7 @@ final class BranchingWizard implements WizardImplementation {
return w.getStepDescription(id);
}
@Override
public final String getLongDescription(String id) {
WizardImplementation w = ownerOf(id);
if (w == null)
@@ -249,10 +253,12 @@ final class BranchingWizard implements WizardImplementation {
}
}
@Override
public final String getTitle() {
return activeWizard.getTitle();
}
@Override
public final JComponent navigatingTo(String id, Map settings) {
if (id == null)
throw new NullPointerException();
@@ -262,63 +268,53 @@ final class BranchingWizard implements WizardImplementation {
WizardImplementation impl = ownerOf(id);
if (impl == null)
throw new NullPointerException("No owning WizardImplementation for"
+ " id " + id);
+ " id " + id);
setCurrent(impl);
return activeWizard.navigatingTo(id, settings);
}
@Override
public final void removeWizardObserver(WizardObserver observer) {
listenerList.remove(observer);
}
@Override
public final void addWizardObserver(WizardObserver observer) {
listenerList.add(observer);
}
private void fireStepsChanged() {
WizardObserver[] listeners = (WizardObserver[]) listenerList.toArray(new WizardObserver[0]);
for (int i = listeners.length - 1; i >= 0; i--) {
WizardObserver l = (WizardObserver) listeners[i];
l.stepsChanged(null);
}
fireChanged(l -> l.stepsChanged(null));
}
private void fireNavigabilityChanged() {
checkForSecondary();
WizardObserver[] listeners = (WizardObserver[]) listenerList.toArray(new WizardObserver[0]);
for (int i = listeners.length - 1; i >= 0; i--) {
WizardObserver l = (WizardObserver) listeners[i];
l.navigabilityChanged(null);
}
fireChanged(l -> l.navigabilityChanged(null));
}
private void fireSelectionChanged() {
WizardObserver[] listeners = (WizardObserver[]) listenerList.toArray(new WizardObserver[0]);
for (int i = listeners.length - 1; i >= 0; i--) {
WizardObserver l = (WizardObserver) listeners[i];
l.selectionChanged(null);
}
fireChanged(l -> l.selectionChanged(null));
}
@Override
public boolean cancel(Map settings) {
return activeWizard == null ? true : activeWizard.cancel(settings);
}
private class WL implements WizardObserver {
@Override
public void stepsChanged(Wizard wizard) {
fireStepsChanged();
}
@Override
public void navigabilityChanged(Wizard wizard) {
fireNavigabilityChanged();
}
@Override
public void selectionChanged(Wizard wizard) {
fireSelectionChanged();
}

View File

@@ -18,10 +18,7 @@
package org.jackhuang.hellominecraft.util.ui.wizard.spi;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.swing.JComponent;
@@ -33,10 +30,8 @@ import javax.swing.JComponent;
* @see SimpleWizardInfo
* @author Tim Boudreau
*/
final class SimpleWizard implements WizardImplementation {
final class SimpleWizard extends AbstractWizard {
private final List listenerList
= Collections.synchronizedList(new LinkedList());
private final Map ids2panels = new HashMap();
final SimpleWizardInfo info;
@@ -65,14 +60,17 @@ final class SimpleWizard implements WizardImplementation {
info.setWizard(this);
}
@Override
public void addWizardObserver(WizardObserver observer) {
listenerList.add(observer);
}
@Override
public void removeWizardObserver(WizardObserver observer) {
listenerList.remove(observer);
}
@Override
public int getForwardNavigationMode() {
int result = info.getFwdNavMode();
if (!subwizard && ((result & WizardController.MODE_CAN_CONTINUE) != 0) && isLastStep())
@@ -85,6 +83,7 @@ final class SimpleWizard implements WizardImplementation {
return currID != null && steps.length > 0 && currID.equals(steps[steps.length - 1]);
}
@Override
public String[] getAllSteps() {
String[] allSteps = info.getSteps();
String[] result = new String[allSteps.length];
@@ -93,6 +92,7 @@ final class SimpleWizard implements WizardImplementation {
return result;
}
@Override
public String getStepDescription(String id) {
int idx = Arrays.asList(info.getSteps()).indexOf(id);
if (idx == -1)
@@ -100,10 +100,12 @@ final class SimpleWizard implements WizardImplementation {
return info.getDescriptions()[idx];
}
@Override
public String getLongDescription(String id) {
return info.getLongDescription(id);
}
@Override
public JComponent navigatingTo(String id, Map settings) {
// assert SwingUtilities.isEventDispatchThread();
@@ -121,10 +123,12 @@ final class SimpleWizard implements WizardImplementation {
return result;
}
@Override
public String getCurrentStep() {
return currID;
}
@Override
public String getNextStep() {
if (!info.isValid())
return null;
@@ -138,6 +142,7 @@ final class SimpleWizard implements WizardImplementation {
return null;
}
@Override
public String getPreviousStep() {
int idx = currentStepIndex();
if (idx < info.getSteps().length && idx > 0)
@@ -154,47 +159,44 @@ final class SimpleWizard implements WizardImplementation {
}
void fireNavigability() {
WizardObserver[] listeners = (WizardObserver[]) listenerList.toArray(new WizardObserver[0]);
for (int i = listeners.length - 1; i >= 0; i--) {
WizardObserver l = (WizardObserver) listeners[i];
l.navigabilityChanged(null);
}
fireChanged(l -> l.navigabilityChanged(null));
}
private void fireSelectionChanged() {
WizardObserver[] listeners = (WizardObserver[]) listenerList.toArray(new WizardObserver[0]);
for (int i = listeners.length - 1; i >= 0; i--) {
WizardObserver l = (WizardObserver) listeners[i];
l.selectionChanged(null);
}
fireChanged(l -> l.selectionChanged(null));
}
@Override
public Object finish(Map settings) throws WizardException {
return info.finish(settings);
}
@Override
public boolean cancel(Map settings) {
return info.cancel(settings);
}
@Override
public String getTitle() {
return info.getTitle();
}
@Override
public String getProblem() {
return info.getProblem();
}
@Override
public boolean isBusy() {
return info.isBusy();
}
@Override
public int hashCode() {
return info.hashCode() ^ 17;
}
@Override
public boolean equals(Object o) {
if (o instanceof SimpleWizard)
return ((SimpleWizard) o).info.equals(info);
@@ -202,6 +204,7 @@ final class SimpleWizard implements WizardImplementation {
return false;
}
@Override
public String toString() {
return "SimpleWizard for " + info;
}

View File

@@ -29,6 +29,8 @@ import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import org.jackhuang.hellominecraft.util.code.Charsets;
import org.jackhuang.hellominecraft.util.system.IOUtils;
/**
* Provides information about a simple wizard. Wraps a
@@ -117,9 +119,9 @@ public final class SimpleWizardInfo implements WizardControllerImplementation {
JTextArea jta = new JTextArea();
jta.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.RED));
ByteArrayOutputStream buf = new ByteArrayOutputStream();
PrintStream str = new PrintStream(buf);
PrintStream str = IOUtils.createPrintStream(buf, Charsets.UTF_8);
re.printStackTrace(str);
jta.setText(new String(buf.toByteArray()));
jta.setText(new String(buf.toByteArray(), Charsets.UTF_8));
setProblem(re.getLocalizedMessage());
return new JScrollPane(jta);
}
@@ -176,6 +178,7 @@ public final class SimpleWizardInfo implements WizardControllerImplementation {
return a == null ? 0 : a.currentStepIndex();
}
@Override
public final void setBusy(boolean value) {
if (value != busy) {
busy = value;
@@ -188,6 +191,7 @@ public final class SimpleWizardInfo implements WizardControllerImplementation {
* user-entered information in a panel changes, call this method as
* appropriate.
*/
@Override
public final void setProblem(String value) {
this.problem = value;
int idx = index();
@@ -215,6 +219,7 @@ public final class SimpleWizardInfo implements WizardControllerImplementation {
*
* @see setProblem
*/
@Override
public final void setForwardNavigationMode(int value) {
switch (value) {
case WizardController.MODE_CAN_CONTINUE:
@@ -292,6 +297,7 @@ public final class SimpleWizardInfo implements WizardControllerImplementation {
return busy;
}
@Override
public boolean equals(Object o) {
if (o != null && o.getClass() == getClass()) {
SimpleWizardInfo info = (SimpleWizardInfo) o;
@@ -308,6 +314,7 @@ public final class SimpleWizardInfo implements WizardControllerImplementation {
return false;
}
@Override
public int hashCode() {
int result = 0;
for (int i = 0; i < steps.length; i++)

View File

@@ -7,6 +7,8 @@ package org.jackhuang.hellominecraft.util.ui.wizard.spi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashSet;
import java.util.Set;
@@ -30,7 +32,7 @@ final class Util {
result[i] = pages[i].id();
if (result[i] == null || uniqueNames.contains(result[i])) {
result[i] = uniquify(getIDFromStaticMethod(pages[i].getClass()),
uniqueNames);
uniqueNames);
pages[i].id = result[i];
}
uniqueNames.add(result[i]);
@@ -67,12 +69,12 @@ final class Util {
// System.err.println("GetID by method for " + clazz);
String result = null;
try {
Method m = clazz.getDeclaredMethod("getStep", new Class[] {});
Method m = clazz.getDeclaredMethod("getStep", new Class[]{});
// assert m.getReturnType() == String.class;
result = (String) m.invoke(clazz, (Object[]) null);
if (result == null)
throw new NullPointerException("getStep may not return null");
} catch (Exception ex) {
} catch (IllegalAccessException | IllegalArgumentException | NoSuchMethodException | NullPointerException | SecurityException | InvocationTargetException ex) {
//do nothing
}
return result == null ? clazz.getName() : result;
@@ -92,11 +94,11 @@ final class Util {
for (int i = 0; i < pages.length; i++) {
if (pages[i] == null)
throw new NullPointerException("Null at " + i + " in array "
+ "of panel classes");
+ "of panel classes");
if (!WizardPage.class.isAssignableFrom(pages[i]))
throw new IllegalArgumentException(pages[i]
+ " is not a subclass of WizardPage");
+ " is not a subclass of WizardPage");
result[i] = uniquify(getIDFromStaticMethod(pages[i]), used);
if (result[i] == null)
result[i] = pages[i].getName();
@@ -128,33 +130,33 @@ final class Util {
}
static String getDescriptionFromStaticMethod(Class clazz) {
String result = null;
Method m;
try {
m = clazz.getDeclaredMethod("getDescription", (Class[]) null);
} catch (Exception e) {
} catch (NoSuchMethodException | SecurityException e) {
throw new IllegalArgumentException("Could not find or access "
+ "public static String " + clazz.getName()
+ ".getDescription() - make sure it exists");
+ "public static String " + clazz.getName()
+ ".getDescription() - make sure it exists");
}
if (m.getReturnType() != String.class)
throw new IllegalArgumentException("getStep has wrong "
+ " return type: " + m.getReturnType() + " on "
+ clazz);
+ " return type: " + m.getReturnType() + " on "
+ clazz);
if (!Modifier.isStatic(m.getModifiers()))
throw new IllegalArgumentException("getStep is not "
+ "static on " + clazz);
+ "static on " + clazz);
try {
m.setAccessible(true);
result = (String) m.invoke(null, (Object[]) null);
} catch (InvocationTargetException | IllegalAccessException ite) {
throw new IllegalArgumentException("Could not invoke "
+ "public static String " + clazz.getName()
+ ".getDescription() - make sure it exists.", ite);
}
return result;
return AccessController.doPrivileged((PrivilegedAction<String>) () -> {
try {
m.setAccessible(true);
return (String) m.invoke(null, (Object[]) null);
} catch (InvocationTargetException | IllegalAccessException ite) {
throw new IllegalArgumentException("Could not invoke "
+ "public static String " + clazz.getName()
+ ".getDescription() - make sure it exists.", ite);
}
});
}
}

View File

@@ -33,14 +33,13 @@ import java.util.Map;
* <p/>
* <b>Automatic listening to child components</b><br>
* If you add an editable component (all standard Swing controls are supported)
* to a WizardPage or a child JPanel inside it,
* a listener is automatically attached to it. If user input occurs, the
* following things happen, in order:
* to a WizardPage or a child JPanel inside it, a listener is automatically
* attached to it. If user input occurs, the following things happen, in order:
* <ul>
* <li>If the <code>name</code> property of the component has been set, then
* the value from the component (i.e. Boolean for checkboxes, selected item(s)
* for lists/combo boxes/trees, etc.) will automatically be added to the
* wizard settings map, with the component name as the key.</li>
* <li>If the <code>name</code> property of the component has been set, then the
* value from the component (i.e. Boolean for checkboxes, selected item(s) for
* lists/combo boxes/trees, etc.) will automatically be added to the wizard
* settings map, with the component name as the key.</li>
* <li>Regardless of whether the <code>name</code> property is set,
* <code>validateContents()</code> will be called. You can override that method
* to enable/disable the finish button, call <code>setProblem()</code> to
@@ -51,21 +50,21 @@ import java.util.Map;
* appropriate constructor. In that case, <code>validateContents</code> will
* never be called automatically.
* <p/>
* If you have custom components that WizardPage will not know how to listen
* to automatically, attach an appropriate listener to them and optionally
* call <code>userInputReceived()</code> with the component and the event if
* you want to run your automatic validation code.
* If you have custom components that WizardPage will not know how to listen to
* automatically, attach an appropriate listener to them and optionally call
* <code>userInputReceived()</code> with the component and the event if you want
* to run your automatic validation code.
* <p/>
* For convenience, this class implements the relevant methods for accessing
* the <code>WizardController</code> and the settings map for the wizard that
* the panel is a part of.
* For convenience, this class implements the relevant methods for accessing the
* <code>WizardController</code> and the settings map for the wizard that the
* panel is a part of.
* <p/>
* Instances of WizardPage can be returned from a WizardPanelProvider; this
* class also offers two methods for conveniently assembling a wizard:
* <ul>
* <li>Pass an array of already instantiated WizardPages to
* <code>createWizard()</code>. Note that for large wizards, it is preferable
* to construct the panels on demand rather than at construction time.</li>
* <code>createWizard()</code>. Note that for large wizards, it is preferable to
* construct the panels on demand rather than at construction time.</li>
* <li>Construct a wizard out of WizardPages, instantiating the panels as
* needed: Pass an array of classes all of which
* <ul>
@@ -80,20 +79,19 @@ import java.util.Map;
* <p/>
* Note that during development of a wizard, it is worthwhile to test/run with
* assertions enabled, as there is quite a bit of validity checking via
* assertions
* that can help find problems early.
* assertions that can help find problems early.
* <h2>Using Custom Components</h2>
* If the <code>autoListen</code> constructor argument is true, a WizardPage
* will automatically listen to components which have a name, if they are
* standard Swing components it knows how to listen to. If you are using
* custom components, implement WizardPage.CustomComponentListener and return
* it from <code>createCustomComponentListener()</code> to add supplementary
* listening code for custom components.
* standard Swing components it knows how to listen to. If you are using custom
* components, implement WizardPage.CustomComponentListener and return it from
* <code>createCustomComponentListener()</code> to add supplementary listening
* code for custom components.
* <p/>
* Note: Swing components do not fire property changes when setName() is called.
* If your component's values are not being propagated into the settings map,
* make sure you are calling setName() <i>before</i> adding the component
* to the hierarchy.
* make sure you are calling setName() <i>before</i> adding the component to the
* hierarchy.
* <p/>
* Also note that cell editors in tables and lists and so forth are always
* ignored by the automatic listening code.
@@ -127,23 +125,23 @@ public class WizardPage extends JPanel implements WizardPanel {
* behavior.
*
* @param stepDescription the localized description of this step
* @param autoListen if true, components added will automatically be
* listened to for user input
* @param autoListen if true, components added will automatically be
* listened to for user input
*/
public WizardPage(String stepDescription, boolean autoListen) {
this(null, stepDescription, autoListen);
}
/**
* Construct a new WizardPage with the passed step id and description.
* Use this constructor for WizardPages which will be constructed ahead
* of time and passed in an array to <code>createWizard</code>.
* Construct a new WizardPage with the passed step id and description. Use
* this constructor for WizardPages which will be constructed ahead of time
* and passed in an array to <code>createWizard</code>.
*
* @param stepId the unique ID for the step represented. If null,
* the class name or a variant of it will be used
* @param stepId the unique ID for the step represented. If null, the class
* name or a variant of it will be used
* @param stepDescription the localized description of this step
* @param autoListen if true, components added will automatically be
* listened to for user input
* @param autoListen if true, components added will automatically be
* listened to for user input
*
* @see #validateContents
*/
@@ -161,12 +159,12 @@ public class WizardPage extends JPanel implements WizardPanel {
if (autoListen) {
//It will attach itself
GenericListener gl = new GenericListener(this, ccl = createCustomComponentListener(),
ccl == null ? null : new CustomComponentNotifierImpl(this));
ccl == null ? null : new CustomComponentNotifierImpl(this));
gl.attachToHierarchyOf(this);
} else if ((ccl = createCustomComponentListener()) != null)
throw new IllegalStateException("CustomComponentListener "
+ "will never be called if the autoListen parameter is "
+ "false");
+ "will never be called if the autoListen parameter is "
+ "false");
// if (getClass() == WizardPage.class && stepId == null ||
// description == null) {
// throw new NullPointerException ("Step or ID is null");
@@ -186,8 +184,8 @@ public class WizardPage extends JPanel implements WizardPanel {
/**
* Create an auto-listening WizardPage with the passed description
*
* @param stepId The unique id for the step. If null, an id will be
* generated
* @param stepId The unique id for the step. If null, an id will be
* generated
* @param stepDescription the localized description of this step
*
*/
@@ -196,8 +194,8 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* Use this constructor or the default constructor if you intend to
* pass an array of Class objects to lazily create WizardPanels.
* Use this constructor or the default constructor if you intend to pass an
* array of Class objects to lazily create WizardPanels.
*/
protected WizardPage(boolean autoListen) {
this(null, null, autoListen);
@@ -211,10 +209,9 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* If you are using custom Swing or AWT components which the
* WizardPage will not know how to automatically listen to, you
* may want to override this method, implement CustomComponentListener
* and return an instance of it.
* If you are using custom Swing or AWT components which the WizardPage will
* not know how to automatically listen to, you may want to override this
* method, implement CustomComponentListener and return an instance of it.
*
* @return A CustomComponentListener implementation, or null (the default).
*/
@@ -223,8 +220,8 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* Implement this class if you are using custom Swing or AWT components,
* and return an instance of it from
* Implement this class if you are using custom Swing or AWT components, and
* return an instance of it from
* <code>WizardPage.createCustomComponentListener()</code>.
*/
public static abstract class CustomComponentListener {
@@ -232,21 +229,20 @@ public class WizardPage extends JPanel implements WizardPanel {
/**
* Indicates that this CustomComponentListener will take responsibility
* for noticing events from the passed component, and that the
* WizardPage should not try to automatically listen on it (which it
* can only do for standard Swing components and their children).
* WizardPage should not try to automatically listen on it (which it can
* only do for standard Swing components and their children).
* <p>
* Note that this method may be called frequently and any test it
* does should be fast.
* Note that this method may be called frequently and any test it does
* should be fast.
* <p>
* <b>Important:</b> The return value from this method should always
* be the same for any given component, for the lifetime of the
* WizardPage.
* <b>Important:</b> The return value from this method should always be
* the same for any given component, for the lifetime of the WizardPage.
*
* @param c A component
*
* @return Whether or not this CustomComponentListener will listen
* on the passed component. If true, the component will later be
* passed to <code>startListeningTo()</code>
* @return Whether or not this CustomComponentListener will listen on
* the passed component. If true, the component will later be passed to
* <code>startListeningTo()</code>
*/
public abstract boolean accept(Component c);
@@ -256,8 +252,8 @@ public class WizardPage extends JPanel implements WizardPanel {
* <code>CustomComponentNotifier</code>.
*
* @param c The component to start listening to
* @param n An object that can be called to update the settings map
* when an interesting event occurs on the component
* @param n An object that can be called to update the settings map when
* an interesting event occurs on the component
*/
public abstract void startListeningTo(Component c, CustomComponentNotifier n);
@@ -269,8 +265,8 @@ public class WizardPage extends JPanel implements WizardPanel {
public abstract void stopListeningTo(Component c);
/**
* Determine if the passed component is a container whose children
* may need to be listened on. Returns false by default.
* Determine if the passed component is a container whose children may
* need to be listened on. Returns false by default.
*
* @param c A component which might be a container
*/
@@ -279,47 +275,44 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* Get the map key for this component's value. By default, returns
* the component's name. Will only
* be passed components which the <code>accept()</code> method
* returned true for.
* Get the map key for this component's value. By default, returns the
* component's name. Will only be passed components which the
* <code>accept()</code> method returned true for.
* <p>
* <b>Important:</b> The return value from this method should always
* be the same for any given component, for the lifetime of the
* WizardPage.
* <b>Important:</b> The return value from this method should always be
* the same for any given component, for the lifetime of the WizardPage.
*
* @param c the component, which the accept method earlier returned
* true for
* @param c the component, which the accept method earlier returned true
* for
*
* @return A string key that should be used in the Wizard's settings
* map for the name of this component's value
* @return A string key that should be used in the Wizard's settings map
* for the name of this component's value
*/
public String keyFor(Component c) {
return c.getName();
}
/**
* Get the value currently set on the passed component. Will only
* be passed components which the <code>accept()</code> method
* returned true for, and which <code>keyFor()</code> returned non-null.
* Get the value currently set on the passed component. Will only be
* passed components which the <code>accept()</code> method returned
* true for, and which <code>keyFor()</code> returned non-null.
*
* @param c the component
*
* @return An object representing the current value of this component.
* For example, if it were a <code>JTextComponent</code>, the value
* would likely
* be the return value of <code>JTextComponent.getText()</code>
* For example, if it were a <code>JTextComponent</code>, the value
* would likely be the return value of
* <code>JTextComponent.getText()</code>
*/
public abstract Object valueFor(Component c);
}
/**
* Object which is passed to
* <code>CustomComponentListener.startListeningTo()</code>,
* which can be called when an event has occurred on a custom component the
* <code>CustomComponentListener.startListeningTo()</code>, which can be
* called when an event has occurred on a custom component the
* <code>CustomComponentListener</code> has claimed (by returning
* <code>true</code>
* from its <code>accept()</code> method).
* <code>true</code> from its <code>accept()</code> method).
*/
public static abstract class CustomComponentNotifier {
@@ -330,10 +323,10 @@ public class WizardPage extends JPanel implements WizardPanel {
* Method which may be called when an event occurred on a custom
* component.
*
* @param c the component
* @param c the component
* @param eventObject the event object from the component, or null (with
* the exception of <code>javax.swing.text.DocumentEvent</code>, it
* will likely be a subclass of <code>java.util.EventObject</code>).
* the exception of <code>javax.swing.text.DocumentEvent</code>, it will
* likely be a subclass of <code>java.util.EventObject</code>).
*/
public abstract void userInputReceived(Component c, Object eventObject);
}
@@ -398,9 +391,8 @@ public class WizardPage extends JPanel implements WizardPanel {
private boolean inValidateContents = false;
/**
* Called whenever the page is rendered.
* This can be used by the page as a notification
* to load page-specific information in its fields.
* Called whenever the page is rendered. This can be used by the page as a
* notification to load page-specific information in its fields.
* <p/>
* By default, this method does nothing.
*/
@@ -424,57 +416,55 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* Create a simple Wizard from an array of WizardPages, with a
* no-op WizardResultProducer.
* Create a simple Wizard from an array of WizardPages, with a no-op
* WizardResultProducer.
*/
public static Wizard createWizard(WizardPage[] contents) {
return createWizard(contents, WizardResultProducer.NO_OP);
}
/**
* Create simple Wizard from an array of classes, each of which is a
* unique subclass of WizardPage.
* Create simple Wizard from an array of classes, each of which is a unique
* subclass of WizardPage.
*/
public static Wizard createWizard(Class[] wizardPageClasses, WizardResultProducer finisher) {
return new CWPP(wizardPageClasses, finisher).createWizard();
}
/**
* Create simple Wizard from an array of classes, each of which is a
* unique subclass of WizardPage.
* Create simple Wizard from an array of classes, each of which is a unique
* subclass of WizardPage.
*/
public static Wizard createWizard(String title, Class[] wizardPageClasses, WizardResultProducer finisher) {
return new CWPP(title, wizardPageClasses, finisher).createWizard();
}
/**
* Create simple Wizard from an array of classes, each of which is a
* unique subclass of WizardPage.
* Create simple Wizard from an array of classes, each of which is a unique
* subclass of WizardPage.
*/
public static Wizard createWizard(String title, Class[] wizardPageClasses) {
return new CWPP(title, wizardPageClasses,
WizardResultProducer.NO_OP).createWizard();
WizardResultProducer.NO_OP).createWizard();
}
/**
* Create a simple Wizard from an array of classes, each of which is a
* unique subclass of WizardPage, with a
* no-op WizardResultProducer.
* unique subclass of WizardPage, with a no-op WizardResultProducer.
*/
public static Wizard createWizard(Class[] wizardPageClasses) {
return createWizard(wizardPageClasses, WizardResultProducer.NO_OP);
}
/**
* Called by createPanelForStep, with whatever map is passed. In the
* current impl this is always the same Map, but that is not guaranteed.
* If any content was added by calls to putWizardData() during the
* constructor, etc., such data is copied to the settings map the first
* time this method is called.
* Called by createPanelForStep, with whatever map is passed. In the current
* impl this is always the same Map, but that is not guaranteed. If any
* content was added by calls to putWizardData() during the constructor,
* etc., such data is copied to the settings map the first time this method
* is called.
*
* Subclasses do NOT need to override this method,
* they can override renderPage which is always called AFTER the map has
* been made valid.
* Subclasses do NOT need to override this method, they can override
* renderPage which is always called AFTER the map has been made valid.
*/
void setWizardDataMap(Map m) {
if (m == null)
@@ -497,8 +487,8 @@ public class WizardPage extends JPanel implements WizardPanel {
/**
* Set the WizardController. In the current impl, this is always the same
* object, but the API does not guarantee that. The first time this is
* called, it will update the state of the passed controller to match
* any state that was set by components during the construction of this
* called, it will update the state of the passed controller to match any
* state that was set by components during the construction of this
* component
*/
void setController(WizardController controller) {
@@ -509,9 +499,8 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* Get the WizardController for interacting with the Wizard that
* contains this panel.
* Return value will never be null.
* Get the WizardController for interacting with the Wizard that contains
* this panel. Return value will never be null.
*/
private WizardController getController() {
return controller;
@@ -519,29 +508,29 @@ public class WizardPage extends JPanel implements WizardPanel {
/**
* Set the problem string. Call this method if next/finish should be
* disabled. The passed string will be visible to the user, and should
* be a short, localized description of what is wrong.
* disabled. The passed string will be visible to the user, and should be a
* short, localized description of what is wrong.
*/
protected final void setProblem(String value) {
getController().setProblem(value);
}
/**
* Set whether the finish, next or both buttons should be enabled,
* assuming no problem string is set.
* Set whether the finish, next or both buttons should be enabled, assuming
* no problem string is set.
*
* @param value WizardController.MODE_CAN_CONTINUE,
* WizardController.MODE_CAN_FINISH or
* WizardController.MODE_CAN_CONTINUE_OR_FINISH;
* WizardController.MODE_CAN_FINISH or
* WizardController.MODE_CAN_CONTINUE_OR_FINISH;
*/
protected final void setForwardNavigationMode(int value) {
getController().setForwardNavigationMode(value);
}
/**
* Disable all navigation. Useful if some background task is being
* completed during which no navigation should be allowed. Use with care,
* as it disables the cancel button as well.
* Disable all navigation. Useful if some background task is being completed
* during which no navigation should be allowed. Use with care, as it
* disables the cancel button as well.
*/
protected final void setBusy(boolean busy) {
getController().setBusy(busy);
@@ -572,8 +561,7 @@ public class WizardPage extends JPanel implements WizardPanel {
/**
* Retrieve a value stored in the wizard map, which may have been
* putWizardData there by this panel or any previous panel in the wizard
* which
* contains this panel.
* which contains this panel.
*/
protected final Object getWizardData(Object key) {
return getWizardDataMap().get(key);
@@ -587,21 +575,20 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* Called when an event is received from one of the components in the
* panel that indicates user input. Typically you won't need to touch this
* method, unless your panel contains custom components which are not
* subclasses of any standard Swing component, which the framework won't
* know how to listen for changes on. For such cases, attach a listener
* to the custom component, and call this method with the event if you want
* validation to run when input happens. Automatic updating of the
* settings map will not work for such custom components, for obvious
* reasons, so update the settings map, if needed, in validateContents
* for this case.
* Called when an event is received from one of the components in the panel
* that indicates user input. Typically you won't need to touch this method,
* unless your panel contains custom components which are not subclasses of
* any standard Swing component, which the framework won't know how to
* listen for changes on. For such cases, attach a listener to the custom
* component, and call this method with the event if you want validation to
* run when input happens. Automatic updating of the settings map will not
* work for such custom components, for obvious reasons, so update the
* settings map, if needed, in validateContents for this case.
*
* @param source The component that the user interacted with (if it can
* be determined from the event) or null
* @param event Usually an instance of EventObject, except in the case of
* DocumentEvent.
* @param source The component that the user interacted with (if it can be
* determined from the event) or null
* @param event Usually an instance of EventObject, except in the case of
* DocumentEvent.
*/
protected final void userInputReceived(Component source, Object event) {
if (inBeginUIChanged)
@@ -633,8 +620,8 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* Puts the value from the component in the settings map if the
* component's name property is not null
* Puts the value from the component in the settings map if the component's
* name property is not null
*/
void maybeUpdateMap(Component comp) {
Object mapKey = getMapKeyFor(comp);
@@ -657,8 +644,8 @@ public class WizardPage extends JPanel implements WizardPanel {
* Given an ad-hoc swing component, fetch the likely value based on its
* state. The default implementation handles most common swing components.
* If you are using custom components and have assigned them names, override
* this method to handle getting an appropriate value out of your
* custom component and call super for the others.
* this method to handle getting an appropriate value out of your custom
* component and call super for the others.
*/
protected Object valueFrom(Component comp) {
if (ccl != null && ccl.accept(comp))
@@ -673,11 +660,10 @@ public class WizardPage extends JPanel implements WizardPanel {
return ((JFormattedTextField) comp).getValue();
else if (comp instanceof JList) {
Object[] o = ((JList) comp).getSelectedValues();
if (o != null)
if (o.length > 1)
return o;
else if (o.length == 1)
return o[0];
if (o.length > 1)
return o;
else if (o.length == 1)
return o[0];
} else if (comp instanceof JTextComponent)
return ((JTextComponent) comp).getText();
else if (comp instanceof JComboBox)
@@ -693,12 +679,11 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* Given an ad-hoc swing component, set the value as the property
* from the settings. The default implementation handles most common swing
* components.
* If you are using custom components and have assigned them names, override
* this method to handle getting an appropriate value out of your
* custom component and call super for the others.
* Given an ad-hoc swing component, set the value as the property from the
* settings. The default implementation handles most common swing
* components. If you are using custom components and have assigned them
* names, override this method to handle getting an appropriate value out of
* your custom component and call super for the others.
*/
protected void valueTo(Map settings, Component comp) {
String name = comp.getName();
@@ -734,14 +719,13 @@ public class WizardPage extends JPanel implements WizardPanel {
* represented by this component into the wizard data map.
* <p/>
* The default implementation returns the result of
* <code>c.getName()</code>,
* which is almost always sufficient and convenient - just set the
* component names in a GUI builder and everything will be handled.
* <code>c.getName()</code>, which is almost always sufficient and
* convenient - just set the component names in a GUI builder and everything
* will be handled.
*
* @return null if the component's value should not be automatically
* written to the wizard data map, or an object which is the key that
* later code will use to find this value. By default, it returns the
* component's name.
* @return null if the component's value should not be automatically written
* to the wizard data map, or an object which is the key that later code
* will use to find this value. By default, it returns the component's name.
*/
protected Object getMapKeyFor(Component c) {
if (ccl != null && ccl.accept(c))
@@ -752,55 +736,54 @@ public class WizardPage extends JPanel implements WizardPanel {
/**
* Called when user interaction has occurred on a component contained by
* this
* panel or one of its children. Override this method to check if all of
* the values are legal, such that the Next/Finish button should be enabled,
* optionally calling <code>setForwardNavigationMode()</code> if warranted.
* this panel or one of its children. Override this method to check if all
* of the values are legal, such that the Next/Finish button should be
* enabled, optionally calling <code>setForwardNavigationMode()</code> if
* warranted.
* <p/>
* This method also may be called with a null argument an effect of
* calling <code>putWizardData()</code> from someplace other than within
* this method.
* This method also may be called with a null argument an effect of calling
* <code>putWizardData()</code> from someplace other than within this
* method.
* <p/>
* Note that this method may be called very frequently, so it is important
* that validation code be fast. For cases such as
* <code>DocumentEvent</code>s,
* it may be desirable to delay validation with a timer, if the
* implementation
* of this method is too expensive to call on each keystroke.
* <code>DocumentEvent</code>s, it may be desirable to delay validation with
* a timer, if the implementation of this method is too expensive to call on
* each keystroke.
* <p/>
* Either the component, or the event, or both may be null on some calls
* to this method (such as when it is called because the settings map
* has been written to).
* Either the component, or the event, or both may be null on some calls to
* this method (such as when it is called because the settings map has been
* written to).
* <p/>
* The default implementation returns null.
*
* @param component The component the user interacted with, if it can be
* determined. The infrastructure does track the owners of list models
* and such, and can find the associated component, so this will usually
* (but not necessarily) be non-null.
* @param event The event object (if any) that triggered this call to
* validateContents. For most cases this will be an instance of
* EventObject, and can be used to directly detect what component
* the user interacted with. Since javax.swing.text.DocumentEvent is
* not a subclass of EventObject, the type of the argument is Object,
* so these events may be passed.
* determined. The infrastructure does track the owners of list models and
* such, and can find the associated component, so this will usually (but
* not necessarily) be non-null.
* @param event The event object (if any) that triggered this call to
* validateContents. For most cases this will be an instance of EventObject,
* and can be used to directly detect what component the user interacted
* with. Since javax.swing.text.DocumentEvent is not a subclass of
* EventObject, the type of the argument is Object, so these events may be
* passed.
*
* @return A localized string describing why navigation should be disabled,
* or null if the state of the components is valid and forward navigation
* should be enabled.
* or null if the state of the components is valid and forward navigation
* should be enabled.
*/
protected String validateContents(Component component, Object event) {
return null;
}
/**
* Called if the user is navigating into this panel when it has already
* been displayed at least once - the user has navigated back to this
* panel, or back past this panel and is now navigating forward again.
* Called if the user is navigating into this panel when it has already been
* displayed at least once - the user has navigated back to this panel, or
* back past this panel and is now navigating forward again.
* <p/>
* If some of the UI needs to be set up based on values from earlier
* pages that may have changed, do that here, fetching values from the
* settings map by calling <code>getWizardData()</code>.
* If some of the UI needs to be set up based on values from earlier pages
* that may have changed, do that here, fetching values from the settings
* map by calling <code>getWizardData()</code>.
* <p/>
* The default implementation simply calls
* <code>validateContents (null, null)</code>.
@@ -810,8 +793,8 @@ public class WizardPage extends JPanel implements WizardPanel {
}
/**
* Get the settings map into which the wizard gathers settings.
* Return value will never be null.
* Get the settings map into which the wizard gathers settings. Return value
* will never be null.
*/
// the map is empty during construction, then later set to the map from the containing WizardController
protected Map getWizardDataMap() {
@@ -823,22 +806,22 @@ public class WizardPage extends JPanel implements WizardPanel {
private String longDescription;
/**
* Set the long description of this page. This method may be called
* only once and should be called from within the constructor.
* Set the long description of this page. This method may be called only
* once and should be called from within the constructor.
*
* @param desc The long description for this step
*/
protected void setLongDescription(String desc) {
if (!Beans.isDesignTime() && this.longDescription != null)
throw new IllegalStateException("Long description already set to"
+ " " + desc);
+ " " + desc);
this.longDescription = desc;
}
/**
* Get the long description of this page, which should be used in the title
* area of the wizard's UI if non-null. To use, call setLongDescription()
* in your WizardPage's constructor. It may be set only once.
* area of the wizard's UI if non-null. To use, call setLongDescription() in
* your WizardPage's constructor. It may be set only once.
*
* @return the description
*/
@@ -847,7 +830,7 @@ public class WizardPage extends JPanel implements WizardPanel {
}
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) {
@@ -897,7 +880,7 @@ public class WizardPage extends JPanel implements WizardPanel {
}
protected JComponent createPanel(WizardController controller, String id,
Map wizardData) {
Map wizardData) {
int idx = indexOfStep(id);
// assert idx != -1 : "Bad ID passed to createPanel: " + id;
@@ -915,7 +898,7 @@ public class WizardPage extends JPanel implements WizardPanel {
private String valid(WizardPage[] pages) {
if (new HashSet(Arrays.asList(pages)).size() != pages.length)
return "Duplicate entry in array: "
+ Arrays.asList(pages);
+ Arrays.asList(pages);
for (int i = 0; i < pages.length; i++)
if (pages[i] == null)
@@ -1005,10 +988,10 @@ public class WizardPage extends JPanel implements WizardPanel {
result.setWizardDataMap(wizardData);
return result;
} catch (Exception e) {
} catch (IllegalAccessException | InstantiationException e) {
// really IllegalArgumentException, but we need to have the "cause" get shown in stack trace
throw new RuntimeException("Could not instantiate "
+ classes[idx], e);
+ classes[idx], e);
}
}
@@ -1028,15 +1011,15 @@ public class WizardPage extends JPanel implements WizardPanel {
int idx = indexOfStep(stepId);
if (idx != -1)
return longDescriptions[idx] == null ? descriptions[idx]
: longDescriptions[idx];
: longDescriptions[idx];
return null;
}
}
/**
* A dummy wizard controller which is used until the panel has actually
* been put into use; so state can be set during the constructor, etc.
* Its state will be dumped into the real one once there is a real one.
* A dummy wizard controller which is used until the panel has actually been
* put into use; so state can be set during the constructor, etc. Its state
* will be dumped into the real one once there is a real one.
*/
private static final class WC implements WizardControllerImplementation {
@@ -1050,12 +1033,12 @@ public class WizardPage extends JPanel implements WizardPanel {
public void setForwardNavigationMode(int value) {
switch (value) {
case WizardController.MODE_CAN_CONTINUE:
case WizardController.MODE_CAN_FINISH:
case WizardController.MODE_CAN_CONTINUE_OR_FINISH:
break;
default:
throw new IllegalArgumentException(Integer.toString(value));
case WizardController.MODE_CAN_CONTINUE:
case WizardController.MODE_CAN_FINISH:
case WizardController.MODE_CAN_CONTINUE_OR_FINISH:
break;
default:
throw new IllegalArgumentException(Integer.toString(value));
}
canFinish = value;
@@ -1082,9 +1065,9 @@ public class WizardPage extends JPanel implements WizardPanel {
/**
* Interface that is passed to WizardPage.createWizard(). For wizards
* created from a set of WizardPages or WizardPage subclasses, this is
* the object that whose code will be run to create or do whatever the
* wizard does when the user clicks the Finish button.
* created from a set of WizardPages or WizardPage subclasses, this is the
* object that whose code will be run to create or do whatever the wizard
* does when the user clicks the Finish button.
*/
public static interface WizardResultProducer {
@@ -1093,30 +1076,23 @@ public class WizardPage extends JPanel implements WizardPanel {
* gathered into the map on the various panels.
* <p>
* 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
* except the Close/Cancel button.
* the UI shall display it on a final page and disable all navigation
* buttons except the Close/Cancel button.
* <p>
* If an instance of <code>DeferredWizardResult</code> is returned from
* this
* method, the UI shall display some sort of progress bar while the
* result
* is computed in the background. If that
* <code>DeferredWizardResult</code>
* produces a <code>Summary</code> object, that summary shall be
* displayed
* as described above.
* this method, the UI shall display some sort of progress bar while the
* result is computed in the background. If that
* <code>DeferredWizardResult</code> produces a <code>Summary</code>
* object, that summary shall be displayed as described above.
*
* @param wizardData the map with key-value pairs which has been
* populated by the UI as the user progressed through the wizard
* populated by the UI as the user progressed through 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
* special handling if an instance of <code>DeferredWizardResult</code>
* or <code>Summary</code> is returned from this method.
* wizard - somethingmeaningful to whatever code invoked the wizard, or
* null. Note special handling if an instance of
* <code>DeferredWizardResult</code> or <code>Summary</code> is returned
* from this method.
*/
Object finish(Map wizardData) throws WizardException;

View File

@@ -298,7 +298,7 @@ mainwindow.enter_script_name=输入要生成脚本的文件名
mainwindow.make_launch_succeed=启动脚本已生成完毕:
mainwindow.no_version=未找到任何版本,是否进入游戏下载?
launcher.about=<html>默认背景图感谢gamerteam提供。<br><a href="http://huangyuhui.duapp.com/link.php?type=sponsor">如果您希望本软件继续发展,请赞助</a><br/>关于作者:<br/>百度IDhuanghongxun20<br/>mcbbshuanghongxun<br/>邮箱huanghongxun2008@126.com<br/>Minecraft Forum ID: klkl6523<br/>欢迎提交Bug哦<br/>Copyright (c) 2013-2016 huangyuhui.<br/>免责声明Minecraft软件版权归Mojang AB所有使用本软件产生的版权问题本软件制作方概不负责。<br/>本启动器在GPLv3协议下开源:https://github.com/huanghongxun/HMCL/ ,感谢issues和pull requests贡献者<br/>本软件使用了基于Apache License 2.0的Gson项目感谢贡献者。</html>
launcher.about=<html>默认背景图感谢gamerteam提供。<br/>关于作者:<br/>百度IDhuanghongxun20<br/>mcbbshuanghongxun<br/>Minecraft Forum ID: klkl6523<br/>欢迎提交Bug哦<br/>Copyright (c) 2013-2017 huangyuhui.<br/>免责声明Minecraft软件版权归Mojang AB所有使用本软件产生的版权问题本软件制作方概不负责。<br/>本启动器在GPLv3协议下开源:https://github.com/huanghongxun/HMCL/ ,感谢issues和pull requests贡献者<br/>本软件使用了基于Apache License 2.0的Gson项目感谢贡献者。</html>
launcher.download_source=下载源
launcher.background_location=背景地址
launcher.exit_failed=强制退出失败可能是Forge 1.7.10及更高版本导致的,无法解决。

View File

@@ -298,7 +298,7 @@ mainwindow.enter_script_name=\u8f93\u5165\u8981\u751f\u6210\u811a\u672c\u7684\u6
mainwindow.make_launch_succeed=\u542f\u52a8\u811a\u672c\u5df2\u751f\u6210\u5b8c\u6bd5:
mainwindow.no_version=\u672a\u627e\u5230\u4efb\u4f55\u7248\u672c\uff0c\u662f\u5426\u8fdb\u5165\u6e38\u620f\u4e0b\u8f7d\uff1f
launcher.about=<html>\u9ed8\u8ba4\u80cc\u666f\u56fe\u611f\u8c22gamerteam\u63d0\u4f9b\u3002<br><a href="http://huangyuhui.duapp.com/link.php?type=sponsor">\u5982\u679c\u60a8\u5e0c\u671b\u672c\u8f6f\u4ef6\u7ee7\u7eed\u53d1\u5c55\uff0c\u8bf7\u8d5e\u52a9</a><br/>\u5173\u4e8e\u4f5c\u8005\uff1a<br/>\u767e\u5ea6ID\uff1ahuanghongxun20<br/>mcbbs\uff1ahuanghongxun<br/>\u90ae\u7bb1\uff1ahuanghongxun2008@126.com<br/>Minecraft Forum ID: klkl6523<br/>\u6b22\u8fce\u63d0\u4ea4Bug\u54e6<br/>Copyright (c) 2013-2016 huangyuhui.<br/>\u514d\u8d23\u58f0\u660e\uff1aMinecraft\u8f6f\u4ef6\u7248\u6743\u5f52Mojang AB\u6240\u6709\uff0c\u4f7f\u7528\u672c\u8f6f\u4ef6\u4ea7\u751f\u7684\u7248\u6743\u95ee\u9898\u672c\u8f6f\u4ef6\u5236\u4f5c\u65b9\u6982\u4e0d\u8d1f\u8d23\u3002<br/>\u672c\u542f\u52a8\u5668\u5728GPLv3\u534f\u8bae\u4e0b\u5f00\u6e90:https://github.com/huanghongxun/HMCL/ ,\u611f\u8c22issues\u548cpull requests\u8d21\u732e\u8005<br/>\u672c\u8f6f\u4ef6\u4f7f\u7528\u4e86\u57fa\u4e8eApache License 2.0\u7684Gson\u9879\u76ee\uff0c\u611f\u8c22\u8d21\u732e\u8005\u3002</html>
launcher.about=<html>\u9ed8\u8ba4\u80cc\u666f\u56fe\u611f\u8c22gamerteam\u63d0\u4f9b\u3002<br/>\u5173\u4e8e\u4f5c\u8005\uff1a<br/>\u767e\u5ea6ID\uff1ahuanghongxun20<br/>mcbbs\uff1ahuanghongxun<br/>Minecraft Forum ID: klkl6523<br/>\u6b22\u8fce\u63d0\u4ea4Bug\u54e6<br/>Copyright (c) 2013-2017 huangyuhui.<br/>\u514d\u8d23\u58f0\u660e\uff1aMinecraft\u8f6f\u4ef6\u7248\u6743\u5f52Mojang AB\u6240\u6709\uff0c\u4f7f\u7528\u672c\u8f6f\u4ef6\u4ea7\u751f\u7684\u7248\u6743\u95ee\u9898\u672c\u8f6f\u4ef6\u5236\u4f5c\u65b9\u6982\u4e0d\u8d1f\u8d23\u3002<br/>\u672c\u542f\u52a8\u5668\u5728GPLv3\u534f\u8bae\u4e0b\u5f00\u6e90:https://github.com/huanghongxun/HMCL/ ,\u611f\u8c22issues\u548cpull requests\u8d21\u732e\u8005<br/>\u672c\u8f6f\u4ef6\u4f7f\u7528\u4e86\u57fa\u4e8eApache License 2.0\u7684Gson\u9879\u76ee\uff0c\u611f\u8c22\u8d21\u732e\u8005\u3002</html>
launcher.download_source=\u4e0b\u8f7d\u6e90
launcher.background_location=\u80cc\u666f\u5730\u5740
launcher.exit_failed=\u5f3a\u5236\u9000\u51fa\u5931\u8d25\uff0c\u53ef\u80fd\u662fForge 1.7.10\u53ca\u66f4\u9ad8\u7248\u672c\u5bfc\u81f4\u7684\uff0c\u65e0\u6cd5\u89e3\u51b3\u3002

View File

@@ -298,7 +298,7 @@ mainwindow.enter_script_name=Enter the script name.
mainwindow.make_launch_succeed=Finished script creation.
mainwindow.no_version=No version found. Switch to Game Downloads Tab?
launcher.about=<html>About Author<br/>Emailhuanghongxun2008@126.com<br/>Minecraft Forum ID: klkl6523<br/>Copyright (c) 2013 huangyuhui<br/>Opened source under GPL v3 license:http://github.com/huanghongxun/HMCL/<br/>This software used project Gson which is under Apache License 2.0, thanks contributors.</html>
launcher.about=<html>About Author<br/>Minecraft Forum ID: klkl6523<br/>Copyright (c) 2013 huangyuhui<br/>Opened source under GPL v3 license:http://github.com/huanghongxun/HMCL/<br/>This software used project Gson which is under Apache License 2.0, thanks contributors.</html>
launcher.download_source=Download Source
launcher.background_location=Background Location
launcher.exit_failed=Failed to shutdown.

View File

@@ -298,7 +298,7 @@ mainwindow.enter_script_name=Enter the script name.
mainwindow.make_launch_succeed=Finished script creation.
mainwindow.no_version=No version found. Switch to Game Downloads Tab?
launcher.about=<html>About Author<br/>Email\uff1ahuanghongxun2008@126.com<br/>Minecraft Forum ID: klkl6523<br/>Copyright (c) 2013 huangyuhui<br/>Opened source under GPL v3 license:http://github.com/huanghongxun/HMCL/<br/>This software used project Gson which is under Apache License 2.0, thanks contributors.</html>
launcher.about=<html>About Author<br/>Minecraft Forum ID: klkl6523<br/>Copyright (c) 2013 huangyuhui<br/>Opened source under GPL v3 license:http://github.com/huanghongxun/HMCL/<br/>This software used project Gson which is under Apache License 2.0, thanks contributors.</html>
launcher.download_source=Download Source
launcher.background_location=Background Location
launcher.exit_failed=Failed to shutdown.

View File

@@ -298,7 +298,7 @@ mainwindow.enter_script_name=輸入要生成腳本的資料名
mainwindow.make_launch_succeed=啟動腳本已生成完畢:
mainwindow.no_version=未找到任何版本,是否進入遊戲下載?
launcher.about=<html>默認背景圖感謝gamerteam提供。<br><a href="http://huangyuhui.duapp.com/link.php?type=sponsor">如果您希望本軟件繼續發展,請贊助</a><br>關於作者:<br>百度IDhuanghongxun20<br>mcbbshuanghongxun<br>郵箱huanghongxun2008@126.com<br>Minecraft Forum ID: klkl6523<br>歡迎提交Bug哦<br/>Copyright (c) 2013-2016 huangyuhui.<br>免責聲明Minecraft軟體版權歸Mojang AB所有遊戲由於誤操作本啟動器而丟失數據的概不負責。<br>本啟動器在GPLv3協議下開源:http://github.com/huanghongxun/HMCL/ ,感谢issues和pull requests贡献者<br>本軟體使用了基於Apache License 2.0的Gson項目感謝貢獻者。</html>
launcher.about=<html>默認背景圖感謝gamerteam提供。<br>關於作者:<br>百度IDhuanghongxun20<br>mcbbshuanghongxun<br>Minecraft Forum ID: klkl6523<br>歡迎提交Bug哦<br/>Copyright (c) 2013-2016 huangyuhui.<br>免責聲明Minecraft軟體版權歸Mojang AB所有遊戲由於誤操作本啟動器而丟失數據的概不負責。<br>本啟動器在GPLv3協議下開源:http://github.com/huanghongxun/HMCL/ ,感谢issues和pull requests贡献者<br>本軟體使用了基於Apache License 2.0的Gson項目感謝貢獻者。</html>
launcher.download_source=下載源
launcher.background_location=背景地址
launcher.exit_failed=強制退出失敗可能是Forge 1.7.10及更高版本導致的,無法解決。

View File

@@ -298,7 +298,7 @@ mainwindow.enter_script_name=\u8f38\u5165\u8981\u751f\u6210\u8173\u672c\u7684\u8
mainwindow.make_launch_succeed=\u555f\u52d5\u8173\u672c\u5df2\u751f\u6210\u5b8c\u7562:
mainwindow.no_version=\u672a\u627e\u5230\u4efb\u4f55\u7248\u672c\uff0c\u662f\u5426\u9032\u5165\u904a\u6232\u4e0b\u8f09\uff1f
launcher.about=<html>\u9ed8\u8a8d\u80cc\u666f\u5716\u611f\u8b1dgamerteam\u63d0\u4f9b\u3002<br><a href="http://huangyuhui.duapp.com/link.php?type=sponsor">\u5982\u679c\u60a8\u5e0c\u671b\u672c\u8edf\u4ef6\u7e7c\u7e8c\u767c\u5c55\uff0c\u8acb\u8d0a\u52a9</a><br>\u95dc\u65bc\u4f5c\u8005\uff1a<br>\u767e\u5ea6ID\uff1ahuanghongxun20<br>mcbbs\uff1ahuanghongxun<br>\u90f5\u7bb1\uff1ahuanghongxun2008@126.com<br>Minecraft Forum ID: klkl6523<br>\u6b61\u8fce\u63d0\u4ea4Bug\u54e6<br/>Copyright (c) 2013-2016 huangyuhui.<br>\u514d\u8cac\u8072\u660e\uff1aMinecraft\u8edf\u9ad4\u7248\u6b0a\u6b78Mojang AB\u6240\u6709\uff0c\u904a\u6232\u7531\u65bc\u8aa4\u64cd\u4f5c\u672c\u555f\u52d5\u5668\u800c\u4e1f\u5931\u6578\u64da\u7684\u6982\u4e0d\u8ca0\u8cac\u3002<br>\u672c\u555f\u52d5\u5668\u5728GPLv3\u5354\u8b70\u4e0b\u958b\u6e90:http://github.com/huanghongxun/HMCL/ ,\u611f\u8c22issues\u548cpull requests\u8d21\u732e\u8005<br>\u672c\u8edf\u9ad4\u4f7f\u7528\u4e86\u57fa\u65bcApache License 2.0\u7684Gson\u9805\u76ee\uff0c\u611f\u8b1d\u8ca2\u737b\u8005\u3002</html>
launcher.about=<html>\u9ed8\u8a8d\u80cc\u666f\u5716\u611f\u8b1dgamerteam\u63d0\u4f9b\u3002<br>\u95dc\u65bc\u4f5c\u8005\uff1a<br>\u767e\u5ea6ID\uff1ahuanghongxun20<br>mcbbs\uff1ahuanghongxun<br>Minecraft Forum ID: klkl6523<br>\u6b61\u8fce\u63d0\u4ea4Bug\u54e6<br/>Copyright (c) 2013-2016 huangyuhui.<br>\u514d\u8cac\u8072\u660e\uff1aMinecraft\u8edf\u9ad4\u7248\u6b0a\u6b78Mojang AB\u6240\u6709\uff0c\u904a\u6232\u7531\u65bc\u8aa4\u64cd\u4f5c\u672c\u555f\u52d5\u5668\u800c\u4e1f\u5931\u6578\u64da\u7684\u6982\u4e0d\u8ca0\u8cac\u3002<br>\u672c\u555f\u52d5\u5668\u5728GPLv3\u5354\u8b70\u4e0b\u958b\u6e90:http://github.com/huanghongxun/HMCL/ ,\u611f\u8c22issues\u548cpull requests\u8d21\u732e\u8005<br>\u672c\u8edf\u9ad4\u4f7f\u7528\u4e86\u57fa\u65bcApache License 2.0\u7684Gson\u9805\u76ee\uff0c\u611f\u8b1d\u8ca2\u737b\u8005\u3002</html>
launcher.download_source=\u4e0b\u8f09\u6e90
launcher.background_location=\u80cc\u666f\u5730\u5740
launcher.exit_failed=\u5f37\u5236\u9000\u51fa\u5931\u6557\uff0c\u53ef\u80fd\u662fForge 1.7.10\u53ca\u66f4\u9ad8\u7248\u672c\u5c0e\u81f4\u7684\uff0c\u7121\u6cd5\u89e3\u6c7a\u3002