Added Gaussion Blur
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
@@ -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()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class ParallelTask extends Task {
|
||||
Collection<Task> dependsTask = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void executeTask() {
|
||||
public void executeTask(boolean areDependTasksSucceeded) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -35,7 +35,7 @@ public class TaskRunnable extends TaskInfo {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeTask() {
|
||||
public void executeTask(boolean areDependTasksSucceeded) {
|
||||
r.run();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 < 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 < 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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/>百度ID:huanghongxun20<br/>mcbbs:huanghongxun<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/>百度ID:huanghongxun20<br/>mcbbs:huanghongxun<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及更高版本导致的,无法解决。
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:huanghongxun2008@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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>百度ID:huanghongxun20<br>mcbbs:huanghongxun<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>百度ID:huanghongxun20<br>mcbbs:huanghongxun<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及更高版本導致的,無法解決。
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user