values(MultiMap mm) {
return mm == null ? emptyList() : concatLists(values(mm.data));
}
static Object nuObject(String className, Object... args) { try {
return nuObject(classForName(className), args);
} catch (Exception __e) { throw rethrow(__e); } }
// too ambiguous - maybe need to fix some callers
/*static O nuObject(O realm, S className, O... args) {
ret nuObject(_getClass(realm, className), args);
}*/
static A nuObject(Class c, Object... args) { try {
if (args.length == 0) return nuObjectWithoutArguments(c); // cached!
Constructor m = nuObject_findConstructor(c, args);
makeAccessible(m);
return (A) m.newInstance(args);
} catch (Exception __e) { throw rethrow(__e); } }
static Constructor nuObject_findConstructor(Class c, Object... args) {
for (Constructor m : c.getDeclaredConstructors()) {
if (!nuObject_checkArgs(m.getParameterTypes(), args, false))
continue;
return m;
}
throw fail("Constructor " + c.getName() + getClasses(args) + " not found"
+ (args.length == 0 && (c.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0 ? " - hint: it's a non-static class!" : ""));
}
static boolean nuObject_checkArgs(Class[] types, Object[] args, boolean debug) {
if (types.length != args.length) {
if (debug)
System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
return false;
}
for (int i = 0; i < types.length; i++)
if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
if (debug)
System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
return false;
}
return true;
}
static JTextArea jTextAreaWithUndo() {
return jTextAreaWithUndo("");
}
static JTextArea jTextAreaWithUndo(final String text) {
return jenableUndoRedo(swingNu(JTextArea.class, text));
}
static boolean swic(String a, String b) {
return startsWithIgnoreCase(a, b);
}
static boolean swic(String a, String b, Matches m) {
if (!swic(a, b)) return false;
m.m = new String[] {substring(a, l(b))};
return true;
}
static boolean containsNewLines(String s) {
return containsNewLine(s);
}
static String jlabel_textAsHTML_center(String text) {
return ""
+ replace(htmlencode2(text), "\n", "
")
+ "
";
}
static boolean headless() {
return isHeadless();
}
static Throwable innerException2(Throwable e) {
if (e == null) return null;
while (empty(e.getMessage()) && e.getCause() != null)
e = e.getCause();
return e;
}
static String getSelectedItem(JList l) {
return (String) l.getSelectedValue();
}
static String getSelectedItem(JComboBox cb) {
return strOrNull(cb.getSelectedItem());
}
static JPanel jpanel(LayoutManager layout) {
return swingNu(JPanel.class, layout);
}
static JPanel jpanel() {
return swingNu(JPanel.class);
}
static Rect toRect(Rectangle r) {
return r == null ? null : new Rect(r);
}
static Rect toRect(RectangularShape r) {
return r == null ? null : toRect(r.getBounds());
}
static Rect toRect(DoubleRect r) {
if (r == null) return null;
int x = iround(r.x), y = iround(r.y);
return new Rect(x, y, iround(r.x2())-x, iround(r.y2())-y);
}
static Rect toRect(Rect r) { return r; }
static List screenDevices() {
return asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices());
}
static List immutableEmptyList() {
return Collections.emptyList();
}
static short[] emptyShortArray = new short[0];
static short[] emptyShortArray() { return emptyShortArray; }
static Map immutableEmptyMap() {
return Collections.emptyMap();
}
static Object pcallFunction(Object f, Object... args) {
try { return callFunction(f, args); } catch (Throwable __e) { printStackTrace(__e); }
return null;
}
static boolean emptyString(String s) {
return s == null || s.length() == 0;
}
static A getWeakRef(Reference ref) {
return ref == null ? null : ref.get();
}
static x30_pkg.x30_util.BetterThreadLocal dm_current_generic_tl;
static x30_pkg.x30_util.BetterThreadLocal dm_current_generic_tl() {
if (dm_current_generic_tl == null)
dm_current_generic_tl = vm_generalMap_getOrCreate("currentModule", () -> new x30_pkg.x30_util.BetterThreadLocal());
return dm_current_generic_tl;
}
static int cmp(Number a, Number b) {
return a == null ? b == null ? 0 : -1 : cmp(a.doubleValue(), b.doubleValue());
}
static int cmp(double a, double b) {
return a < b ? -1 : a == b ? 0 : 1;
}
static int cmp(int a, int b) {
return a < b ? -1 : a == b ? 0 : 1;
}
static int cmp(long a, long b) {
return a < b ? -1 : a == b ? 0 : 1;
}
static int cmp(Object a, Object b) {
if (a == null) return b == null ? 0 : -1;
if (b == null) return 1;
return ((Comparable) a).compareTo(b);
}
static A[] makeArray(Class type, int n) {
return (A[]) Array.newInstance(type, n);
}
static A popLast(List l) {
return liftLast(l);
}
static List popLast(int n, List l) {
return liftLast(n, l);
}
static Set> _entrySet(Map map) {
return map == null ? Collections.EMPTY_SET : map.entrySet();
}
static boolean regionMatchesIC(String a, int offsetA, String b, int offsetB, int len) {
return a != null && a.regionMatches(true, offsetA, b, offsetB, len);
}
static File programDir_mine; // set this to relocate program's data
static File programDir() {
return programDir(getProgramID());
}
static File programDir(String snippetID) {
boolean me = sameSnippetID(snippetID, programID());
if (programDir_mine != null && me)
return programDir_mine;
File dir = new File(javaxDataDir(), formatSnippetIDOpt(snippetID));
if (me) {
String c = caseID();
if (nempty(c)) dir = newFile(dir, c);
}
return dir;
}
static File programDir(String snippetID, String subPath) {
return new File(programDir(snippetID), subPath);
}
static boolean nempty(Collection c) {
return !empty(c);
}
static boolean nempty(CharSequence s) {
return !empty(s);
}
static boolean nempty(Object[] o) { return !empty(o); }
static boolean nempty(byte[] o) { return !empty(o); }
static boolean nempty(int[] o) { return !empty(o); }
static boolean nempty(BitSet bs) { return !empty(bs); }
static boolean nempty(Map m) {
return !empty(m);
}
static boolean nempty(Iterator i) {
return i != null && i.hasNext();
}
static boolean nempty(MultiMap mm) { return mm != null && !mm.isEmpty(); }
static boolean nempty(Object o) { return !empty(o); }
static boolean nempty(IntRange r) { return !empty(r); }
static boolean nempty(Rect r) { return r != null && r.w != 0 && r.h != 0; }
static boolean nempty(MultiSet ms) { return ms != null && !ms.isEmpty(); }
static String formatSnippetIDOpt(String s) {
return isSnippetID(s) ? formatSnippetID(s) : s;
}
static String formatSnippetID(String id) {
return "#" + parseSnippetID(id);
}
static String formatSnippetID(long id) {
return "#" + id;
}
static Class getMainClass() {
return mc();
}
static Class getMainClass(Object o) { try {
if (o == null) return null;
if (o instanceof Class && eq(((Class) o).getName(), "x30")) return (Class) o;
ClassLoader cl = (o instanceof Class ? (Class) o : o.getClass()).getClassLoader();
if (cl == null) return null;
String name = mainClassNameForClassLoader(cl);
return loadClassFromClassLoader_orNull(cl, name);
} catch (Exception __e) { throw rethrow(__e); } }
static Map vm_threadInterruptionReasonsMap() {
return vm_generalWeakSubMap("Thread interruption reasons");
}
static String strOr(Object o, String ifNull) {
return o == null ? ifNull : str(o);
}
static void lockOrFail(Lock lock, long timeout) { try {
ping();
vmBus_send("locking", lock, "thread" , currentThread());
if (!lock.tryLock(timeout, TimeUnit.MILLISECONDS)) {
String s = "Couldn't acquire lock after " + timeout + " ms.";
if (lock instanceof ReentrantLock) {
ReentrantLock l = (ReentrantLock) lock;
s += " Hold count: " + l.getHoldCount() + ", owner: " + call(l, "getOwner");
}
throw fail(s);
}
vmBus_send("locked", lock, "thread" , currentThread());
ping();
} catch (Exception __e) { throw rethrow(__e); } }
static ReentrantLock fairLock() {
return new ReentrantLock(true);
}
static String f2s(File f) {
return f == null ? null : f.getAbsolutePath();
}
static String f2s(String s) { return f2s(newFile(s)); }
static String f2s(java.nio.file.Path p) {
return p == null ? null : f2s(p.toFile());
}
static void _registerIO(Object object, String path, boolean opened) {
}
static AutoCloseable tempSetTL(ThreadLocal tl, A a) {
return tempSetThreadLocal(tl, a);
}
static List concatLists(Iterable... lists) {
List l = new ArrayList();
if (lists != null) for (Iterable list : lists)
addAll(l, list);
return l;
}
static List concatLists(Collection extends Iterable> lists) {
List l = new ArrayList();
if (lists != null) for (Iterable list : lists)
addAll(l, list);
return l;
}
static Map classForName_cache = synchroHashMap();
static Class classForName(String name) { return classForName(name, null); }
static Class classForName(String name, Object classFinder) {
// first clause is when we're in class init
if (classForName_cache == null || classFinder != null)
return classForName_uncached(name, classFinder);
Class c = classForName_cache.get(name);
if (c == null)
classForName_cache.put(name, c = classForName_uncached(name, null));
return c;
}
static Class classForName_uncached(String name, Object classFinder) { try {
if (classFinder != null) return (Class) callF(classFinder, name);
return Class.forName(name);
} catch (Exception __e) { throw rethrow(__e); } }
static Map nuObjectWithoutArguments_cache = newDangerousWeakHashMap();
static Object nuObjectWithoutArguments(String className) { try {
return nuObjectWithoutArguments(classForName(className));
} catch (Exception __e) { throw rethrow(__e); } }
static A nuObjectWithoutArguments(Class c) { try {
if (nuObjectWithoutArguments_cache == null)
// in class init
return (A) nuObjectWithoutArguments_findConstructor(c).newInstance();
Constructor m = nuObjectWithoutArguments_cache.get(c);
if (m == null)
nuObjectWithoutArguments_cache.put(c, m = nuObjectWithoutArguments_findConstructor(c));
return (A) m.newInstance();
} catch (Exception __e) { throw rethrow(__e); } }
static Constructor nuObjectWithoutArguments_findConstructor(Class c) {
for (Constructor m : c.getDeclaredConstructors())
if (empty(m.getParameterTypes())) {
makeAccessible(m);
return m;
}
throw fail("No default constructor found in " + c.getName());
}
static A jenableUndoRedo(final A textcomp) {
{ swing(() -> {
final UndoManager undo = new UndoManager();
vm_generalWeakSet("Undo Managers").add(undo);
textcomp.getDocument().addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undo.addEdit(evt.getEdit());
}
});
textcomp.getActionMap().put("Undo", abstractAction("Undo", new Runnable() { public void run() { try {
if (undo.canUndo()) undo.undo()
;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (undo.canUndo()) undo.undo()"; }}));
textcomp.getActionMap().put("Redo", abstractAction("Redo", new Runnable() { public void run() { try {
if (undo.canRedo()) undo.redo()
;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "if (undo.canRedo()) undo.redo()"; }}));
textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Z"), "Undo");
textcomp.getInputMap().put(KeyStroke.getKeyStroke("control Y"), "Redo");
}); }
return textcomp;
}
static A swingNu(final Class c, final Object... args) {
return swingConstruct(c, args);
}
static boolean startsWithIgnoreCase(String a, String b) {
return regionMatchesIC(a, 0, b, 0, b.length());
}
static boolean containsNewLine(String s) {
return contains(s, '\n'); // screw \r, nobody needs it
}
static List replace(List l, A a, A b) {
for (int i = 0; i < l(l); i++)
if (eq(l.get(i), a))
l.set(i, b);
return l;
}
static List replace(A a, A b, List l) {
return replace(l, a, b);
}
// replace all occurrences of a in s with b
static String replace(String s, String a, String b) {
return s == null ? null : a == null || b == null ? s : s.replace(a, b);
}
static String replace(String s, char a, char b) {
return s == null ? null : s.replace(a, b);
}
static String htmlencode2(String s) {
return htmlencode_noQuotes(s);
}
static A liftLast(List l) {
if (empty(l)) return null;
int i = l(l)-1;
A a = l.get(i);
l.remove(i);
return a;
}
static List liftLast(int n, List l) {
int i = l(l)-n;
List part = cloneSubList(l, i);
removeSubList(l, i);
return part;
}
static boolean sameSnippetID(String a, String b) {
if (!isSnippetID(a) || !isSnippetID(b)) return false;
return parseSnippetID(a) == parseSnippetID(b);
}
static String programID() {
return getProgramID();
}
static String programID(Object o) {
return getProgramID(o);
}
static volatile String caseID_caseID;
static String caseID() { return caseID_caseID; }
static void caseID(String id) {
caseID_caseID = id;
}
public static boolean isSnippetID(String s) {
try {
parseSnippetID(s);
return true;
} catch (RuntimeException e) {
return false;
}
}
public static long parseSnippetID(String snippetID) {
long id = Long.parseLong(shortenSnippetID(snippetID));
if (id == 0) throw fail("0 is not a snippet ID");
return id;
}
static String mainClassNameForClassLoader(ClassLoader cl) {
return or((String) callOpt(cl, "mainClassName"), "main");
}
static Class loadClassFromClassLoader_orNull(ClassLoader cl, String name) {
try {
return cl == null ? null : cl.loadClass(name);
} catch (ClassNotFoundException e) {
return null;
}
}
static Map vm_generalWeakSubMap(Object name) {
synchronized(vm_generalMap()) {
Map map = (Map) (vm_generalMap_get(name));
if (map == null)
vm_generalMap_put(name, map = newWeakMap());
return map;
}
}
static AutoCloseable tempSetThreadLocalIfNecessary(ThreadLocal tl, A a) {
if (tl == null) return null;
A prev = tl.get();
if (eq(prev, a)) return null;
tl.set(a);
return new AutoCloseable() { public String toString() { return "tl.set(prev);"; } public void close() throws Exception { tl.set(prev); }};
}
static void addAll(Collection c, Iterable b) {
if (c != null && b != null) for (A a : b) c.add(a);
}
static boolean addAll(Collection c, Collection b) {
return c != null && b != null && c.addAll(b);
}
static boolean addAll(Collection c, B... b) {
return c != null && b != null && c.addAll(Arrays.asList(b));
}
static Map addAll(Map a, Map extends A,? extends B> b) {
if (a != null && b != null) a.putAll(b);
return a;
}
static Set vm_generalWeakSet(Object name) {
synchronized(vm_generalMap()) {
Set set = (Set) (vm_generalMap_get(name));
if (set == null)
vm_generalMap_put(name, set = newWeakHashSet());
return set;
}
}
static String htmlencode_noQuotes(String s) {
if (s == null) return "";
int n = s.length();
StringBuilder out = null;
for (int i = 0; i < n; i++) {
char c = s.charAt(i);
if (c == '<') {
if (out == null) out = new StringBuilder(Math.max(16, n)).append(takeFirst(i, s));
out
.append("<");
}
else if (c == '>') {
if (out == null) out = new StringBuilder(Math.max(16, n)).append(takeFirst(i, s));
out
.append(">");
}
else if (c > 127 || c == '&') {
int cp = s.codePointAt(i);
if (out == null) out = new StringBuilder(Math.max(16, n)).append(takeFirst(i, s));
out
.append("");
out.append(intToHex_flexLength(cp));
out.append(';');
i += Character.charCount(cp)-1;
} else
{ if (out != null) out.append(c); }
}
return out == null ? s : out.toString();
}
static List cloneSubList(List l, int startIndex, int endIndex) {
return newSubList(l, startIndex, endIndex);
}
static List cloneSubList(List l, int startIndex) {
return newSubList(l, startIndex);
}
static void removeSubList(List l, int from, int to) {
if (l != null) subList(l, from, to).clear();
}
static void removeSubList(List l, int from) {
if (l != null) subList(l, from).clear();
}
static String shortenSnippetID(String snippetID) {
if (snippetID.startsWith("#"))
snippetID = snippetID.substring(1);
String httpBlaBla = "http://tinybrain.de/";
if (snippetID.startsWith(httpBlaBla))
snippetID = snippetID.substring(httpBlaBla.length());
return "" + parseLong(snippetID);
}
static Map newWeakMap() {
return newWeakHashMap();
}
static Set newWeakHashSet() {
return synchroWeakHashSet();
}
static List takeFirst(List l, int n) {
return l(l) <= n ? l : newSubListOrSame(l, 0, n);
}
static List takeFirst(int n, List l) {
return takeFirst(l, n);
}
static String takeFirst(int n, String s) { return substring(s, 0, n); }
static String takeFirst(String s, int n) { return substring(s, 0, n); }
static CharSequence takeFirst(int n, CharSequence s) { return subCharSequence(s, 0, n); }
static List takeFirst(int n, Iterator it) {
if (it == null) return null;
List l = new ArrayList();
for (int _repeat_0 = 0; _repeat_0 < n; _repeat_0++) { if (it.hasNext()) l.add(it.next()); else break; }
return l;
}
static List takeFirst(int n, Iterable i) {
if (i == null) return null;
return i == null ? null : takeFirst(n, i.iterator());
}
static List takeFirst(int n, IterableIterator i) {
return takeFirst(n, (Iterator) i);
}
static int[] takeFirst(int n, int[] a) { return takeFirstOfIntArray(n, a); }
static short[] takeFirst(int n, short[] a) { return takeFirstOfShortArray(n, a); }
static byte[] takeFirst(int n, byte[] a) { return takeFirstOfByteArray(n, a); }
static byte[] takeFirst(byte[] a, int n) { return takeFirstOfByteArray(n, a); }
static double[] takeFirst(int n, double[] a) { return takeFirstOfDoubleArray(n, a); }
static double[] takeFirst(double[] a, int n) { return takeFirstOfDoubleArray(n, a); }
static String intToHex_flexLength(int i) {
return Integer.toHexString(i);
}
static List newSubList(List l, int startIndex, int endIndex) {
return cloneList(subList(l, startIndex, endIndex));
}
static List newSubList(List l, int startIndex) {
return cloneList(subList(l, startIndex));
}
static List subList(List l, int startIndex) {
return subList(l, startIndex, l(l));
}
static List subList(int startIndex, List l) {
return subList(l, startIndex);
}
static List subList(int startIndex, int endIndex, List l) {
return subList(l, startIndex, endIndex);
}
static List subList(List l, int startIndex, int endIndex) {
if (l == null) return null;
int n = l(l);
startIndex = Math.max(0, startIndex);
endIndex = Math.min(n, endIndex);
if (startIndex > endIndex) return ll();
if (startIndex == 0 && endIndex == n) return l;
return l.subList(startIndex, endIndex);
}
static List subList(List l, IntRange r) {
return subList(l, r.start, r.end);
}
static long parseLong(String s) {
if (empty(s)) return 0;
return Long.parseLong(dropSuffix("L", s));
}
static long parseLong(Object s) {
return Long.parseLong((String) s);
}
static Set synchroWeakHashSet() {
return Collections.newSetFromMap((Map) newWeakHashMap());
}
static List newSubListOrSame(List l, int startIndex) {
return newSubListOrSame(l, startIndex, l(l));
}
static List newSubListOrSame(List l, int startIndex, int endIndex) {
if (l == null) return null;
int n = l(l);
startIndex = max(0, startIndex);
endIndex = min(n, endIndex);
if (startIndex >= endIndex) return ll();
if (startIndex == 0 && endIndex == n) return l;
return cloneList(l.subList(startIndex, endIndex));
}
static List newSubListOrSame(List l, IntRange r) {
return newSubListOrSame(l, r.start, r.end);
}
static CharSequence subCharSequence(CharSequence s, int x) {
return subCharSequence(s, x, s == null ? 0 : s.length());
}
static CharSequence subCharSequence(CharSequence s, int x, int y) {
if (s == null) return null;
if (x < 0) x = 0;
if (x >= s.length()) return "";
if (y < x) y = x;
if (y > s.length()) y = s.length();
return s.subSequence(x, y);
}
static int[] takeFirstOfIntArray(int[] b, int n) {
return subIntArray(b, 0, n);
}
static int[] takeFirstOfIntArray(int n, int[] b) {
return takeFirstOfIntArray(b, n);
}
static short[] takeFirstOfShortArray(short[] b, int n) {
return subShortArray(b, 0, n);
}
static short[] takeFirstOfShortArray(int n, short[] b) {
return takeFirstOfShortArray(b, n);
}
static byte[] takeFirstOfByteArray(byte[] b, int n) {
return subByteArray(b, 0, n);
}
static byte[] takeFirstOfByteArray(int n, byte[] b) {
return takeFirstOfByteArray(b, n);
}
static double[] takeFirstOfDoubleArray(double[] b, int n) {
return subDoubleArray(b, 0, n);
}
static double[] takeFirstOfDoubleArray(int n, double[] b) {
return takeFirstOfDoubleArray(b, n);
}
static String dropSuffix(String suffix, String s) {
return nempty(suffix) && endsWith(s, suffix) ? s.substring(0, l(s)-l(suffix)) : s;
}
static int[] subIntArray(int[] b, int start) {
return subIntArray(b, start, l(b));
}
static int[] subIntArray(int[] b, int start, int end) {
start = max(start, 0); end = min(end, l(b));
if (start == 0 && end == l(b)) return b;
if (start >= end) return new int[0];
int[] x = new int[end-start];
System.arraycopy(b, start, x, 0, end-start);
return x;
}
static int[] subIntArray(int[] a, IntRange r) {
return r == null ? null : subIntArray(a, r.start, r.end);
}
static short[] subShortArray(short[] b, int start, int end) {
start = max(start, 0); end = min(end, l(b));
if (start == 0 && end == l(b)) return b;
if (start >= end) return new short[0];
short[] x = new short[end-start];
System.arraycopy(b, start, x, 0, end-start);
return x;
}
static byte[] subByteArray(byte[] b, int start) {
return subByteArray(b, start, l(b));
}
static byte[] subByteArray(byte[] b, int start, int end) {
start = max(start, 0); end = min(end, l(b));
if (start == 0 && end == l(b)) return b;
if (start >= end) return new byte[0];
byte[] x = new byte[end-start];
System.arraycopy(b, start, x, 0, end-start);
return x;
}
static byte[] subByteArray(byte[] b, IntRange r) {
return r == null ? null : subByteArray(b, r.start, r.end);
}
static double[] subDoubleArray(double[] b, int start) { return subDoubleArray(b, start, l(b)); }
static double[] subDoubleArray(double[] b, int start, int end) {
start = max(start, 0); end = min(end, l(b));
if (start == 0 && end == l(b)) return b;
if (start >= end) return new double[0];
double[] x = new double[end-start];
System.arraycopy(b, start, x, 0, end-start);
return x;
}
static boolean endsWith(String a, String b) {
return a != null && a.endsWith(b);
}
static boolean endsWith(String a, char c) {
return nempty(a) && lastChar(a) == c;
}
static boolean endsWith(String a, String b, Matches m) {
if (!endsWith(a, b)) return false;
m.m = new String[] {dropLast(l(b), a)};
return true;
}
static char lastChar(String s) {
return empty(s) ? '\0' : s.charAt(l(s)-1);
}
static A[] dropLast(A[] a) { return dropLast(a, 1); }
static A[] dropLast(A[] a, int n) {
if (a == null) return null;
n = Math.min(n, a.length);
A[] b = arrayOfSameType(a, a.length-n);
System.arraycopy(a, 0, b, 0, b.length);
return b;
}
static List dropLast(List l) {
return subList(l, 0, l(l)-1);
}
static List dropLast(int n, List l) {
return subList(l, 0, l(l)-n);
}
static List dropLast(Iterable l) {
return dropLast(asList(l));
}
static String dropLast(String s) {
return substring(s, 0, l(s)-1);
}
static String dropLast(String s, int n) {
return substring(s, 0, l(s)-n);
}
static String dropLast(int n, String s) {
return dropLast(s, n);
}
static A[] arrayOfSameType(A[] a, int n) {
return newObjectArrayOfSameType(a, n);
}
static A[] newObjectArrayOfSameType(A[] a) { return newObjectArrayOfSameType(a, a.length); }
static A[] newObjectArrayOfSameType(A[] a, int n) {
return (A[]) Array.newInstance(a.getClass().getComponentType(), n);
}
// immutable, has strong refs
// Do not run in a synchronized block - it goes wrong in the presence
// of elaborate classloaders (like in Gazelle BEA)
// see #1102990 and #1102991
final static class _MethodCache {
final Class c;
final HashMap> cache = new HashMap();
_MethodCache(Class c) {
this.c = c; _init(); }
void _init() {
Class _c = c;
Module myModule = getClass().getModule();
boolean anyHiddenClasses = false;
while (_c != null) {
boolean exported = classIsExportedTo(_c, myModule);
if (!exported)
anyHiddenClasses = true;
else
for (Method m : _c.getDeclaredMethods())
if ((anyHiddenClasses || !isAbstract(m))
&& !reflection_isForbiddenMethod(m))
multiMapPut(cache, m.getName(), makeAccessible(m));
_c = _c.getSuperclass();
}
// add default methods - this might lead to a duplication
// because the overridden method is also added, but it's not
// a problem except for minimal performance loss.
// If any classes in the hierarchy were inaccessible, we add
// all interface methods (see test_callForbiddenMethodByReflection for a test)
for (Class intf : allInterfacesImplementedBy(c))
for (Method m : intf.getDeclaredMethods())
if ((anyHiddenClasses || m.isDefault()) && !reflection_isForbiddenMethod(m))
multiMapPut(cache, m.getName(), makeAccessible(m));
}
// Returns only matching methods
Method findMethod(String method, Object[] args) { try {
List m = cache.get(method);
if (m == null) return null;
int n = m.size();
for (int i = 0; i < n; i++) {
Method me = m.get(i);
if (call_checkArgs(me, args, false))
return me;
}
return null;
} catch (Exception __e) { throw rethrow(__e); } }
Method findStaticMethod(String method, Object[] args) { try {
List m = cache.get(method);
if (m == null) return null;
int n = m.size();
for (int i = 0; i < n; i++) {
Method me = m.get(i);
if (isStaticMethod(me) && call_checkArgs(me, args, false))
return me;
}
return null;
} catch (Exception __e) { throw rethrow(__e); } }
}
static abstract class VF1 implements IVF1 {
public abstract void get(A a);
}
static class OKOrError implements IF0 {
A value;
final public Throwable getError(){ return error(); }
public Throwable error() { return error; }
Throwable error;
OKOrError() {}
OKOrError(A value) {
this.value = value;}
OKOrError(boolean dummy, Throwable error) {
this.error = error; assertNotNull(error); }
final boolean isOK(){ return ok(); }
boolean ok() { return error == null; }
public String toString() {
return ok()
? /*"OK: " +*/ str(value)
: "Error: " + str(error);
}
public A get() { return !ok() ? null : value; }
public A getMandatory() { if (!ok()) throw rethrow(error); return value; }
static OKOrError ok(A a) { return new OKOrError(a); }
static OKOrError error(Throwable error) { return new OKOrError(false, error); }
}
static class Matches {
String[] m;
Matches() {}
Matches(String... m) {
this.m = m;}
String get(int i) { return i < m.length ? m[i] : null; }
String unq(int i) { return unquote(get(i)); }
String tlc(int i) { return unq(i).toLowerCase(); }
boolean bool(int i) { return "true".equals(unq(i)); }
String rest() { return m[m.length-1]; } // for matchStart
int psi(int i) { return Integer.parseInt(unq(i)); }
public String toString() { return "Matches(" + joinWithComma(quoteAll(asList(m))) + ")"; }
public int hashCode() { return _hashCode(toList(m)); }
public boolean equals(Object o) { return o instanceof Matches && arraysEqual(m, ((Matches) o).m); }
}
// for the version with MasterSymbol (used WAY back in "Smart Bot"!) see #1010608
static class Symbol implements CharSequence {
String text;
Symbol() {}
Symbol(String text, boolean dummy) {
this.text = text;} // weird signature to prevent accidental calling
public int hashCode() { return _hashCode(text); }
public String toString() { return text; }
public boolean equals(Object o) {
return this == o;
}
// implementation of CharSequence methods
public int length() { return text.length(); }
public char charAt(int index) { return text.charAt(index); }
public CharSequence subSequence(int start, int end) {
return text.substring(start, end);
}
}
static class Var implements IVar, ISetter {
Var() {}
Var(A v) {
this.v = v;}
A v; // you can access this directly if you use one thread
public synchronized void set(A a) {
if (v != a) {
v = a;
notifyAll();
}
}
public synchronized A get() { return v; }
public synchronized boolean has() { return v != null; }
public void clear() { set(null); }
public String toString() { return str(this.get()); }
}
static class G22Utils {
final public G22Utils setBackgroundProcessesUI(BackgroundProcessesUI backgroundProcessesUI){ return backgroundProcessesUI(backgroundProcessesUI); }
public G22Utils backgroundProcessesUI(BackgroundProcessesUI backgroundProcessesUI) { this.backgroundProcessesUI = backgroundProcessesUI; return this; } final public BackgroundProcessesUI getBackgroundProcessesUI(){ return backgroundProcessesUI(); }
public BackgroundProcessesUI backgroundProcessesUI() { return backgroundProcessesUI; }
BackgroundProcessesUI backgroundProcessesUI;
final public G22Utils setModule(Enterable module){ return module(module); }
public G22Utils module(Enterable module) { this.module = module; return this; } final public Enterable getModule(){ return module(); }
public Enterable module() { return module; }
Enterable module;
final public G22Utils setMasterStuff(G22MasterStuff masterStuff){ return masterStuff(masterStuff); }
public G22Utils masterStuff(G22MasterStuff masterStuff) { this.masterStuff = masterStuff; return this; } final public G22MasterStuff getMasterStuff(){ return masterStuff(); }
public G22MasterStuff masterStuff() { return masterStuff; }
G22MasterStuff masterStuff;
final public G22Utils setConcepts(Concepts concepts){ return concepts(concepts); }
public G22Utils concepts(Concepts concepts) { this.concepts = concepts; return this; } final public Concepts getConcepts(){ return concepts(); }
public Concepts concepts() { return concepts; }
Concepts concepts;
final public CombinedStringifier getStringifier(){ return stringifier(); }
public CombinedStringifier stringifier() { return stringifier; }
CombinedStringifier stringifier = new CombinedStringifier(
o -> o instanceof BufferedImage ? "Image (" + ((BufferedImage) o).getWidth() + "*" + ((BufferedImage) o).getHeight() + " px)" : null
);
ImageSurface stdImageSurface() {
var is = pixelatedImageSurface().setAutoZoomToDisplay(true).repaintInThread(false);
is.specialPurposed = true;
new ImageSurface_PositionToolTip(is);
return is;
}
ImageSurface stdImageSurface(MakesBufferedImage img) { return stdImageSurface(toBufferedImage(img)); }
ImageSurface stdImageSurface(BufferedImage img) {
var is = stdImageSurface();
is.setImage(img);
return is;
}
String stringify(Object o) { return stringifier.toString(o); }
transient Set> onSettingUpParser;
public G22Utils onSettingUpParser(IVF1 f) { onSettingUpParser = createOrAddToSyncLinkedHashSet(onSettingUpParser, f); return this; }
public G22Utils removeSettingUpParserListener(IVF1 f) { main.remove(onSettingUpParser, f); return this; }
public void settingUpParser(GazelleV_LeftArrowScriptParser parser) { pcallFAll(onSettingUpParser, parser); }
GazelleV_LeftArrowScriptParser leftArrowParser() {
GazelleV_LeftArrowScriptParser parser = new GazelleV_LeftArrowScriptParser();
parser.g22utils(this);
settingUpParser(parser);
return parser;
}
void basicParserTest() {
var parser = leftArrowParser();
print("classContainerPrefixes" , parser.classContainerPrefixes());
assertEquals(pair(1, 2), parser.parse("new Pair 1 2").get());
}
JLeftArrowScriptIDE leftArrowIDE() {
JLeftArrowScriptIDE ide = new JLeftArrowScriptIDE();
ide.g22utils(this);
return ide;
}
File byteCodePath() {
return assertNotNull(getBytecodePathForClass(this));
}
ClassNameResolver classNameResolver_cache;
ClassNameResolver classNameResolver() { if (classNameResolver_cache == null) classNameResolver_cache = classNameResolver_load(); return classNameResolver_cache;}
ClassNameResolver classNameResolver_load() {
return new ClassNameResolver().byteCodePath(byteCodePath()).init();
}
File databasesMotherDir() {
return javaxDataDir("Gazelle-22");
}
AutoCloseable enter() { return module == null ? null : module.enter(); }
String defaultDBName() { return "Default"; }
File lastOpenedDBFile() {
return newFile(databasesMotherDir(), "Last Opened");
}
String dbToOpen() {
String name = loadTextFile(lastOpenedDBFile());
if (nempty(name) && fileExists(newFile(databasesMotherDir(), name)))
return name;
return defaultDBName();
}
void openedDB(File dbDir) {
if (sameFile(databasesMotherDir(), dirOfFile(dbDir)))
saveTextFile(lastOpenedDBFile(), fileName(dbDir));
}
// e.g. for an image file
List labelsForFile(File file) {
if (file == null) return null;
File labelsFile = appendToFileName(file, ".labels");
List labels = tlft(loadTextFile(labelsFile));
return map(__56 -> getLabel(__56), labels);
}
File labelsFile(File file) {
if (file == null) return null;
return appendToFileName(file, ".labels");
}
void setLabelsForFile(File file, List labels) {
List list = map(labels, label -> label.name);
File f = labelsFile(file);
saveTextFile(f, lines(list));
print("Saved " + nLabels(list) + " (" + joinWithComma(list) + ") to " + f);
}
G22Label getLabel(String name) {
if (empty(name)) return null;
if (containsNewLine(name)) throw fail("No newlines in label names allowed: " + name);
return uniqCI(concepts, G22Label.class, "name", name);
}
File fileInDbDir(String name) { return newFile(conceptsDir(concepts), name); }
}
static class MultiMap {
Map> data = new HashMap>();
int fullSize;
MultiMap() {}
MultiMap(boolean useTreeMap) { if (useTreeMap) data = new TreeMap(); }
MultiMap(MultiMap map) { putAll(map); }
MultiMap(Map> data) {
this.data = data;}
void put(A key, B value) { synchronized(data) {
List list = data.get(key);
if (list == null)
data.put(key, list = _makeEmptyList());
list.add(value);
++fullSize;
}}
void add(A key, B value) { put(key, value); }
void addAll(A key, Collection values) { putAll(key, values); }
void addAllIfNotThere(A key, Collection values) { synchronized(data) {
for (B value : values)
setPut(key, value);
}}
void setPut(A key, B value) { synchronized(data) {
if (!containsPair(key, value))
put(key, value);
}}
boolean containsPair(A key, B value) { synchronized(data) {
return get(key).contains(value);
}}
void putAll(Collection keys, B value) { synchronized(data) {
for (A key : unnullForIteration(keys))
put(key, value);
}}
void putAll(A key, Collection values) { synchronized(data) {
if (nempty(values)) getActual(key).addAll(values);
}}
void putAll(Iterable> pairs) { synchronized(data) {
for (Pair p : unnullForIteration(pairs))
put(p.a, p.b);
}}
void removeAll(A key, Collection values) { synchronized(data) {
for (B value : values)
remove(key, value);
}}
List get(A key) { synchronized(data) {
List list = data.get(key);
return list == null ? Collections. emptyList() : list;
}}
List getOpt(A key) { synchronized(data) {
return data.get(key);
}}
List getAndClear(A key) { synchronized(data) {
List l = cloneList(data.get(key));
remove(key);
return l;
}}
// returns actual mutable live list
// creates the list if not there
List getActual(A key) { synchronized(data) {
List list = data.get(key);
if (list == null)
data.put(key, list = _makeEmptyList());
return list;
}}
void clean(A key) { synchronized(data) {
List list = data.get(key);
if (list != null && list.isEmpty()) {
fullSize -= l(list);
data.remove(key);
}
}}
Set keySet() { synchronized(data) {
return data.keySet();
}}
Set keys() { synchronized(data) {
return data.keySet();
}}
void remove(A key) { synchronized(data) {
fullSize -= l(this.getOpt(key));
data.remove(key);
}}
final void remove(Pair p){ removePair(p); }
void removePair(Pair p) {
if (p != null) remove(p.a, p.b);
}
void remove(A key, B value) { synchronized(data) {
List list = data.get(key);
if (list != null) {
if (list.remove(value))
fullSize--;
if (list.isEmpty())
data.remove(key);
}
}}
void clear() { synchronized(data) {
data.clear();
}}
boolean containsKey(A key) { synchronized(data) {
return data.containsKey(key);
}}
B getFirst(A key) { synchronized(data) {
List list = get(key);
return list.isEmpty() ? null : list.get(0);
}}
void addAll(MultiMap map) { putAll(map); }
void putAll(MultiMap map) { synchronized(data) {
for (A key : map.keySet())
putAll(key, map.get(key));
}}
void putAll(Map map) { synchronized(data) {
if (map != null) for (Map.Entry e : map.entrySet())
put(e.getKey(), e.getValue());
}}
final int keyCount(){ return keysSize(); }
int keysSize() { synchronized(data) { return l(data); }}
// full size - note: expensive operation
final int fullSize(){ return size(); }
int size() { synchronized(data) {
return fullSize;
}}
// expensive operation
List reverseGet(B b) { synchronized(data) {
List l = new ArrayList();
for (A key : data.keySet())
if (data.get(key).contains(b))
l.add(key);
return l;
}}
Map> asMap() { synchronized(data) {
return cloneMap(data);
}}
boolean isEmpty() { synchronized(data) { return data.isEmpty(); }}
// override in subclasses
List _makeEmptyList() {
return new ArrayList();
}
// returns live lists
Collection> allLists() {
synchronized(data) {
return new ArrayList(data.values());
}
}
Collection> values() { return allLists(); }
List allValues() {
return concatLists(data.values());
}
Object mutex() { return data; }
public String toString() { return "mm" + str(data); }
}
/*
* @(#)WeakHashMap.java 1.5 98/09/30
*
* Copyright 1998 by Sun Microsystems, Inc.,
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
*
* This software is the confidential and proprietary information
* of Sun Microsystems, Inc. ("Confidential Information"). You
* shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with Sun.
*/
// From https://github.com/mernst/plume-lib/blob/df0bfafc3c16848d88f4ea0ef3c8bf3367ae085e/java/src/plume/WeakHasherMap.java
static final class WeakHasherMap extends AbstractMap implements Map {
private Hasher hasher = null;
/*@Pure*/
private boolean keyEquals(Object k1, Object k2) {
return (hasher==null ? k1.equals(k2)
: hasher.equals(k1, k2));
}
/*@Pure*/
private int keyHashCode(Object k1) {
return (hasher==null ? k1.hashCode()
: hasher.hashCode(k1));
}
// The WeakKey class can't be static because it depends on the hasher.
// That in turn means that its methods can't be static.
// However, I need to be able to call the methods such as create() that
// were static in the original version of this code.
// This finesses that.
private /*@Nullable*/ WeakKey WeakKeyCreate(K k) {
if (k == null) return null;
else return new WeakKey(k);
}
private /*@Nullable*/ WeakKey WeakKeyCreate(K k, ReferenceQueue super K> q) {
if (k == null) return null;
else return new WeakKey(k, q);
}
// Cannot be a static class: uses keyHashCode() and keyEquals()
private final class WeakKey extends WeakReference {
private int hash; /* Hashcode of key, stored here since the key
may be tossed by the GC */
private WeakKey(K k) {
super(k);
hash = keyHashCode(k);
}
private /*@Nullable*/ WeakKey create(K k) {
if (k == null) return null;
else return new WeakKey(k);
}
private WeakKey(K k, ReferenceQueue super K> q) {
super(k, q);
hash = keyHashCode(k);
}
private /*@Nullable*/ WeakKey create(K k, ReferenceQueue super K> q) {
if (k == null) return null;
else return new WeakKey(k, q);
}
/* A WeakKey is equal to another WeakKey iff they both refer to objects
that are, in turn, equal according to their own equals methods */
/*@Pure*/
@Override
public boolean equals(/*@Nullable*/ Object o) {
if (o == null) return false; // never happens
if (this == o) return true;
// This test is illegal because WeakKey is a generic type,
// so use the getClass hack below instead.
// if (!(o instanceof WeakKey)) return false;
if (!(o.getClass().equals(WeakKey.class))) return false;
Object t = this.get();
@SuppressWarnings("unchecked")
Object u = ((WeakKey)o).get();
if ((t == null) || (u == null)) return false;
if (t == u) return true;
return keyEquals(t, u);
}
/*@Pure*/
@Override
public int hashCode() {
return hash;
}
}
/* Hash table mapping WeakKeys to values */
private HashMap hash;
/* Reference queue for cleared WeakKeys */
private ReferenceQueue super K> queue = new ReferenceQueue();
/* Remove all invalidated entries from the map, that is, remove all entries
whose keys have been discarded. This method should be invoked once by
each public mutator in this class. We don't invoke this method in
public accessors because that can lead to surprising
ConcurrentModificationExceptions. */
@SuppressWarnings("unchecked")
private void processQueue() {
WeakKey wk;
while ((wk = (WeakKey)queue.poll()) != null) { // unchecked cast
hash.remove(wk);
}
}
/* -- Constructors -- */
/**
* Constructs a new, empty WeakHashMap
with the given
* initial capacity and the given load factor.
*
* @param initialCapacity the initial capacity of the
* WeakHashMap
*
* @param loadFactor the load factor of the WeakHashMap
*
* @throws IllegalArgumentException If the initial capacity is less than
* zero, or if the load factor is
* nonpositive
*/
public WeakHasherMap(int initialCapacity, float loadFactor) {
hash = new HashMap(initialCapacity, loadFactor);
}
/**
* Constructs a new, empty WeakHashMap
with the given
* initial capacity and the default load factor, which is
* 0.75
.
*
* @param initialCapacity the initial capacity of the
* WeakHashMap
*
* @throws IllegalArgumentException If the initial capacity is less than
* zero
*/
public WeakHasherMap(int initialCapacity) {
hash = new HashMap(initialCapacity);
}
/**
* Constructs a new, empty WeakHashMap
with the default
* capacity and the default load factor, which is 0.75
.
*/
public WeakHasherMap() {
hash = new HashMap();
}
/**
* Constructs a new, empty WeakHashMap
with the default
* capacity and the default load factor, which is 0.75
.
* The WeakHashMap
uses the specified hasher for hashing
* keys and comparing them for equality.
* @param h the Hasher to use when hashing values for this map
*/
public WeakHasherMap(Hasher h) {
hash = new HashMap();
hasher = h;
}
/* -- Simple queries -- */
/**
* Returns the number of key-value mappings in this map.
* Note: In contrast to most implementations of the
* Map
interface, the time required by this operation is
* linear in the size of the map.
*/
/*@Pure*/
@Override
public int size() {
return entrySet().size();
}
/**
* Returns true
if this map contains no key-value mappings.
*/
/*@Pure*/
@Override
public boolean isEmpty() {
return entrySet().isEmpty();
}
/**
* Returns true
if this map contains a mapping for the
* specified key.
*
* @param key the key whose presence in this map is to be tested
*/
/*@Pure*/
@Override
public boolean containsKey(Object key) {
@SuppressWarnings("unchecked")
K kkey = (K) key;
return hash.containsKey(WeakKeyCreate(kkey));
}
/* -- Lookup and modification operations -- */
/**
* Returns the value to which this map maps the specified key
.
* If this map does not contain a value for this key, then return
* null
.
*
* @param key the key whose associated value, if any, is to be returned
*/
/*@Pure*/
@Override
public /*@Nullable*/ V get(Object key) { // type of argument is Object, not K
@SuppressWarnings("unchecked")
K kkey = (K) key;
return hash.get(WeakKeyCreate(kkey));
}
/**
* Updates this map so that the given key
maps to the given
* value
. If the map previously contained a mapping for
* key
then that mapping is replaced and the previous value is
* returned.
*
* @param key the key that is to be mapped to the given
* value
* @param value the value to which the given key
is to be
* mapped
*
* @return the previous value to which this key was mapped, or
* null
if if there was no mapping for the key
*/
@Override
public V put(K key, V value) {
processQueue();
return hash.put(WeakKeyCreate(key, queue), value);
}
/**
* Removes the mapping for the given key
from this map, if
* present.
*
* @param key the key whose mapping is to be removed
*
* @return the value to which this key was mapped, or null
if
* there was no mapping for the key
*/
@Override
public V remove(Object key) { // type of argument is Object, not K
processQueue();
@SuppressWarnings("unchecked")
K kkey = (K) key;
return hash.remove(WeakKeyCreate(kkey));
}
/**
* Removes all mappings from this map.
*/
@Override
public void clear() {
processQueue();
hash.clear();
}
/* -- Views -- */
/* Internal class for entries */
// This can't be static, again because of dependence on hasher.
@SuppressWarnings("TypeParameterShadowing")
private final class Entry implements Map.Entry {
private Map.Entry ent;
private K key; /* Strong reference to key, so that the GC
will leave it alone as long as this Entry
exists */
Entry(Map.Entry ent, K key) {
this.ent = ent;
this.key = key;
}
/*@Pure*/
@Override
public K getKey() {
return key;
}
/*@Pure*/
@Override
public V getValue() {
return ent.getValue();
}
@Override
public V setValue(V value) {
return ent.setValue(value);
}
/*@Pure*/
private boolean keyvalEquals(K o1, K o2) {
return (o1 == null) ? (o2 == null) : keyEquals(o1, o2);
}
/*@Pure*/
private boolean valEquals(V o1, V o2) {
return (o1 == null) ? (o2 == null) : o1.equals(o2);
}
/*@Pure*/
@SuppressWarnings("NonOverridingEquals")
public boolean equals(Map.Entry e /* Object o*/) {
// if (! (o instanceof Map.Entry)) return false;
// Map.Entry e = (Map.Entry)o;
return (keyvalEquals(key, e.getKey())
&& valEquals(getValue(), e.getValue()));
}
/*@Pure*/
@Override
public int hashCode() {
V v;
return (((key == null) ? 0 : keyHashCode(key))
^ (((v = getValue()) == null) ? 0 : v.hashCode()));
}
}
/* Internal class for entry sets */
private final class EntrySet extends AbstractSet> {
Set> hashEntrySet = hash.entrySet();
@Override
public Iterator> iterator() {
return new Iterator>() {
Iterator> hashIterator = hashEntrySet.iterator();
Map.Entry next = null;
@Override
public boolean hasNext() {
while (hashIterator.hasNext()) {
Map.Entry ent = hashIterator.next();
WeakKey wk = ent.getKey();
K k = null;
if ((wk != null) && ((k = wk.get()) == null)) {
/* Weak key has been cleared by GC */
continue;
}
next = new Entry(ent, k);
return true;
}
return false;
}
@Override
public Map.Entry next() {
if ((next == null) && !hasNext())
throw new NoSuchElementException();
Map.Entry e = next;
next = null;
return e;
}
@Override
public void remove() {
hashIterator.remove();
}
};
}
/*@Pure*/
@Override
public boolean isEmpty() {
return !(iterator().hasNext());
}
/*@Pure*/
@Override
public int size() {
int j = 0;
for (Iterator> i = iterator(); i.hasNext(); i.next()) j++;
return j;
}
@Override
public boolean remove(Object o) {
processQueue();
if (!(o instanceof Map.Entry,?>)) return false;
@SuppressWarnings("unchecked")
Map.Entry e = (Map.Entry)o; // unchecked cast
Object ev = e.getValue();
WeakKey wk = WeakKeyCreate(e.getKey());
Object hv = hash.get(wk);
if ((hv == null)
? ((ev == null) && hash.containsKey(wk)) : hv.equals(ev)) {
hash.remove(wk);
return true;
}
return false;
}
/*@Pure*/
@Override
public int hashCode() {
int h = 0;
for (Iterator> i = hashEntrySet.iterator(); i.hasNext(); ) {
Map.Entry ent = i.next();
WeakKey wk = ent.getKey();
Object v;
if (wk == null) continue;
h += (wk.hashCode()
^ (((v = ent.getValue()) == null) ? 0 : v.hashCode()));
}
return h;
}
}
private /*@Nullable*/ Set> entrySet = null;
/**
* Returns a Set
view of the mappings in this map.
*/
/*@SideEffectFree*/
@Override
public Set> entrySet() {
if (entrySet == null) entrySet = new EntrySet();
return entrySet;
}
// find matching key
K findKey(Object key) {
processQueue();
K kkey = (K) key;
// TODO: use replacement for HashMap to avoid reflection
WeakKey wkey = WeakKeyCreate(kkey);
WeakKey found = hashMap_findKey(hash, wkey);
return found == null ? null : found.get();
}
}
static class Fail extends RuntimeException implements IFieldsToList{
Object[] objects;
Fail() {}
Fail(Object... objects) {
this.objects = objects;}public Object[] _fieldsToList() { return new Object[] {objects}; }
Fail(Throwable cause, Object... objects) {
super(cause);
this.objects = objects;
}
public String toString() { return joinNemptiesWithColon("Fail", commaCombine(getCause(), objects)); }
}
static class Pair implements Comparable> {
A a;
B b;
Pair() {}
Pair(A a, B b) {
this.b = b;
this.a = a;}
public int hashCode() {
return hashCodeFor(a) + 2*hashCodeFor(b);
}
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Pair)) return false;
Pair t = (Pair) o;
return eq(a, t.a) && eq(b, t.b);
}
public String toString() {
return "<" + a + ", " + b + ">";
}
public int compareTo(Pair p) {
if (p == null) return 1;
int i = ((Comparable) a).compareTo(p.a);
if (i != 0) return i;
return ((Comparable) b).compareTo(p.b);
}
}
final static class Rect implements IFieldsToList{
static final String _fieldOrder = "x y w h";
int x;
int y;
int w;
int h;
Rect() {}
Rect(int x, int y, int w, int h) {
this.h = h;
this.w = w;
this.y = y;
this.x = x;}
public boolean equals(Object o) {
if (!(o instanceof Rect)) return false;
Rect __1 = (Rect) o;
return x == __1.x && y == __1.y && w == __1.w && h == __1.h;
}
public int hashCode() {
int h = 2543108;
h = boostHashCombine(h, _hashCode(x));
h = boostHashCombine(h, _hashCode(y));
h = boostHashCombine(h, _hashCode(w));
h = boostHashCombine(h, _hashCode(h));
return h;
}
public Object[] _fieldsToList() { return new Object[] {x, y, w, h}; }
Rect(Rectangle r) {
x = r.x;
y = r.y;
w = r.width;
h = r.height;
}
Rect(Pt p, int w, int h) {
this.h = h;
this.w = w; x = p.x; y = p.y; }
Rect(Rect r) { x = r.x; y = r.y; w = r.w; h = r.h; }
Rectangle getRectangle() {
return new Rectangle(x, y, w, h);
}
public String toString() {
return x + "," + y + " / " + w + "," + h;
}
int x1() { return x; }
int y1() { return y; }
int x2() { return x + w; }
int y2() { return y + h; }
boolean contains(Pt p) {
return contains(p.x, p.y);
}
boolean contains(int _x, int _y) {
return _x >= x && _y >= y && _x < x+w && _y < y+h;
}
boolean contains(Rectangle r) {
return rectContains(this, r);
}
boolean empty() { return w <= 0 || h <= 0; }
int getWidth() { return w; }
int getHeight() { return h; }
}
static class Pt implements Comparable, IDoublePt {
int x, y;
Pt() {}
Pt(Point p) {
x = p.x;
y = p.y;
}
Pt(int x, int y) {
this.y = y;
this.x = x;}
Point getPoint() {
return new Point(x, y);
}
public boolean equals(Object o) {
return o instanceof Pt && x == ((Pt) o).x && y == ((Pt) o).y;
}
public int hashCode() {
return boostHashCombine(x, y);
}
// compare in scan order
public int compareTo(Pt p) {
if (y != p.y) return cmp(y, p.y);
return cmp(x, p.x);
}
public String toString() {
return x + ", " + y;
}
double length() { return sqrt(x*x+y*y); }
Pt minus(Pt p) { return ptMinus(this, p); }
public double x_double() { return x; }
public double y_double() { return y; }
}
static abstract class F0 {
abstract A get();
}
static abstract class F1 {
abstract B get(A a);
}
// you still need to implement hasNext() and next()
static abstract class IterableIterator implements Iterator, Iterable {
public Iterator iterator() {
return this;
}
public void remove() {
unsupportedOperation();
}
}
static class G22LAScriptIDE implements Swingable {
final public G22LAScriptIDE setG22utils(G22Utils g22utils){ return g22utils(g22utils); }
public G22LAScriptIDE g22utils(G22Utils g22utils) { this.g22utils = g22utils; return this; } final public G22Utils getG22utils(){ return g22utils(); }
public G22Utils g22utils() { return g22utils; }
G22Utils g22utils;
final public G22LAScriptIDE setNoScriptSelectedMsg(String noScriptSelectedMsg){ return noScriptSelectedMsg(noScriptSelectedMsg); }
public G22LAScriptIDE noScriptSelectedMsg(String noScriptSelectedMsg) { this.noScriptSelectedMsg = noScriptSelectedMsg; return this; } final public String getNoScriptSelectedMsg(){ return noScriptSelectedMsg(); }
public String noScriptSelectedMsg() { return noScriptSelectedMsg; }
String noScriptSelectedMsg = "Please select or create a script to edit it";
A script;
transient SingleComponentPanel scp;
transient JLeftArrowScriptIDE[] ides;
transient JTabbedPane tabs;
abstract class Mode {
String name;
final public boolean getEditable(){ return editable(); }
public boolean editable() { return editable; }
boolean editable = false;
Mode(String name, boolean editable) {
this.editable = editable;
this.name = name;}
IVarWithNotify scriptVar_cache;
IVarWithNotify scriptVar() { if (scriptVar_cache == null) scriptVar_cache = scriptVar_load(); return scriptVar_cache;}
abstract IVarWithNotify scriptVar_load();
void addButtons(JPanel panel) {}
public String toString() { return name; }
String tabName() { return scriptVar().has() ? name : "Not " + firstToLower(name); }
}
class ModeClearedForAutoRun extends Mode {
ModeClearedForAutoRun() { super("Cleared for auto-run", false); }
IVarWithNotify scriptVar_load() {
var var = new VirtualVar(
() -> script.codeForAutoRun(),
null /*text -> script.setClearedForAutoRun(text == null ?: new ClearForAutoRun(text))*/);
addWeakChangeListener(script.varClearedForAutoRun(), var);
return var;
}
void addButtons(JPanel panel) {
panel.add(jbutton("Forget auto-run code", runnableThread(new Runnable() { public void run() { try { forgetAutoRunCode();
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "forgetAutoRunCode();"; }})));
}
}
class ModeSaved extends Mode {
ModeSaved() { super("Saved", false); }
IVarWithNotify scriptVar_load() {
return getterVarOnly(script.varText());
}
void addButtons(JPanel panel) {
panel.add(jbutton("Clear for auto-run", runnableThread(new Runnable() { public void run() { try { clearForAutoRun();
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "clearForAutoRun();"; }})));
panel.add(jbutton("Forget code", runnableThread(new Runnable() { public void run() { try { forgetSaved();
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "forgetSaved();"; }})));
}
}
class ModeEdit extends Mode {
ModeEdit() { super("Editing", true); }
IVarWithNotify scriptVar_load() {
var var = new VirtualVar(
() -> script.textForEditing(),
text -> script.receiveEditingText(text)
);
addWeakChangeListener(script, var);
return var;
}
void addButtons(JPanel panel) {
panel.add(jbutton("Save", runnableThread(new Runnable() { public void run() { try { saveEdit();
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "saveEdit();"; }})));
panel.add(jbutton("Discard changes", runnableThread(new Runnable() { public void run() { try { discardEdit();
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "discardEdit();"; }})));
}
}
transient ModeEdit modeEdit = new ModeEdit();
transient ModeSaved modeSaved = new ModeSaved();
transient ModeClearedForAutoRun modeClearedForAutoRun = new ModeClearedForAutoRun();
transient List modes = ll(
modeEdit,
modeSaved,
modeClearedForAutoRun
);
G22LAScriptIDE(G22Utils g22utils) {
this.g22utils = g22utils;}
public JComponent visualize() {
ides = new JLeftArrowScriptIDE[l(modes)];
if (scp == null) scp = singleComponentPanel();
loadScript(script);
return scp;
}
void setScript(A script) {
if (this.script != script)
if (this.script != null)
throw fail("Can't set script after initialisation");
else
loadScript(script);
}
void loadScript(A script) {
this.script = script;
if (scp == null) return;
if (script == null)
scp.set(jcenteredlabel(noScriptSelectedMsg()));
else {
tabs = jtabs();
for (Pair __0 : iterateWithIndex(modes)) { int i = pairA(__0); Mode mode = pairB(__0);
var ide = ides[i] = g22utils.leftArrowIDE();
ide.makeParser = () -> script.makeParser();
modifyIDE(ide);
var varScript = mode.scriptVar();
ide.lvScript(varWithNotifyToLiveValue_verbose(String.class, varScript));
addTab(tabs, str(mode));
ide.visualize();
JPanel moreButtons = jline();
mode.addButtons(moreButtons);
ide.scpMoreButtons.set(moreButtons);
ide.setEditable(mode.editable());
varScript.onChangeAndNow(text ->
setTab(tabs, i, text == null ? jcenteredlabel("Empty") : wrapIDE(ide)));
}
script.onChangeAndNow(new Runnable() { public void run() { try {
for (Pair __1 : iterateWithIndex(modes))
{ int i = pairA(__1); Mode mode = pairB(__1); setTabTitle(tabs, i, mode.tabName()); }
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "for (Pair __1 : iterateWithIndex(modes))\r\n { int i = ..."; }});
setMode(modeSaved);
scp.set(tabs);
}
}
transient IF1 wrapIDE;
JComponent wrapIDE(JLeftArrowScriptIDE ide) { return wrapIDE != null ? wrapIDE.get(ide) : wrapIDE_base(ide); }
final JComponent wrapIDE_fallback(IF1 _f, JLeftArrowScriptIDE ide) { return _f != null ? _f.get(ide) : wrapIDE_base(ide); }
JComponent wrapIDE_base(JLeftArrowScriptIDE ide) {
return ide.visualize();
}
transient Set> onSettingUpIDE;
public G22LAScriptIDE onSettingUpIDE(IVF1 f) { onSettingUpIDE = createOrAddToSyncLinkedHashSet(onSettingUpIDE, f); return this; }
public G22LAScriptIDE removeSettingUpIDEListener(IVF1 f) { main.remove(onSettingUpIDE, f); return this; }
public void settingUpIDE(JLeftArrowScriptIDE ide) { pcallFAll(onSettingUpIDE, ide); }
transient IVF1 modifyIDE;
void modifyIDE(JLeftArrowScriptIDE ide) { if (modifyIDE != null) modifyIDE.get(ide); else modifyIDE_base(ide); }
final void modifyIDE_fallback(IVF1 _f, JLeftArrowScriptIDE ide) { if (_f != null) _f.get(ide); else modifyIDE_base(ide); }
void modifyIDE_base(JLeftArrowScriptIDE ide) {
ide.showTitle(false);
settingUpIDE(ide);
}
void saveEdit() {
script.completeEdit();
setMode(modeSaved);
}
JLeftArrowScriptIDE ide(Mode mode) {
if (ides == null) visualize();
return _get(ides, indexOf(modes, mode));
}
void setMode(Mode mode) {
selectTab(tabs, indexOf(modes, mode));
}
void discardEdit() {
setMode(modeSaved);
script.editingText(null);
}
void forgetSaved() {
script.setTextWithHistory(null);
}
void clearForAutoRun() {
script.clearForAutoRun();
setMode(modeClearedForAutoRun);
}
void forgetAutoRunCode() {
script.forgetAutoRunCode();
}
private void selfTest_impl() {
G22LeftArrowScript script = new G22LeftArrowScript();
setScript((A) script);
ide(modeEdit).setText("hello");
assertEqualsVerbose(null, script.text());
assertEqualsVerbose("hello", script.editedText());
saveEdit();
assertEqualsVerbose("hello", script.text());
assertEqualsVerbose(null, script.editedText());
}
static void selfTest(G22Utils g22utils) {
new G22LAScriptIDE(g22utils).selfTest_impl();
}
}
static class BetterLabel extends JLabel {
boolean autoToolTip = true;
BetterLabel() {
// Listeners given out to componentPopupMenu must not directly
// reference the outer object (-> weak map problem).
final WeakReference < BetterLabel > me = new WeakReference<>(this);
componentPopupMenu(this, BetterLabel_menuItems(me));
}
BetterLabel(String text) {
this();
this.setText(text);
}
public void setText(String text) {
super.setText(text);
if (autoToolTip)
if (!swic(text, "")) // HTML labels make super-huge, confusing tool tips
setToolTipText(nullIfEmpty(text));
}
}
// moved outside of class for GC reasons (see above)
static VF1 BetterLabel_menuItems(final WeakReference me) {
return new VF1() { public void get(JPopupMenu menu) { try {
addMenuItem(menu, "Copy text to clipboard", new Runnable() { public void run() { try {
copyTextToClipboard(me.get().getText());
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "copyTextToClipboard(me.get().getText());"; }});
} catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "addMenuItem(menu, \"Copy text to clipboard\", r {\r\n copyTextToClipboard(me..."; }};
}
public static interface IF0 {
A get();
}
static interface Hasher {
int hashCode(A a);
boolean equals(A a, A b);
}
static interface IFieldsToList {
Object[] _fieldsToList();
}
static interface IF1 {
B get(A a);
}
static class PersistableThrowable extends DynamicObject {
String className;
String msg;
String stacktrace;
PersistableThrowable() {}
PersistableThrowable(Throwable e) {
if (e == null)
className = "Crazy Null Error";
else {
className = getClassName(e).replace('/', '.');
msg = e.getMessage();
stacktrace = getStackTrace_noRecord(e);
}
}
public String toString() {
return nempty(msg) ? className + ": " + msg : className;
}
}
static interface IVF1 {
void get(A a);
}
interface IVarWithNotify extends IVar, IF0WithChangeListeners {
default IVarWithNotify onChangeAndNow(IVF1 r) {
if (r == null) return this;
onChangeAndNow(() -> r.get(get()));
return this;
}
}
static interface Swingable {
JComponent visualize();
}
interface Enterable {
AutoCloseable enter();
}
static class BackgroundProcessesUI {
Set processes = setWithNotify(syncLinkedHashSet(), () -> updateCount());
SimpleLiveValue lvCount = new SimpleLiveValue(Integer.class, 0);
static class Entry implements IFieldsToList{
static final String _fieldOrder = "name menuItem";
String name;
Entry() {}
Entry(String name) {
this.name = name;}
public boolean equals(Object o) {
if (!(o instanceof Entry)) return false;
Entry __1 = (Entry) o;
return eq(name, __1.name);
}
public int hashCode() {
int h = 67115090;
h = boostHashCombine(h, _hashCode(name));
return h;
}
public Object[] _fieldsToList() { return new Object[] {name}; }
final public Entry setMenuItem(JMenuItem menuItem){ return menuItem(menuItem); }
public Entry menuItem(JMenuItem menuItem) { this.menuItem = menuItem; return this; } final public JMenuItem getMenuItem(){ return menuItem(); }
public JMenuItem menuItem() { return menuItem; }
JMenuItem menuItem;
public String toString() { return name; }
}
JLabel shortLabel() {
var lbl = bindToolTipToTransformedLiveValue(
n -> makeToolTip(), lvCount,
simpleTransformedLiveValueLabel(n -> n2(n), lvCount));
onMouseDown_anyButton(lbl, e -> {
var l = cloneList(processes);
// make sure title is displayed fully
JPopupMenu menu = new JPopupMenu();/* {
public Dimension getMinimumSize() {
TitledBorder border = optCast TitledBorder(getBorder());
_print(+border);
ret maxDimension(super.getMinimumSize(), border?.getMinimumSize(this));
}
};*/
int n = componentCount(menu);
for (Entry a : l)
addMenuItem(menu, processToMenuItem(a));
if (componentCount(menu) != n) {
var border = jRaisedSectionBorder("Background Processes");
setBorder(menu, border);
showPopupMenu(menu, e);
var size = menu.getSize();
var borderSize = dimensionPlus(10 /* hack */, 0, border.getMinimumSize(menu));
printVars("size", size, "borderSize", borderSize);
menu.setPopupSize(maxDimension(size, borderSize));
}
});
return lbl;
}
void add(Entry process) {
processes.add(process);
}
void remove(Entry process) {
processes.remove(process);
}
void addOrRemove(boolean add, Entry process) {
if (add) add(process); else remove(process);
}
AutoCloseable tempAdd(Entry process) {
if (process == null) return null;
return main.tempAdd(processes, process);
}
void updateCount() {
lvCount.set(l(processes));
}
String makeToolTip() {
var l = cloneList(processes);
return empty(l) ? "No background processes"
: n2(l, "background process", "background processes")
+ ": " + joinWithComma(processes);
}
transient IF1 processToMenuItem;
JMenuItem processToMenuItem(Entry process) { return processToMenuItem != null ? processToMenuItem.get(process) : processToMenuItem_base(process); }
final JMenuItem processToMenuItem_fallback(IF1 _f, Entry process) { return _f != null ? _f.get(process) : processToMenuItem_base(process); }
JMenuItem processToMenuItem_base(Entry process) {
return process.getMenuItem();
}
}
static interface ISetter {
void set(A a);
}
// takes ~70 ms to set up, do it only once if possible
static class ClassNameResolver {
final public ClassNameResolver setByteCodePath(File byteCodePath){ return byteCodePath(byteCodePath); }
public ClassNameResolver byteCodePath(File byteCodePath) { this.byteCodePath = byteCodePath; return this; } final public File getByteCodePath(){ return byteCodePath(); }
public File byteCodePath() { return byteCodePath; }
File byteCodePath = byteCodePathForClass(getClass());
List importedPackages = itemPlusList("java.lang",
endingWith_dropSuffix(standardImports(), ".*"));
Set allFullyQualifiedClassNames_cache;
Set allFullyQualifiedClassNames() { if (allFullyQualifiedClassNames_cache == null) allFullyQualifiedClassNames_cache = allFullyQualifiedClassNames_load(); return allFullyQualifiedClassNames_cache;}
Set allFullyQualifiedClassNames_load() {
Set set = new HashSet();
assertNotNull(byteCodePath);
set.addAll(classNamesInJarOrDir(byteCodePath));
printVars("ClassNameResolver", "byteCodePath", byteCodePath, "classesFound" , l(set));
set.addAll(classNamesInLoadedJigsawModules());
return set;
}
ClassNameResolver init() { allFullyQualifiedClassNames(); return this; }
String findClass(String name) {
for (String pkg : importedPackages) {
String fullName = pkg + "." + name;
if (allFullyQualifiedClassNames().contains(fullName))
return fullName;
}
return null;
}
void printMe() {
printVars("ClassNameResolver", "byteCodePath", byteCodePath);
print("importedPackages", importedPackages);
}
}
static class ImageSurface extends Surface {
BufferedImage image;
double zoomX = 1, zoomY = 1, zoomFactor = 1.5;
private Rectangle selection;
List tools = new ArrayList();
// use overlays now
Object overlay; // voidfunc(Graphics2D)
List overlays = syncL();
Runnable onSelectionChange;
static boolean verbose = false;
boolean noMinimumSize = true;
String titleForUpload;
Object onZoom;
boolean specialPurposed = false; // true = don't show image changing commands in popup menu
final public ImageSurface setZoomable(boolean zoomable){ return zoomable(zoomable); }
public ImageSurface zoomable(boolean zoomable) { this.zoomable = zoomable; return this; } final public boolean getZoomable(){ return zoomable(); }
public boolean zoomable() { return zoomable; }
boolean zoomable = true;
boolean noAlpha = false; // set to true to speed up drawing if you don't use alpha
Object interpolationMode = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
Object onNewImage;
BufferedImage imageToDraw; // if you want to draw a different image
File file; // where image was loaded from
boolean autoZoomToDisplay = false; // only works 100% when not in scrollpane
final public ImageSurface setRepaintInThread(boolean repaintInThread){ return repaintInThread(repaintInThread); }
public ImageSurface repaintInThread(boolean repaintInThread) { this.repaintInThread = repaintInThread; return this; } final public boolean getRepaintInThread(){ return repaintInThread(); }
public boolean repaintInThread() { return repaintInThread; }
boolean repaintInThread = false; // after setImage, repaint in same thread
BoolVar showingVar;
Pt mousePosition;
transient Set onMousePositionChanged;
public ImageSurface onMousePositionChanged(Runnable r) { onMousePositionChanged = createOrAddToSyncLinkedHashSet(onMousePositionChanged, r); return this; }
public ImageSurface removeMousePositionChangedListener(Runnable r) { main.remove(onMousePositionChanged, r); return this; }
public void mousePositionChanged() { pcallFAll(onMousePositionChanged); }
public ImageSurface() {
this(dummyImage());
}
static BufferedImage dummyImage() {
return new RGBImage(1, 1, new int[] { 0xFFFFFF }).getBufferedImage();
}
ImageSurface(MakesBufferedImage image) {
this(image != null ? image.getBufferedImage() : dummyImage());
}
ImageSurface(BufferedImage image) {
setImage(image);
clearSurface = false;
onResize(this, () -> performAutoZoom());
bindToComponent(this, () -> performAutoZoom(), null);
componentPopupMenu2(this, ImageSurface_popupMenuMaker());
new ImageSurfaceSelector(this);
jHandleFileDrop(this, new VF1() { public void get(File f) { try { setImage(loadBufferedImage(f)) ; } catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "setImage(loadBufferedImage(f))"; }});
imageSurfaceOnHover(this, p -> {
mousePosition = p;
mousePositionChanged();
});
}
public ImageSurface(RGBImage image, double zoom) {
this(image);
setZoom(zoom);
}
// point is already in image coordinates
protected void fillPopupMenu(JPopupMenu menu, final Point point) {
if (zoomable) {
JMenuItem miZoomReset = new JMenuItem("Zoom 100%");
miZoomReset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
setZoom(1.0);
centerPoint(point);
}
});
menu.add(miZoomReset);
JMenuItem miZoomIn = new JMenuItem("Zoom in");
miZoomIn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
zoomIn(zoomFactor);
centerPoint(point);
}
});
menu.add(miZoomIn);
JMenuItem miZoomOut = new JMenuItem("Zoom out");
miZoomOut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
zoomOut(zoomFactor);
centerPoint(point);
}
});
menu.add(miZoomOut);
/*JMenuItem miZoomToWindow = new JMenuItem("Zoom to window");
miZoomToWindow.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
zoomToDisplaySize();
}
});
menu.add(miZoomToWindow);*/
menu.add(jCheckBoxMenuItem_dyn(/*"Auto-zoom to window"*/"Zoom to window",
() -> autoZoomToDisplay,
b -> { setAutoZoomToDisplay(b); }));
addMenuItem(menu, "Show full screen", new Runnable() { public void run() { try { showFullScreen() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "showFullScreen()"; }});
addMenuItem(menu, "Point: " + point.x + "," + point.y + " (image: " + w() + "*" + h() + ")", null);
menu.addSeparator();
}
if (!specialPurposed)
addMenuItem(menu, "Load image...", new Runnable() { public void run() { try { selectFile("Load image",
new VF1() { public void get(File f) { try { setImage(loadImage2(f)) ; } catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "setImage(loadImage2(f))"; }}) ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "selectFile(\"Load image\",\r\n new VF1() { public void get(File f) c..."; }});
addMenuItem(menu, "Save image...", new Runnable() { public void run() { try { saveImage() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "saveImage()"; }});
addMenuItem(menu, "Upload image...", new Runnable() { public void run() { try { uploadTheImage() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "uploadTheImage()"; }});
addMenuItem(menu, "Copy image to clipboard", new Runnable() { public void run() { try { copyImageToClipboard(getImage()) ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "copyImageToClipboard(getImage())"; }});
if (!specialPurposed) {
addMenuItem(menu, "Paste image from clipboard", new Runnable() { public void run() { try { loadFromClipboard() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "loadFromClipboard()"; }});
addMenuItem(menu, "Load image snippet...", new Runnable() { public void run() { try {
selectImageSnippet(new VF1() { public void get(String imageID) { try {
setImage(loadImage2(imageID))
; } catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "setImage(loadImage2(imageID))"; }});
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "selectImageSnippet(new VF1() { public void get(String imageID) ctex {..."; }});
}
if (selection != null)
addMenuItem(menu, "Crop", new Runnable() { public void run() { try { crop() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "crop()"; }});
if (!specialPurposed)
addMenuItem(menu, "No image", new Runnable() { public void run() { try { noImage() ;
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "noImage()"; }});
}
void noImage() { setImage((BufferedImage) null); }
void crop() {
if (selection == null) return;
BufferedImage img = cloneClipBufferedImage(getImage(), selection);
selection = null;
setImage(img);
}
void loadFromClipboard() {
BufferedImage img = getImageFromClipboard();
if (img != null)
setImage(img);
}
void saveImage() {
RGBImage image = new RGBImage(getImage(), null);
JFileChooser fileChooser = new JFileChooser(getProgramDir());
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
try {
image.save(file = fileChooser.getSelectedFile());
} catch (IOException e) {
popup(e);
}
}
}
void drawImageItself(int w, int h, Graphics2D g) {
int iw = getZoomedWidth(), ih = getZoomedHeight();
if (interpolationMode == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR || zoomX >= 1 || zoomY >= 1) {
// faster
g.drawImage(image, 0, 0, iw, ih, null);
} else
g.drawImage(resizeImage(image, iw, ih), 0, 0, null); // smoother
}
public void render(int w, int h, Graphics2D g) {
if (verbose) _print("render");
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolationMode);
g.setColor(Color.white);
BufferedImage image = or(imageToDraw, this.image);
if (!hasImage())
g.fillRect(0, 0, w, h);
else {
boolean alpha = !noAlpha && hasTransparency(image);
if (alpha) g.fillRect(0, 0, w, h);
drawImageItself(w, h, g);
int iw = getZoomedWidth(), ih = getZoomedHeight();
if (!alpha) {
g.fillRect(iw, 0, w-iw, h);
g.fillRect(0, ih, iw, h-ih);
}
}
if (overlay != null) {
if (verbose) _print("render overlay");
pcallF(overlay, g);
}
for (var overlay : cloneList(overlays)) { try {
overlay.drawOn(g);
} catch (Throwable __e) { printStackTrace(__e); }}
if (selection != null) {
if (verbose) _print("render selection");
// drawRect is inclusive, selection is exclusive, so... whatever, tests show it's cool.
drawSelectionRect(g, selection, Color.green, Color.white);
}
}
public void drawSelectionRect(Graphics2D g, Rectangle selection, Color green, Color white) {
drawSelectionRect(g, selection, green, white, zoomX, zoomY);
}
public void drawSelectionRect(Graphics2D g, Rectangle selection, Color green, Color white, double zoomX, double zoomY) {
g.setColor(green);
int top = (int) (selection.y * zoomY);
int bottom = (int) ((selection.y+selection.height) * zoomY);
int left = (int) (selection.x * zoomX);
int right = (int) ((selection.x+selection.width) * zoomX);
g.drawRect(left-1, top-1, right-left+1, bottom-top+1);
g.setColor(white);
g.drawRect(left - 2, top - 2, right - left + 3, bottom - top + 3);
}
public ImageSurface setZoom(double zoom) {
setZoom(zoom, zoom);
return this;
}
public void setZoom(double zoomX, double zoomY) {
autoZoomToDisplay = false;
setZoom_dontChangeAutoZoom(zoomX, zoomY);
}
public void setZoom_dontChangeAutoZoom(double zoomX) { setZoom_dontChangeAutoZoom(zoomX, zoomX); }
public void setZoom_dontChangeAutoZoom(double zoomX, double zoomY) {
if (this.zoomX == zoomX && this.zoomY == zoomY) return;
if (verbose) _print("Setting zoom");
this.zoomX = zoomX;
this.zoomY = zoomY;
revalidateMe();
repaint();
centerPoint(new Point(getImage().getWidth()/2, getImage().getHeight()/2));
pcallF(onZoom);
}
public Dimension getMinimumSize() {
if (metaGet("scaffolding") != null) scaffoldCalled(this, "getMinimumSize");
if (noMinimumSize) return new Dimension(1, 1);
int w = getZoomedWidth();
int h = getZoomedHeight();
Dimension min = super.getMinimumSize();
return printIfScaffoldingEnabled(this, new Dimension(Math.max(w, min.width), Math.max(h, min.height)));
}
int getZoomedHeight() {
return (int) (h() * zoomY);
}
int getZoomedWidth() {
return (int) (w() * zoomX);
}
boolean isShowing_quick() {
if (showingVar == null) { swing(() -> {
if (showingVar == null) showingVar = componentShowingVar(ImageSurface.this);
}); }
return showingVar.get();
}
public void setImageIfShowing_thisThread(MakesBufferedImage image) { setImageIfShowing_thisThread(toBufferedImage(image)); }
public void setImageIfShowing_thisThread(BufferedImage image) {
if (isShowing_quick())
setImage_thisThread(image);
}
public void setImage(MakesBufferedImage image) { swing(() -> {
setImage_thisThread(image);
}); }
public void setImage(BufferedImage img) { swing(() -> {
setImage_thisThread(img);
}); }
public void setImage_thisThread(MakesBufferedImage img) { setImage_thisThread(toBufferedImage(img)); }
public void setImage_thisThread(BufferedImage img) {
BufferedImage newImage = img != null ? img : dummyImage();
BufferedImage oldImage = image;
image = newImage;
boolean sameSize = !imagesHaveSameSize(oldImage, newImage);
if (!sameSize) {
if (verbose) _print("New image size");
revalidateMe();
}
quickRepaint();
pcallF(onNewImage);
if (!sameSize && autoZoomToDisplay) zoomToDisplaySize();
}
void setImageAndZoomToDisplay(BufferedImage img) {
setImage(img);
zoomToDisplaySize();
}
public BufferedImage getImage() {
return image;
}
public double getZoomX() {
return zoomX;
}
public double getZoomY() {
return zoomY;
}
public Dimension getPreferredSize() {
if (metaGet("scaffolding") != null) scaffoldCalled(this, "getPreferredSize");
return printIfScaffoldingEnabled(this, new Dimension(getZoomedWidth(), getZoomedHeight()));
}
/** returns a scrollpane with the scroll-mode prevent-garbage-drawing fix applied */
public JScrollPane makeScrollPane() {
JScrollPane scrollPane = new JScrollPane(this);
scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
return scrollPane;
}
public void zoomToWindow() { zoomToDisplaySize(); }
public void zoomToDisplaySize() { swing(() -> {
if (!hasImage()) return;
Dimension display = getDisplaySize();
if (display.width == 0 || display.height == 0) return;
int w = w(), h = h();
double xRatio = (display.width-5)/(double) w;
double yRatio = (display.height-5)/(double) h;
if (scaffoldingEnabled(this))
printVars("zoomToDisplaySize", "display", display, "w", w, "h", h, "xRatio", xRatio, "yRatio", yRatio);
setZoom_dontChangeAutoZoom(min(xRatio, yRatio));
revalidateMe();
}); }
/** tricky magic to get parent scroll pane */
private Dimension getDisplaySize() {
if (metaGet("scaffolding") != null) scaffoldCalled(this, "getDisplaySize");
Container c = getParent();
while (c != null) {
if (c instanceof JScrollPane)
return c.getSize();
c = c.getParent();
}
return getSize();
}
public void setSelection(Rect r) {
setSelection(toRectangle(r));
}
public void setSelection(Rectangle r) {
if (neq(selection, r)) {
selection = r;
pcallF(onSelectionChange);
quickRepaint();
}
}
public Rectangle getSelection() {
return selection;
}
public RGBImage getRGBImage() {
return new RGBImage(getImage());
}
// p is in image coordinates
void centerPoint(Point p) {
JScrollPane sp = enclosingScrollPane(this);
if (sp == null) return;
p = new Point((int) (p.x*getZoomX()), (int) (p.y*getZoomY()));
final JViewport viewport = sp.getViewport();
Dimension viewSize = viewport.getExtentSize();
//_print("centerPoint " + p);
int x = max(0, p.x-viewSize.width/2);
int y = max(0, p.y-viewSize.height/2);
//_print("centerPoint " + p + " => " + x + "/" + y);
p = new Point(x,y);
//_print("centerPoint " + p);
final Point _p = p;
awtLater(new Runnable() { public void run() { try {
viewport.setViewPosition(_p);
} catch (Exception __e) { throw rethrow(__e); } } public String toString() { return "viewport.setViewPosition(_p);"; }});
}
Pt pointFromEvent(MouseEvent e) {
return pointFromComponentCoordinates(new Pt(e.getX(), e.getY()));
}
Pt pointFromComponentCoordinates(Pt p) {
return new Pt((int) (p.x/zoomX), (int) (p.y/zoomY));
}
Pt pointToComponentCoordinates(double x, double y) {
return new Pt((int) (x*zoomX), (int) (y*zoomY));
}
void uploadTheImage() {
call(hotwire(/*#1007313*/"#1016427"), "go", getImage(), titleForUpload);
}
void showFullScreen() {
showFullScreenImageSurface(getImage());
}
void zoomIn(double f) { setZoom(getZoomX()*f, getZoomY()*f); }
void zoomOut(double f) { setZoom(getZoomX()/f, getZoomY()/f); }
ImageSurface setFile(File f) { file = f; return this; }
void setOverlay(IVF1 overlay) {
this.overlay = overlay;
}
boolean hasImage() { return image != null; }
public int w() { return image.getWidth(); }
public int h() { return image.getHeight(); }
void setPixelated(boolean b) {
assertTrue(b);
imageSurface_pixelated(this);
}
ImageSurface setAutoZoomToDisplay(boolean b) {
if (autoZoomToDisplay = b)
zoomToDisplaySize();
return this;
}
void quickRepaint() {
if (repaintInThread)
paintImmediately(0, 0, getWidth(), getHeight());
else
repaint();
}
void removeTool(AutoCloseable tool) { swing(() -> {
if (tools.contains(tool)) {
close(tool);
tools.remove(tool);
}
}); }
void removeAllTools() {
closeAllAndClear(tools);
}
void performAutoZoom() {
if (autoZoomToDisplay) zoomToDisplaySize();
}
void revalidateMe() {
revalidateIncludingFullCenterContainer(this);
}
} // end of ImageSurface
// static function allows garbage collection
static VF2 ImageSurface_popupMenuMaker() {
return new VF2() { public void get(ImageSurface is, JPopupMenu menu) { try {
Point p = is.pointFromEvent(componentPopupMenu_mouseEvent.get()).getPoint();
is.fillPopupMenu(menu, p);
} catch (Exception __e) { throw rethrow(__e); } }
public String toString() { return "Point p = is.pointFromEvent(componentPopupMenu_mouseEvent.get()).getPoint();\r..."; }};
}
static class CombinedStringifier implements IStringifier {
CopyOnWriteArrayList> stringifiers = new CopyOnWriteArrayList();
IStringifier defaultStringifier = new Stringifier_ToString();
CombinedStringifier(IPartialStringifier... stringifiers) {
addAll(this.stringifiers, stringifiers);
}
public String toString(A o) {
for (var stringifier : stringifiers) {
String s = stringifier.toStringOpt(o);
if (s != null) return s;
}
return defaultStringifier.toString(o);
}
public String toString() {
return formatFunctionCall("CombinedStringifier",
listPlus((List) stringifiers, defaultStringifier)
);
}
}
static interface MakesBufferedImage extends WidthAndHeight {
BufferedImage getBufferedImage();
public default void drawAt(Graphics2D g, int x, int y) {
g.drawImage(getBufferedImage(), x, y, null);
}
}
/* e.g.
overlay <- ScreenOverlay
bounds <- rightScreenBounds
overlay bounds bounds
overlay show
Can separate commands with ";" also.
For how to define functions in a script see #1033988.
Note: LeftArrowScriptAutoCompleter uses a lot of this class's internals
*/
static class GazelleV_LeftArrowScriptParser extends SimpleLeftToRightParser {
final public GazelleV_LeftArrowScriptParser setG22utils(G22Utils g22utils){ return g22utils(g22utils); }
public GazelleV_LeftArrowScriptParser g22utils(G22Utils g22utils) { this.g22utils = g22utils; return this; } final public G22Utils getG22utils(){ return g22utils(); }
public G22Utils g22utils() { return g22utils; }
G22Utils g22utils = new G22Utils();
List functionContainers;
LinkedHashMap