Skip to content

Commit 1c06b96

Browse files
hansonrhansonr
authored andcommitted
JSEditor TAB work in progress
1 parent d254a0e commit 1c06b96

File tree

9 files changed

+209
-113
lines changed

9 files changed

+209
-113
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2019.07.01 working on JSEditorPaneUI tab business

sources/net.sf.j2s.java.core/src/javax/swing/JTextArea.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ public JTextArea(Document doc) {
200200
* arguments are negative.
201201
*/
202202
public JTextArea(Document doc, String text, int rows, int columns) {
203+
204+
setFocusTraversalKeysEnabled(false); // can't handle CTRL-ENTER in JavaScript
203205
this.rows = rows;
204206
this.columns = columns;
205207
if (doc == null) {

sources/net.sf.j2s.java.core/src/swingjs/plaf/JSComponentUI.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -842,11 +842,11 @@ protected void setJ2sMouseHandler() {
842842
J2S.setMouse(domNode, true);
843843
}
844844

845-
protected boolean handleTab(Object jqevent) {
846-
JSKeyEvent.dispatchKeyEvent(jc, KeyEvent.KEY_PRESSED, 0, jqevent, System.currentTimeMillis());
847-
return CONSUMED;
848-
}
849-
845+
// protected boolean handleTab(Object jqevent) {
846+
// JSKeyEvent.dispatchKeyEvent(jc, KeyEvent.KEY_PRESSED, 0, jqevent, System.currentTimeMillis());
847+
// return CONSUMED;
848+
// }
849+
//
850850

851851
/**
852852
* fired by JSComponent when key listeners are registered

sources/net.sf.j2s.java.core/src/swingjs/plaf/JSEditorPaneUI.java

Lines changed: 108 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@
44
import java.awt.Dimension;
55
import java.awt.Insets;
66
import java.awt.Point;
7+
import java.awt.event.KeyEvent;
78
import java.beans.PropertyChangeEvent;
89

910
import javax.swing.text.AbstractDocument.BranchElement;
1011
import javax.swing.text.AttributeSet;
12+
import javax.swing.text.BadLocationException;
1113
import javax.swing.text.Document;
1214
import javax.swing.text.Element;
1315
import javax.swing.text.JTextComponent;
1416
import javax.swing.text.StyleConstants;
1517

18+
import javajs.util.PT;
1619
import javajs.util.SB;
1720
import swingjs.JSToolkit;
1821
import swingjs.api.js.DOMNode;
@@ -65,6 +68,7 @@ public DOMNode updateDOMNode() {
6568
DOMNode.setStyles(domNode); // default for pre is font-height
6669
$(domNode).addClass("swingjs-doc");
6770
setupViewNode();
71+
System.out.println("JSEditorPaneUI todo -- tab; adding after a tab; backspace through tab");
6872
}
6973
textListener.checkDocument();
7074
setCssFont(domNode, c.getFont());
@@ -87,6 +91,8 @@ public void propertyChange(PropertyChangeEvent e) {
8791
@SuppressWarnings("unused")
8892
private int epTimer;
8993
private String currentHTML;
94+
private static String JSTAB = "<span class='j2stab'>&nbsp;&nbsp;&nbsp;&nbsp;</span>";
95+
private int tabCount = 4;
9096

9197
@Override
9298
public boolean handleJSEvent(Object target, int eventType, Object jQueryEvent) {
@@ -139,6 +145,10 @@ private int getJSCharCount(DOMNode sib) {
139145
case "DIV":
140146
n = 1;
141147
break;
148+
case "SPAN":
149+
if (isJSTAB(sib))
150+
return 1;
151+
break;
142152
}
143153

144154
return n + (/** @j2sNative sib.textContent && sib.textContent.length || */ 0);
@@ -228,17 +238,11 @@ else if (isSup)
228238
if (haveStyle)
229239
sb.append("<span" + style + ">");
230240
String t = text.substring(start, isDiv ? end - 1 : end);
231-
//if (start == 0) {
232241
if (t.indexOf(' ') >= 0)
233242
t = t.replace(' ', '\u00A0');
234-
// for (int i = 0; i < t.length(); i++) {
235-
// if (t.charAt(i) != ' ')
236-
// break;
237-
// t = t.substring(0, i) + "&nbsp;" + t.substring(i + 1);
238-
// i += 5;
239-
// }
240-
//System.out.println("text:'" + t + "'");
241-
//}
243+
if (t.indexOf('\t') >= 0) {
244+
t = PT.rep(t, "\t", JSTAB);
245+
}
242246
sb.append(t);
243247
if (haveStyle)
244248
sb.append("</span>");
@@ -366,13 +370,16 @@ protected String getPropertyPrefix() {
366370
* @param pt target caret position
367371
* @return range information or length: [textNode,charOffset] or [nontextNode,charNodesOffset] or [null, nlen]
368372
*/
373+
@SuppressWarnings("unused")
369374
@Override
370375
protected Object[] getJSNodePt(DOMNode node, int off, int pt) {
376+
// JavaScript
371377
boolean isRoot = (off < 0);
372378
if (isRoot) {
373379
lastTextNode = null;
374380
off = 0;
375-
}
381+
}
382+
boolean isTAB = isJSTAB(node);
376383
// Must consider several cases for BR and DIV:
377384
// <br>
378385
// <div><br><div> where br counts as 1 character --> [div, 0] or [null, 1]
@@ -383,7 +390,9 @@ protected Object[] getJSNodePt(DOMNode node, int off, int pt) {
383390
// also note that range can point to a character position only if the node is #text
384391
// otherwise, it must point to a childNodes index in the parent node. So <br> must
385392
// be indicated this second way.
386-
393+
//
394+
// TAB will be indicated as a JSTAB string (see above).
395+
387396
/**
388397
* @j2sNative
389398
var nodes = node.childNodes;
@@ -395,24 +404,32 @@ protected Object[] getJSNodePt(DOMNode node, int off, int pt) {
395404
var ipt = off;
396405
var nlen = 0;
397406
var i1 = (tag == "DIV" || tag == "P" ? 1 : 0);
407+
var ptIncr = 0;
398408
for (var i = 0; i < n; i++) {
399409
node = nodes[i];
400410
if (node.innerText) {
401-
ret = this.getJSNodePt$swingjs_api_js_DOMNode$I$I(node, ipt, pt, false);
411+
ret = this.getJSNodePt$swingjs_api_js_DOMNode$I$I(node, ipt, pt);
402412
if (ret[0] != null) {
403413
return ret;
404-
}
414+
}
405415
nlen = ret[1];
416+
pt += ret[4];
406417
} else if (node.tagName == "BR") {
407418
if (ipt == pt)
408419
return [node.parentNode, i];
409420
nlen = (isRoot ? 1 : 0);
410-
} else if (ipt + (nlen = (this.lastTextNode = node).length) >= pt) {
411-
return [node, Math.max(0, pt - ipt)];
421+
} else {
422+
this.lastTextNode = node;
423+
nlen = node.length;
424+
var p = ipt + (isTAB ? 1 : nlen);
425+
if (p >= pt)
426+
return [node, Math.max(0, !isTAB ? pt - ipt : p == pt ? nlen : 0)];
427+
if (isTAB)
428+
ptIncr = nlen - 1;
412429
}
413430
ipt += nlen;
414431
}
415-
return (isRoot ? [this.lastTextNode, Math.max(0, ret[3] - 1)] : [null, ipt + i1 - off, node, nlen]);
432+
return (isRoot ? [this.lastTextNode, Math.max(0, ret[3] - 1)] : [null, ipt + i1 - off, node, nlen, ptIncr]);
416433
*/
417434
{
418435
return null;
@@ -438,6 +455,8 @@ private static Object getInnerTextSafely(DOMNode node, boolean isLast, SB sb) {
438455
DOMNode[] nodes = (DOMNode[]) DOMNode.getAttr(node, "childNodes");
439456
if (tagName == "BR" || nodes.length == 1 && DOMNode.getAttr(nodes[0], "tagName") == "BR") {
440457
sb.append("\n");
458+
} else if (tagName == "SPAN" && isJSTAB(node)) {
459+
sb.append("\t");
441460
} else {
442461
for (int i = 0, n = nodes.length; i < n; i++)
443462
ret = (Boolean) getInnerTextSafely(nodes[i], i == n - 1, sb);
@@ -455,6 +474,12 @@ private static Object getInnerTextSafely(DOMNode node, boolean isLast, SB sb) {
455474
return (isRoot ? sb.toString() : ret);
456475
}
457476

477+
private static boolean isJSTAB(Object node) {
478+
return node != null
479+
&& (/** @j2sNative node.nodeType != 3 &&*/true)
480+
&& (((DOMNode) node).getAttribute("class").indexOf("j2stab") >= 0);
481+
}
482+
458483
int timeoutID;
459484

460485
@SuppressWarnings("unused")
@@ -476,6 +501,10 @@ void setJSTextDelayed() {
476501
@SuppressWarnings("unused")
477502
@Override
478503
protected void jsSelect(Object[] r1, Object[] r2, boolean andScroll) {
504+
fixTabRange(r1);
505+
if (r1 != r2)
506+
fixTabRange(r2);
507+
479508
//System.out.println("jsSelect " + r1 + r2);
480509
// range index may be NaN
481510
/**
@@ -506,54 +535,76 @@ protected void jsSelect(Object[] r1, Object[] r2, boolean andScroll) {
506535
}
507536
}
508537

538+
/**
539+
* @param r
540+
*/
541+
private void fixTabRange(Object[] r) {
542+
DOMNode node = (DOMNode)r[0];
543+
boolean isStart = (/** @j2sNative r[1] || */0) == 0;
544+
if (isJSTAB(node)) {
545+
if (isStart) {
546+
547+
} else {
548+
549+
}
550+
551+
}
552+
System.out.println("jsep fixTabRange " + r + " " + isJSTAB(node) + " " + node);
553+
}
554+
509555
@Override
510556
public void updateJSCursorFromCaret() {
511557
updateJSCursor("editordefault");
512558
}
513559

514-
@SuppressWarnings("unused")
560+
@SuppressWarnings("unused")
515561
@Override
516-
boolean getJSMarkAndDot(Point pt) {
562+
boolean getJSMarkAndDot(Point pt, int keycode) {
517563
int dot = 0, mark = 0, apt = 0, fpt = 0;
518-
DOMNode anode = null, fnode = null;
564+
DOMNode anode = null, fnode = null, apar = null, fpar = null;
519565
String atag = null, ftag = null;
520-
566+
int alen = 0, flen = 0;
567+
568+
boolean toEnd = (keycode == KeyEvent.VK_RIGHT || keycode == KeyEvent.VK_KP_RIGHT);
569+
boolean toStart = (keycode == KeyEvent.VK_LEFT || keycode == KeyEvent.VK_KP_LEFT);
521570
/**
522-
* @j2sNative
571+
* @j2sNative
523572
*
524573
*
525-
* var s = window.getSelection();
526-
* anode = s.anchorNode;
527-
* apt = s.anchorOffset;
528-
* if (anode.tagName) {
529-
* anode = anode.childNodes[apt];
530-
* apt = 0;
531-
* }
532-
* fnode = s.focusNode;
533-
* fpt = s.focusOffset;
534-
* if (fnode.tagName) {
535-
* fnode = fnode.childNodes[fpt];
536-
* fpt = 0;
537-
* }
574+
* var s = window.getSelection(); anode = s.anchorNode; apt =
575+
* s.anchorOffset; if (anode.tagName) { anode =
576+
* anode.childNodes[apt]; apt = 0; } else { alen = anode.length; apar
577+
* = anode.parentElement; } fnode = s.focusNode; fpt = s.focusOffset;
578+
* if (fnode.tagName) { fnode = fnode.childNodes[fpt]; fpt = 0; }
579+
* else { flen = fnode.length; fpar = fnode.parentElement; }
538580
*/
539581

540582
if (anode == null || fnode == null) {
541583
System.out.println("JSEditorPaneUI anode or fnode is null ");
542584
return false;
543585
}
586+
boolean isAInTab = (alen == tabCount && apt != 0 && isJSTAB(apar));
587+
boolean isFInTab = (flen == tabCount && fpt != 0 && isJSTAB(fpar));
588+
boolean updateJS = false;
589+
if (isAInTab)
590+
apt = (apt == tabCount || (updateJS = toEnd) ? 1 : 0);
591+
if (isFInTab)
592+
fpt = (fpt == tabCount || (updateJS = toEnd) ? 1 : 0);
593+
if (toStart && (isAInTab && apt == 0 || isFInTab && fpt == 0))
594+
updateJS = true;
544595
mark = getJSDocOffset(anode);
545596
dot = (anode == fnode ? mark : getJSDocOffset(fnode)) + fpt;
546597
mark += apt;
547-
548-
//System.out.println("==windows at " + mark + "-" + dot + "/" + apt + " " + fpt);
549598

599+
System.out.println("==windows at " + mark + "-" + dot + "/" + apt + " " + fpt + " " + isAInTab + " " + isFInTab);
550600
pt.x = mark;
551601
pt.y = dot;
552602

603+
if (updateJS)
604+
setJSSelection(mark, dot, false);
553605
return true;
554606
}
555607

556-
557608
@Override
558609
void setJSMarkAndDot(int mark, int dot, boolean andScroll) {
559610
// key up with text change -- need to refresh data-ui attributes
@@ -562,13 +613,29 @@ void setJSMarkAndDot(int mark, int dot, boolean andScroll) {
562613
editor.getCaret().setDot(dot);
563614
updateDataUI();
564615
}
616+
617+
@Override
618+
public boolean isFocusable() {
619+
return false;
620+
}
565621

622+
566623
@Override
567624
protected boolean handleTab(Object jqEvent) {
568-
// TODO check. OK? Problem is that we can't CTRL-tab out of a JEditorPane
569-
return NOT_CONSUMED;
625+
int x0 = editor.getCaret().getMark();
626+
int y = editor.getCaret().getDot();
627+
int x = Math.min(x0, y);
628+
/** @j2sNative xxt = this.focusNode */
629+
y = Math.max(x0, y);
630+
try {
631+
if (x < y)
632+
editor.getDocument().remove(x, y - x);
633+
editor.getDocument().insertString(x, "\t", null);
634+
setJavaMarkAndDot(new Point(x + 1, x + 1));
635+
} catch (BadLocationException e) {
636+
}
637+
System.out.println("jsep handleTab " + x + " " + y + " " + editor.getText().replace('\t','_'));
638+
return CONSUMED;
570639
}
571640

572-
573-
574641
}

sources/net.sf.j2s.java.core/src/swingjs/plaf/JSTextAreaUI.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
package swingjs.plaf;
22

3-
import java.awt.Color;
43
import java.awt.Dimension;
54
import java.awt.Insets;
5+
import java.awt.Point;
66
import java.beans.PropertyChangeEvent;
77

88
import javax.swing.JTextArea;
9-
import javax.swing.text.Document;
109
import javax.swing.text.Element;
11-
import javax.swing.text.JTextComponent;
1210
import javax.swing.text.PlainView;
1311
import javax.swing.text.View;
1412
import javax.swing.text.WrappedPlainView;
1513

16-
import swingjs.JSToolkit;
1714
import swingjs.api.js.DOMNode;
1815

1916
/**
@@ -155,6 +152,18 @@ public boolean isFocusable() {
155152

156153
@Override
157154
protected boolean handleTab(Object jqEvent) {
155+
String val = getJSTextValue();
156+
Point pt = new Point();
157+
getJSMarkAndDot(pt, 0);
158+
int x = Math.min(pt.x, pt.y);
159+
int y = Math.max(pt.x, pt.y);
160+
val = val.substring(0, x) + "\t" + val.substring(y);
161+
editor.setTextFromUI(val);
162+
pt.x = pt.y = ++x;
163+
setJSMarkAndDot(x, x, false);
164+
checkNewEditorTextValue();
165+
setJavaMarkAndDot(pt);
166+
//System.out.println("JSTextAreaUI " + editor.getCaretPosition() + " " + pt);
158167
return CONSUMED;
159168
}
160169

0 commit comments

Comments
 (0)