diff --git a/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip b/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip index 52042b8a2..59db2cab0 100644 Binary files a/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip and b/sources/net.sf.j2s.core/dist/swingjs/SwingJS-site.zip differ diff --git a/sources/net.sf.j2s.core/dist/swingjs/timestamp b/sources/net.sf.j2s.core/dist/swingjs/timestamp index 62e636da7..b06e62268 100644 --- a/sources/net.sf.j2s.core/dist/swingjs/timestamp +++ b/sources/net.sf.j2s.core/dist/swingjs/timestamp @@ -1 +1 @@ -20190724061400 +20190814182015 diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/SwingJS-site.zip b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/SwingJS-site.zip index 52042b8a2..59db2cab0 100644 Binary files a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/SwingJS-site.zip and b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/SwingJS-site.zip differ diff --git a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/timestamp b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/timestamp index 62e636da7..b06e62268 100644 --- a/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/timestamp +++ b/sources/net.sf.j2s.core/dist/swingjs/ver/3.2.4/timestamp @@ -1 +1 @@ -20190724061400 +20190814182015 diff --git a/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip b/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip index 52042b8a2..59db2cab0 100644 Binary files a/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip and b/sources/net.sf.j2s.java.core/dist/SwingJS-site.zip differ diff --git a/sources/net.sf.j2s.java.core/doc/Differences.txt b/sources/net.sf.j2s.java.core/doc/Differences.txt index ead5c418c..7a0e8e569 100644 --- a/sources/net.sf.j2s.java.core/doc/Differences.txt +++ b/sources/net.sf.j2s.java.core/doc/Differences.txt @@ -1,10 +1,11 @@ Notes ===== +updated 8/16/19 -- minor typos and added summary paragraph updated 7/19/19 -- clarification that AWT and Swing classes are supported directly updated 5/13/19 -- Mandarin U+79D8 reserved character; Missing Math methods; int and long updated 5/10/19 -- adds a section on static issues in multi-(duplicate)-applet pages updated 1/4/19 -- nio -updated 9/15/18 -- adds integer 1/0 == 0 +updated 9/15/18 -- adds integer 1/0 == Infinity updated 7/24/18 -- most classes replaced with https://github.com/frohoff/jdk8u-jdk updated 6/5/17 -- reserved package name "window" updated 3/11/17 -- myClass.getField @@ -537,14 +538,14 @@ qualified field and method names In order to minimize the chance of added SwingJS field and method names colliding with ones developers might use in subclassing Java classes, we have added U+79D8 (first character of Mandarin -"secrect") to the characters already disrecommended by Java documentation ("$" and "_"). The only problem +"secret") to the characters already disrecommended by Java documentation ("$" and "_"). The only problem would be if you use that character followed by certain English words in certain classes. For example \u79D8canvas for JComponents (in java.awt.JSComponent) and \u79D8byte (in java.io.File). missing Math methods -------------------- -java.lang.Math is worked out, but some methods are missing, eithr because they +java.lang.Math is worked out, but some methods are missing, either because they involve long integer value that are inaccessible in JavaScript, or because I just didn't implement them. This is a result of continued Java development. It is easy enough to add these methods if you have the source. They go into j2sClazz.js, @@ -566,7 +567,7 @@ For example, this will definitely NOT work in SwingJS: this.paint(getGraphics()) -and really should not in Java, either, as it is technically a resource memory leak. +and really should not work in Java, either, as it is technically a resource memory leak. Instead, if you really do not want to use repaint(), use this: @@ -601,7 +602,7 @@ Static classes such as: which are created using Class.forName are implemented using classes in the swingjs package. -AWTAccessor and AwtContext need to be customized +AWTAccessor is not implemented. AWT component peers and component "ui" user interfaces @@ -739,7 +740,7 @@ to BigInteger: * the integer storage bit length to 24, giving 48 for long and leaving * the last 16 bits clear for the exponent of the double number. This should * not affect performance significantly. It does increase the storage - * size by about 33%. By bring an "int" to 3 bytes, we can easily construct + * size by about 33%. By bringing an "int" to 3 bytes, we can easily construct * and use byte[] data intended for the original BitSet. "Easily" may be a bit strong there. This was a serious challenge. @@ -772,13 +773,11 @@ JEditorPane (JavaScript
) For the initial implementation, we don't implement infinite undo/redo, and the abstract document model is much less elaborate. Only PlainDocument (in the form of JSPlainDocument) -is implemented. -The Document returned by JTextField.getDocument() is a javax.swing.text.Document. +is implemented. The Document returned by JTextField.getDocument() is a javax.swing.text.Document. -all scrolling is handled by HTML5 -javax.swing.AutoScroller is not implemented +All scrolling is handled by HTML5. javax.swing.AutoScroller is not implemented. public static methods .stop, .isRunning, .processMouseDragged require true Java threading -javax.swing.text.View and its subclasses are not implemented. +and so are not implmented. javax.swing.text.View and its subclasses are not implemented. The JS document model does not allow two text fields to address the same underlying document. @@ -792,9 +791,23 @@ Matcher.start(groupID) is not supported. java.util.Formatter will function correctly for all standard %... patterns. -integer 1/0 == 0 ----------------- +integer 1/0 == Infinity +----------------------- 1/0 in Java throws "java.lang.ArithmeticException: / by zero", but in JavaScript is just Infinity. - + + +Summary +------- + +These are all the known limitations of SwingJS. We have not found any of these limitations +to be show-stoppers. The primary issue for newcomers to SwingJS is having the source code. +You must check that source code for all your library jar files is available or, if you +choose, you will need to decompile those classes. We have used decompilation on some projects, +and it works just fine. So, technically, all we really need are JAR/class files. But the +source is by far superior. It's generally prettier, and it has the license information that +may or may not be present with the JAR or class files. Use class files at your own risk. + +Bob Hanson +2019.08.16 diff --git a/sources/net.sf.j2s.java.core/src/javax/swing/JFrame.java b/sources/net.sf.j2s.java.core/src/javax/swing/JFrame.java index 291225a69..acce0093f 100644 --- a/sources/net.sf.j2s.java.core/src/javax/swing/JFrame.java +++ b/sources/net.sf.j2s.java.core/src/javax/swing/JFrame.java @@ -170,7 +170,7 @@ public void add(Component comp, Object constraints) { */ protected boolean rootPaneCheckingEnabled = false; - private boolean _boundsFrozen; + private boolean 秘boundsFrozen; /** * Constructs a new frame that is initially invisible. @@ -915,15 +915,15 @@ protected String paramString() { + ",rootPaneCheckingEnabled=" + rootPaneCheckingEnabledString; } - public void _freezeBounds(int w, int h) { + public void 秘freezeBounds(int w, int h) { setSize(w, h); - _boundsFrozen = true; + 秘boundsFrozen = true; resizable = false; } @Override public void reshape(int x, int y, int width, int height) { - if (!_boundsFrozen) + if (!秘boundsFrozen) super.reshape(x, y, width, height); } diff --git a/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java b/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java index f0e55133b..4897a9c1f 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/JSGraphics2D.java @@ -790,9 +790,13 @@ public boolean hitClip(int x, int y, int width, int height) { return clipRect.intersects(x, y, width, height); } + private int alpha; private void setGraphicsColor(Color c) { if (c == null) return; // this was the case with a JRootPanel graphic call + int a = c.getAlpha(); + if (a != alpha) + ctx.globalAlpha = (alpha = a) / 256F; ctx.fillStyle = ctx.strokeStyle = JSToolkit.getCSSColor(c); } @@ -1010,13 +1014,8 @@ public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { } public void setAlpha(float f) { - /** - * @j2sNative - * - * this.ctx.globalAlpha = f; - */ - { - } + ctx.globalAlpha = f; + alpha = (int) Math.floor(f * 256 + 0.0039); } public HTML5Canvas getCanvas() { @@ -1056,17 +1055,7 @@ public int mark() { // note: This method is referred to in JComponent.java j2snative block as mark$ ctx.save(); Object[] map = new Object[SAVE_MAX]; - - float alpha = 0; - /** - * @j2sNative - * - * alpha = this.ctx.globalAlpha; - * - */ - { - } - map[SAVE_ALPHA] = Float.valueOf(alpha); + map[SAVE_ALPHA] = Float.valueOf(ctx.globalAlpha); map[SAVE_COMPOSITE] = alphaComposite; map[SAVE_STROKE] = currentStroke; map[SAVE_TRANSFORM] = transform; @@ -1089,8 +1078,9 @@ public void reset(int n0) { Object[] map = HTML5CanvasContext2D.pop(ctx); setComposite((Composite) map[SAVE_COMPOSITE]); Float alpha = (Float) map[SAVE_ALPHA]; - if (alpha != null) + if (alpha != null) { setAlpha(alpha.floatValue()); + } setStroke((Stroke) map[SAVE_STROKE]); setTransform((AffineTransform) map[SAVE_TRANSFORM]); setFont((Font) map[SAVE_FONT]); diff --git a/sources/net.sf.j2s.java.core/src/swingjs/api/js/HTML5CanvasContext2D.java b/sources/net.sf.j2s.java.core/src/swingjs/api/js/HTML5CanvasContext2D.java index 60bf6700e..0ced65e96 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/api/js/HTML5CanvasContext2D.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/api/js/HTML5CanvasContext2D.java @@ -16,6 +16,8 @@ public class ImageData { public String font, fillStyle, strokeStyle; + public float globalAlpha; + public abstract void drawImage(DOMNode img, int sx, int sy, int swidth, int sheight, int dx, int dy, int dwidth, int dheight); diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java index 280b55377..07a563393 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java @@ -147,6 +147,10 @@ public class JSComponentUI extends ComponentUI implements JSEventHandler, PropertyChangeListener, ChangeListener, DropTargetPeer { + public interface Embeddable { + Object getEmbedded(String type); + } + private static final int MENUITEM_OFFSET = 11; final J2SInterface J2S = JSUtil.J2S; diff --git a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSFrameUI.java b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSFrameUI.java index 0f061e29e..ab653c857 100644 --- a/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSFrameUI.java +++ b/sources/net.sf.j2s.java.core/src/swingjs/plaf/JSFrameUI.java @@ -44,7 +44,7 @@ * @author hansonr * */ -public class JSFrameUI extends JSWindowUI implements FramePeer { +public class JSFrameUI extends JSWindowUI implements FramePeer, JSComponentUI.Embeddable { private static final Insets ZERO_INSETS = new Insets(0, 0, 0, 0); @@ -111,24 +111,11 @@ public DOMNode updateDOMNode() { h = defaultHeight; DOMNode.setSize(frameNode, w, h); DOMNode.setTopLeftAbsolute(frameNode, 0, 0); - String fname = frame.getName(); - DOMNode node = DOMNode.getElement(fname + "-div"); + DOMNode node = (DOMNode) getEmbedded("init"); if (node != null) { embeddingNode = node; - doEmbed = (DOMNode.getWidth(embeddingNode) > 0); + doEmbed = (DOMNode.getWidth(node) > 0); isHidden = !doEmbed; - if (doEmbed) { - frame.setUndecorated(true); - frame.setLocation(0, 0); - } else { - DOMNode.setStyles(embeddingNode, "position", "relative", "overflow", "hidden"); - } - - int ew = DOMNode.getWidth(node); - int eh = DOMNode.getHeight(node); - if (ew > 0 && eh > 0) { - frame._freezeBounds(ew, eh); - } } setWindowClass(); if (!frame.isUndecorated()) { @@ -182,6 +169,46 @@ public DOMNode updateDOMNode() { return domNode; } + /** + * Note: DO NOT CHANGE THE NAME OF THIS METHOD + * + * @param frame + * @param type + * one of: "name", "node", "init", "dim" + * @return + */ + @Override + @SuppressWarnings("unused") + public Object getEmbedded(String type) { + String name = frame.getName(); + DOMNode node = DOMNode.getElement(name + "-div"); + if (node == null) + return null; + switch (type) { + case "name": + return name; + case "node": + return node; + case "dim": + return new Dimension(DOMNode.getWidth(node), DOMNode.getHeight(node)); + case "init": + if (node == null) + return null; + Dimension dim = (Dimension) getEmbedded("dim"); + if (dim.width > 0) { + frame.setUndecorated(true); + frame.setLocation(0, 0); + String resize = DOMNode.getStyle(node, "resize"); + if (resize == "none") + frame.秘freezeBounds(dim.width, dim.height); + } else { + DOMNode.setStyles(node, "position", "relative", "overflow", "hidden"); + } + return node; + } + return null; + } + @Override protected boolean isFrameIndependent() { return !doEmbed; diff --git a/sources/net.sf.j2s.java.core/src/test/Test_Array.java b/sources/net.sf.j2s.java.core/src/test/Test_Array.java index 606517abe..4f31c2faf 100644 --- a/sources/net.sf.j2s.java.core/src/test/Test_Array.java +++ b/sources/net.sf.j2s.java.core/src/test/Test_Array.java @@ -11,6 +11,12 @@ class Test_Array extends Test_ { static int y; static { + + + int[][] ia = (int[][])c33def2b; + int[][] ib = ia.clone(); + assert("[[I".equals(ib.getClass().getName())); + int x = 3; y = x; Test_Array[] a = new Test_Array[3]; @@ -82,8 +88,10 @@ public static void main(String[] args) { double[] da = new double[3]; System.out.println(da[iI]); assert (ii3[2] == 1 && j == 1); + System.out.println("Test_Array OK"); } + } \ No newline at end of file diff --git a/sources/net.sf.j2s.java.core/src/test/Test_Interval.java b/sources/net.sf.j2s.java.core/src/test/Test_Interval.java new file mode 100644 index 000000000..1a04aaceb --- /dev/null +++ b/sources/net.sf.j2s.java.core/src/test/Test_Interval.java @@ -0,0 +1,223 @@ +package test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Random; + +class Test_Interval extends Test_ { + + static int[] i0 = new int[0]; + + static int[][] a = new int[][] { + { 1, 7 }, + { 2, 4 }, + { 3, 5 }, + { 3, 6 }, + { 4, 5 }, + { 7, 8 }, + { 9, 10 } + + }; + + public static void main(String[] args) { + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + int[] ap = new int[] { 10, 20, 30, 40, 50, 50, 50, 60, 70, 80, 90, 100, 110, 120 }; + + System.out.println(findClosestPoint(ap, 11, true)); // 0 + System.out.println(findClosestPoint(ap, 11, false)); // 1 + System.out.println(findClosestPoint(ap, 51, true)); // 6 + System.out.println(findClosestPoint(ap, 51, false)); // 7 + System.out.println(findClosestPoint(ap, 130, true));// -1 + System.out.println(findClosestPoint(ap, 130, false)); // -1 + System.out.println(findClosestPoint(ap, 0, true)); // -1 + System.out.println(findClosestPoint(ap, 0, false)); // -1 + System.out.println(findClosestPoint(ap, 30, true)); // 2 + System.out.println(findClosestPoint(ap, 60, true)); // 7 + System.out.println(findClosestPoint(ap, 50, true)); // 6 + System.out.println(findClosestPoint(ap, 50, false)); // 4 + + assert (findClosestPoint(ap, 11, true) == 0); + assert (findClosestPoint(ap, 11, false) == 1); + assert (findClosestPoint(ap, 51, true) == 6); + assert (findClosestPoint(ap, 51, false) == 7); + assert (findClosestPoint(ap, 130, true) == -1); + assert (findClosestPoint(ap, 130, false) == -1); + assert (findClosestPoint(ap, 0, true) == -1); + assert (findClosestPoint(ap, 0, false) == -1); + assert (findClosestPoint(ap, 30, true) == 2); + assert (findClosestPoint(ap, 60, true) == 7); + assert (findClosestPoint(ap, 50, true) == 6); + assert (findClosestPoint(ap, 50, false) == 4); + + new Test_Interval().findIntervals(a, 3); + new Test_Interval().findIntervals(a, 5); + new Test_Interval().findIntervals(a, 9); + + System.out.println("Test_Interval OK"); + } + + private static Interval[] ints; + + private void findIntervals(int[][] a, int pos) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + Random rand = new Random(); + int n = a.length; + Interval[] intervals = new Interval[n]; + for (int i = 0; i < n;) { + int r = rand.nextInt(n); + if (intervals[r] == null) { + intervals[r] = new Interval(a[i][0], a[i][1], i); + i++; + } + } + System.out.println("====="); + //dumpIntervals(intervals); + System.out.println("-----"); + ints = intervals; + Arrays.sort(intervals, new IComparator()); + linkIntervals(intervals); + //dumpIntervals(intervals); + List result = new ArrayList<>(); + findInterval(intervals, pos, result); + for (int i = 0; i < result.size(); i++) + System.out.println(pos + " " + result.get(i)); + + } + + private void findInterval(Interval[] intervals, int pos, List result) { + Interval ithis = findClosestInterval(intervals, pos); + while (ithis != null) { + if (ithis.end >= pos) + result.add(ithis); + ithis = ithis.containedBy; + } + } + + private Interval findClosestInterval(Interval[] l, int pos) { + int low = 0; + int high = l.length - 1; + int mid = 0; + while (low <= high) { + mid = (low + high) >>> 1; + int f = l[mid].begin; + switch (Long.signum(f - pos)) { + case -1: + low = mid + 1; + continue; + case 1: + high = mid - 1; + continue; + case 0: + while (++mid <= high && l[mid].begin == pos) { + ; + } + mid--; + return l[mid]; + } + } + return (high < 0 || low >= l.length ? null : l[high]); + } + + static void dumpIntervals(Interval[] intervals) { + for (int i = 0; i < intervals.length; i++) { + System.out.println(intervals[i]); + } + System.out.println(""); + } + + public void linkIntervals(Interval[] intervals) { + if (intervals.length < 2) + return; + int maxEnd = intervals[0].end; + for (int i = 1, n = intervals.length; i < n; i++) { + Interval ithis = intervals[i]; + if (ithis.begin <= maxEnd) + ithis.containedBy = getContainedBy(intervals, i); + if (ithis.end > maxEnd) + maxEnd = ithis.end; + } + + } + + private Interval getContainedBy(Interval[] intervals, int i) { + Interval ithis = intervals[i]; + while (--i >= 0) { + Interval ilast = intervals[i]; + if (ithis.begin <= ilast.end) { + return ilast; + } + } + return null; + } + + class Interval { + int begin, end, index; + Interval containedBy; + + Interval(int begin, int end, int index) { + this.begin = begin; + this.end = end; + this.index = index; + } + + @Override + public String toString() { + return "I" + index + " begin:" + begin + " end:" + end + " cont:" + + (containedBy == null ? "?" : containedBy.index); + } + + } + + class IComparator implements Comparator { + + @Override + public int compare(Interval a, Interval b) { + int val = (a.begin < b.begin ? -1 : a.begin > b.begin ? 1 : a.end > b.end ? 1 : a.end < b.end ? -1 : 0); + return val; + } + + } + + static private int findClosestPoint(int[] l, int pos, boolean isStart) { + int low = 0; + int high = l.length - 1; + int mid = 0; + while (low <= high) { + mid = (low + high) >>> 1; + int f = l[mid]; + switch (Long.signum(f - pos)) { + case -1: + low = mid + 1; + continue; + case 1: + high = mid - 1; + continue; + case 0: + if (isStart) { + while (--mid >= low && (f = l[mid]) != -1 && f == pos) { + ; + } + ++mid; + } else { + while (++mid <= high && (f = l[mid]) != -1 && f == pos) { + ; + } + mid--; + } + return mid; + } + } + // -1 here? + System.out.println(isStart + " " + low + " " + mid + " " + high); + return (high < 0 || low >= l.length ? -1 : isStart ? high : low); + } + +} \ No newline at end of file diff --git a/sources/net.sf.j2s.java.core/srcjs/js/j2sClazz.js b/sources/net.sf.j2s.java.core/srcjs/js/j2sClazz.js index c1ff62d00..8b7136c4d 100644 --- a/sources/net.sf.j2s.java.core/srcjs/js/j2sClazz.js +++ b/sources/net.sf.j2s.java.core/srcjs/js/j2sClazz.js @@ -9,6 +9,7 @@ // TODO: still a lot of references to window[...] +// BH 2019.07.27 fixes array(intArray).clone // BH 2019.07.09 adds Java String.trim() // BH 2019.05.21 changes Clazz.isClassDefined to Clazz._isClassDefined for compression // BH 2019.05.13 fixes for Math.getExponent, Math.IEEERemainder, Array.equals(Object) @@ -214,7 +215,7 @@ var _array = function(baseClass, paramType, ndims, params, isClone) { } params.push(paramType); var nbits = 0; - if (ndims != 0) { + if (ndims != 0 && !(isClone && Array.isArray(params[1]))) { switch (prim) { case "B": nbits = 8; @@ -4423,11 +4424,8 @@ sp.contains$S = function(a) {return this.indexOf(a) >= 0} // bh added sp.compareTo$ = sp.compareTo$S = sp.compareTo$TT = function(a){return this > a ? 1 : this < a ? -1 : 0} // bh added sp.toCharArray$=function(){ -var result=new Array(this.length); -for(var i=0;i= 0} // bh added sp.compareTo$ = sp.compareTo$S = sp.compareTo$TT = function(a){return this > a ? 1 : this < a ? -1 : 0} // bh added sp.toCharArray$=function(){ -var result=new Array(this.length); -for(var i=0;i