656 lines
19 KiB
Java
656 lines
19 KiB
Java
/*
|
|
VStream.java
|
|
*
|
|
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
|
|
*
|
|
* You may use and distribute under the terms of either the GNU Lesser
|
|
* General Public License, either version 2 of the license or,
|
|
* at your choice, any later version. Alternatively, you may use and
|
|
* distribute under the terms of the XPL.
|
|
*
|
|
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
|
|
* the licenses.
|
|
*
|
|
* This software is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
|
|
* file for more details.
|
|
*
|
|
*/
|
|
/*
|
|
* Written by Tuomas Lukka
|
|
*/
|
|
|
|
package org.gzigzag;
|
|
import java.util.*;
|
|
import java.awt.*;
|
|
|
|
/** Utility functions for vstreams.
|
|
* NOTE! USE THE VirtualCursor OBJECTS ONLY SHORT-TERM, put stuff
|
|
* in the structure
|
|
* for longer term.
|
|
* ANY call to VStream.* routines invalidates all VirtualCursor objects pointing
|
|
* to that vstream.
|
|
* <p>
|
|
* TODO: d.markup, active references to parts of another vstream
|
|
* (via including complete vstream objects!)
|
|
* <p>
|
|
* The vstream format is simple: the headcell on d.2 is a dummy cell
|
|
* that is never moved (so that it remains easy to refer to the vstream).
|
|
* Note that cells with the span length of 0 (i.e. end less than start)
|
|
* are explicitly ALLOWED.
|
|
* <p>
|
|
* Important policy decision pending: what to do about non-span cells
|
|
* in vstreams?
|
|
* <p>
|
|
* In addition to pointers, we'll probably need spans (of vstream) to complement
|
|
* them, for formatting etc.
|
|
* @deprecated This is a bit old now - see e.g. Nile and Stream.java.
|
|
*/
|
|
|
|
public class VStream {
|
|
public static final String rcsid = "$Id: VStream.java,v 1.28 2000/11/24 16:24:21 tjl Exp $";
|
|
|
|
public static final boolean dbg = false;
|
|
static final void p(String s) { if(dbg) System.out.println(s); }
|
|
|
|
static String dim = "d.2";
|
|
static public class Rend {
|
|
public Span[] spans;
|
|
public String[] strs;
|
|
public ZZCell[] cells;
|
|
public int[][] marks;
|
|
public ZZCell[][] markcells;
|
|
}
|
|
|
|
static public final void assertOffs(ZZCursor c) {
|
|
if(c.getOffs() == c.NO_OFFSET)
|
|
throw new ZZError("Need cursor offset");
|
|
}
|
|
|
|
static public ZZCursorVirtual add(ZZCursor vc, int o) {
|
|
assertOffs(vc);
|
|
|
|
ZZCell c = vc.get();
|
|
o += vc.getOffs();
|
|
|
|
// XXX Do we need to enforce spans?
|
|
while(o < 0) {
|
|
c = c.s(dim, -1);
|
|
if(c == null || c.getSpan() == null) return null;
|
|
o += (int)c.getSpan().length();
|
|
}
|
|
while(o > c.getSpan().length()) {
|
|
o -= (int)c.getSpan().length();
|
|
c = c.s(dim, 1);
|
|
if(c == null || c.getSpan() == null) return null;
|
|
}
|
|
return new ZZCursorVirtual(c, o);
|
|
}
|
|
|
|
static public String error(ZZCell c) {
|
|
ZZCell s = c.h(dim, -1);
|
|
if(s.getSpan() != null) return "First cell has span";
|
|
while((s=s.s(dim, 1))!=null) {
|
|
if(s.getSpan() == null)
|
|
return "No span in cell!";
|
|
}
|
|
return null;
|
|
}
|
|
static public void check(ZZCell c) {
|
|
if(!dbg) return;
|
|
String e = error(c);
|
|
System.out.println("VSTREAM DUMP");
|
|
for(ZZCell s = c.h(dim, -1); s != null;
|
|
s = s.s(dim, 1)) {
|
|
System.out.println("'"+s.getText()+"' from span: "+s.getSpan());
|
|
}
|
|
if(e == null) return;
|
|
throw new ZZError("VStream error in stream! '"+e+"' dumped");
|
|
}
|
|
|
|
// The first cell is the second of the rank.
|
|
static public ZZCursor start(ZZCell c) {
|
|
c = c.h(dim, -1).s(dim, 1);
|
|
if(c==null) return null;
|
|
return new ZZCursorVirtual(c, 0);
|
|
}
|
|
static public ZZCursor end(ZZCell c) {
|
|
c = c.h(dim, 1);
|
|
return new ZZCursorVirtual(c, c.getText().length());
|
|
}
|
|
|
|
static public void create(ZZCell c, String dim, int dir, Span s) {
|
|
ZZCell n = c.N(dim, dir).N("d.2", 1);
|
|
if(s != null)
|
|
n.setSpan(s);
|
|
}
|
|
/** Find the first instance of the given character
|
|
* that occurs at position p or after.
|
|
*/
|
|
static public ZZCursor findChar(char c, ZZCursor p) {
|
|
assertOffs(p);
|
|
|
|
String s = p.get().getText();
|
|
int io = s.indexOf(c, p.getOffs());
|
|
if(io != -1) return new ZZCursorVirtual(p.get(), io);
|
|
ZZCell cur = p.get();
|
|
while((cur = cur.s(dim, 1))!=null) {
|
|
io = cur.getText().indexOf(c);
|
|
if(io != -1) return new ZZCursorVirtual(cur, io);
|
|
}
|
|
return null;
|
|
}
|
|
/** Return the string between two positions, inclusive.
|
|
*/
|
|
static public String getStr(ZZCursor p1, ZZCursor p2) {
|
|
p("getStr: "+p1+" "+p2);
|
|
assertOffs(p1); assertOffs(p2);
|
|
|
|
StringBuffer s = new StringBuffer();
|
|
if(p1.get() == p2.get()) {
|
|
return p1.get().getText().substring(p1.getOffs(), p2.getOffs()+1);
|
|
}
|
|
s.append(p1.get().getText().substring(p1.getOffs()));
|
|
ZZCell c = p1.get();
|
|
while((c=c.s(dim,1)) != null && c != p2.get()) {
|
|
s.append(c.getText());
|
|
}
|
|
if(c!=null) {
|
|
String str = c.getText();
|
|
// Have to check whether one past end or end
|
|
if(str.length() > p2.getOffs())
|
|
s.append(str.substring(0, p2.getOffs()+1));
|
|
else
|
|
s.append(str);
|
|
}
|
|
return s.toString();
|
|
}
|
|
// XXX Join the next two methods
|
|
static public Span[] getSpans(ZZCursor p1, ZZCursor p2) {
|
|
Vector sp = new Vector();
|
|
p("getspans: "+p1+" "+p2+" "+p1.get()+" "+p2.get());
|
|
p("getspans1: "+p1.get().getText());
|
|
p("getspans2: "+p1.get().getSpan());
|
|
p("getspans3: "+p1.get().getSpan().subSpan(p1.getOffs()));
|
|
if(p1.get() == p2.get()) {
|
|
sp.addElement(
|
|
p1.get().getSpan().subSpan(p1.getOffs(), p2.getOffs()+1)
|
|
);
|
|
} else {
|
|
sp.addElement(
|
|
p1.get().getSpan().subSpan(p1.getOffs())
|
|
);
|
|
ZZCell c = p1.get();
|
|
while((c=c.s(dim,1)) != null && c != p2.get()) {
|
|
sp.addElement(c.getSpan());
|
|
}
|
|
if(c!=null)
|
|
sp.addElement(c.getSpan().subSpan(0, p2.getOffs()+1));
|
|
}
|
|
Span[] ret = new Span[sp.size()];
|
|
for(int i=0; i<ret.length; i++) ret[i] = (Span)sp.elementAt(i);
|
|
return ret;
|
|
}
|
|
static public String[] getStrings(ZZCursor p1, ZZCursor p2) {
|
|
Vector sp = new Vector();
|
|
if(p1.get() == p2.get()) {
|
|
p("Gs==: "+p1.getOffs()+" "+p2.getOffs());
|
|
sp.addElement(
|
|
p1.get().getText().substring(p1.getOffs(), p2.getOffs()+1)
|
|
);
|
|
} else {
|
|
sp.addElement(
|
|
p1.get().getText().substring(p1.getOffs())
|
|
);
|
|
ZZCell c = p1.get();
|
|
while((c=c.s(dim,1)) != null && c != p2.get()) {
|
|
sp.addElement(c.getText());
|
|
}
|
|
if(c!=null)
|
|
sp.addElement(c.getText().substring(0, p2.getOffs()+1));
|
|
}
|
|
String[] ret = new String[sp.size()];
|
|
for(int i=0; i<ret.length; i++) ret[i] = (String)sp.elementAt(i);
|
|
return ret;
|
|
}
|
|
|
|
static public void findMarks(ZZCell c, int o1, int o2,
|
|
Vector mkindto, Vector mkcellto) {
|
|
Vector res = null;
|
|
if(o1 <= 0 && c.s("d.cut", 1) != null) {
|
|
res = new Vector();
|
|
// A cut == null cell
|
|
res.addElement(new Integer(0));
|
|
res.addElement(null);
|
|
}
|
|
while((c = c.s("d.cursor", 1))!=null) {
|
|
try {
|
|
int i = Integer.parseInt(c.getText());
|
|
if((o1 < 0 || i >= o1) && (o2<0 || i <= o2)) {
|
|
if(res==null) res = new Vector();
|
|
res.addElement(new Integer(i-o1));
|
|
res.addElement(c);
|
|
}
|
|
} catch(NumberFormatException e) {
|
|
// Nothin'
|
|
}
|
|
}
|
|
if(res!=null) {
|
|
int[] r = new int[res.size()/2];
|
|
ZZCell[] rc = new ZZCell[res.size()];
|
|
for(int i=0 ;i<res.size(); i+=2) {
|
|
r[i/2] = ((Integer)res.elementAt(i)).intValue();
|
|
rc[i/2] = (ZZCell)res.elementAt(i+1);
|
|
}
|
|
mkindto.addElement(r);
|
|
mkcellto.addElement(rc);
|
|
} else {
|
|
mkindto.addElement(null);
|
|
mkcellto.addElement(null);
|
|
}
|
|
}
|
|
|
|
|
|
static public Rend getRend(ZZCursor p1, ZZCursor p2) {
|
|
Vector sp = new Vector();
|
|
Vector cells = new Vector();
|
|
Vector strs = new Vector();
|
|
Vector mk = new Vector();
|
|
Vector mkc = new Vector();
|
|
Rend r = new Rend();
|
|
|
|
if(p1.get() == p2.get()) {
|
|
r.spans = new Span[] {p1.get().getSpan().subSpan(p1.getOffs(), p2.getOffs()+1)};
|
|
r.strs = new String[] {
|
|
p1.get().getText().substring(p1.getOffs(), p2.getOffs()+1)
|
|
};
|
|
findMarks(p1.get(), p1.getOffs(), p2.getOffs()+1, mk, mkc);
|
|
r.marks = new int[][] { (int[])mk.elementAt(0) };
|
|
r.markcells = new ZZCell[][] { (ZZCell[])mkc.elementAt(0) };
|
|
r.cells = new ZZCell[] { p1.get() };
|
|
return r;
|
|
}
|
|
sp.addElement(p1.get().getSpan().subSpan(p1.getOffs()));
|
|
strs.addElement(p1.get().getText().substring(p1.getOffs()));
|
|
cells.addElement(p1.get());
|
|
findMarks(p1.get(), p1.getOffs(), -1, mk, mkc);
|
|
ZZCell c = p1.get();
|
|
while((c=c.s(dim, 1)) != null && c != p2.get()) {
|
|
sp.addElement(c.getSpan());
|
|
strs.addElement(c.getText());
|
|
cells.addElement(c);
|
|
findMarks(c, 0, -1, mk, mkc);
|
|
}
|
|
if(c!=null) {
|
|
int n = p2.getOffs() + 1;
|
|
p("RENDEND: "+n+" '"+c.getText()+"' ");
|
|
if(c.getText().length() < n) n = c.getText().length();
|
|
sp.addElement(c.getSpan().subSpan(0, n));
|
|
strs.addElement(c.getText().substring(0, n));
|
|
findMarks(c, 0, p2.getOffs(), mk, mkc);
|
|
cells.addElement(c);
|
|
}
|
|
|
|
r.spans = new Span[sp.size()];
|
|
r.strs = new String[sp.size()];
|
|
r.marks = new int[sp.size()][];
|
|
r.markcells = new ZZCell[sp.size()][];
|
|
r.cells = new ZZCell[sp.size()];
|
|
for(int i=0; i<r.spans.length; i++) {
|
|
r.spans[i] = (Span)sp.elementAt(i);
|
|
r.strs[i] = (String)strs.elementAt(i);
|
|
r.marks[i] = (int[])mk.elementAt(i);
|
|
r.markcells[i] = (ZZCell[])mkc.elementAt(i);
|
|
r.cells[i] = (ZZCell)cells.elementAt(i);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
// XXX The following two are ridiculous now that Pos
|
|
// has been changed to Cursor.
|
|
static public ZZCursor posFromCursor(ZZCell curscell) {
|
|
// XXX Go to cursor-cargo, then get offset, then go to cell.
|
|
int of = 0;
|
|
curscell = curscell.h("d.cursor-cargo", -1);
|
|
try {
|
|
of = Integer.parseInt(curscell.getText());
|
|
} catch(NumberFormatException e) {
|
|
// Nothin'
|
|
}
|
|
curscell = curscell.h("d.cursor", -1);
|
|
if(curscell.getSpan() == null) return null;
|
|
return new ZZCursorVirtual(curscell, of);
|
|
}
|
|
static public void setCursorFromPos(ZZCell c, ZZCursor p) {
|
|
ZZCursorReal.set(c, p.get());
|
|
c.h("d.cursor-cargo", -1).setText(""+p.getOffs());
|
|
}
|
|
static public void insert(ZZCursor p, String s) {
|
|
p("Insert: "+p+" "+p.get());
|
|
StringScroll sc = p.get().getSpace().getStringScroll();
|
|
long offs = sc.append(s);
|
|
p("Insertsc: "+sc+" "+offs);
|
|
Span sp = Span.create(
|
|
Address.scrollOffs(sc, offs),
|
|
Address.scrollOffs(sc, offs + s.length() - 1)
|
|
);
|
|
insert(p, sp);
|
|
}
|
|
|
|
static public void moveCurs(ZZCell c0, int offs0, int offs1, ZZCell r,
|
|
int noffs) {
|
|
ZZCell[] rnk = c0.readRank("d.cursor", 1, false);
|
|
for(int i=0; i<rnk.length; i++) {
|
|
try {
|
|
int of = Integer.parseInt(rnk[i].getText());
|
|
if((offs0 < -1 || of >= offs0) &&
|
|
(offs1 < -1 || of <= offs1)) {
|
|
rnk[i].setText(""+(of-offs0+noffs));
|
|
r.insert("d.cursor", 1, rnk[i]);
|
|
}
|
|
} catch(NumberFormatException e) {
|
|
// Nothin'
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/** Split a VStream at position, return the cell just BEFORE the
|
|
* split. XXX MAYBE ALL VSTREAMS SHOULD HAVE EMPTY CELL AT BEGINNING AND
|
|
* END.
|
|
*/
|
|
static private ZZCell splitAt(ZZCursor p) {
|
|
// If offs == 0, need to do nothing.
|
|
if(p.getOffs() == 0) return p.get().s(dim, -1);
|
|
|
|
Span cur = p.get().getSpan();
|
|
if(p.getOffs() == cur.length()) return p.get();
|
|
// In the middle -> split and reposition cursors.
|
|
ZZCell n1 = p.get().N(dim, 1);
|
|
n1.setSpan(cur.subSpan(p.getOffs()));
|
|
p.get().setSpan(cur.subSpan(0, p.getOffs()));
|
|
|
|
ZZCell[] rnk = p.get().readRank("d.cursor", 1, false);
|
|
for(int i=0; i<rnk.length; i++) {
|
|
try {
|
|
int of = Integer.parseInt(rnk[i].getText());
|
|
if(of >= p.getOffs()) {
|
|
int nof = of-p.getOffs();
|
|
rnk[i].setText(""+nof);
|
|
n1.insert("d.cursor", 1, rnk[i]);
|
|
}
|
|
} catch(NumberFormatException e) {
|
|
// Nothin'
|
|
}
|
|
}
|
|
return p.get();
|
|
}
|
|
|
|
/** Insert a cut mark at the given position.
|
|
*/
|
|
static public void cut(ZZCursor p) {
|
|
ZZCell prev = splitAt(p);
|
|
ZZCell n = prev.s(dim, 1);
|
|
n.disconnect("d.cut", 1);
|
|
|
|
n.connect("d.cut", 1, n);
|
|
}
|
|
/** Clear the cuts in the given vstream.
|
|
*/
|
|
static public void clearcuts(ZZCursor p) {
|
|
if ( p == null ) return ;
|
|
for(ZZCell c = p.get().h(dim, -1); c!=null;
|
|
c = c.s(dim, 1))
|
|
if(c.s("d.cut", 1) != null)
|
|
c.disconnect("d.cut", 1);
|
|
}
|
|
|
|
static ZZCell findPrevCut(ZZCursor p) {
|
|
ZZCell prev;
|
|
for(prev=p.get(); prev != null && prev.s("d.cut", 1) == null;
|
|
prev = prev.s(dim, -1));
|
|
return prev;
|
|
}
|
|
static ZZCell findNextCut(ZZCursor p) {
|
|
ZZCell next;
|
|
for(next=p.get().s(dim, 1); next != null &&
|
|
next.s("d.cut", 1) == null;
|
|
next = next.s(dim, 1));
|
|
return next;
|
|
}
|
|
|
|
/** Create a new vstream between the given cut marks.
|
|
* XXX This is difficult since Pos doesn't have the forwards-backwards
|
|
* info - Swing positions do. This should probably be added...
|
|
* Imagine cutting apart at single character edges...
|
|
*/
|
|
static public ZZCell separate(ZZCursor p) {
|
|
ZZCell prev = findPrevCut(p);
|
|
ZZCell next = findNextCut(p);
|
|
ZZCell tmp;
|
|
// based on their nullness, find the section to cut.
|
|
if(prev == null && next == null) return null; // nothing.
|
|
if(prev == null) {
|
|
next.disconnect("d.cut", 1);
|
|
next.disconnect(dim, -1);
|
|
tmp = p.get().h(dim, -1);
|
|
tmp.disconnect(dim, 1);
|
|
tmp.connect(dim, 1, next);
|
|
return p.get().h(dim, -1).N(dim, -1);
|
|
} else {
|
|
if(next != null){
|
|
//prev.s(dim, -1).connect(dim, 1, next);
|
|
next.disconnect(dim, -1);
|
|
tmp = prev.s(dim, -1);
|
|
tmp.disconnect(dim, 1);
|
|
tmp.connect(dim, 1, next);
|
|
}
|
|
prev.disconnect(dim, -1);
|
|
prev.disconnect("d.cut", 1);
|
|
return prev.N(dim, -1);
|
|
}
|
|
// return null;
|
|
}
|
|
|
|
/** Copy the part of the vstream between the nearest cut marks
|
|
* into a new vstream.
|
|
*/
|
|
static public ZZCell separateCopy(ZZCursor p) {
|
|
ZZCell nhead = p.get().N("d.tmp",1);
|
|
nhead.excise("d.tmp");
|
|
ZZCell prev = findPrevCut(p);
|
|
ZZCell next = findNextCut(p);
|
|
if(prev == null) prev = p.get().h(dim, -1).s(dim, 1);
|
|
ZZCell n = nhead;
|
|
for(ZZCell c = prev; c != null && c != next; c=c.s(dim, 1)) {
|
|
n = n.N(dim, 1);
|
|
n.setSpan(c.getSpan());
|
|
}
|
|
return nhead;
|
|
}
|
|
|
|
|
|
/** Insert the given span.
|
|
* Cursors at the insertion point will be moved to AFTER the
|
|
* insertion. XXX Here's something where more flexibility
|
|
* is needed: does a cursor point forwards or backwards?
|
|
*/
|
|
static public void insert(ZZCursor p, Span s) {
|
|
ZZCell prev = splitAt(p);
|
|
|
|
Span cur = prev.getSpan();
|
|
if(prev.getSpan() != null && prev.getSpan().isAppendable(s)) {
|
|
int len = (int)prev.getSpan().length();
|
|
moveCurs(prev, len, len, prev, (int)(len+s.length()));
|
|
prev.setSpan(prev.getSpan().append(s));
|
|
return;
|
|
}
|
|
ZZCell n = prev.N(dim, 1);
|
|
n.setSpan(s);
|
|
|
|
moveCurs(p.get(), p.getOffs(), p.getOffs(), n, 1);
|
|
}
|
|
|
|
/** Assimilate a whole vstream in insertion.
|
|
* Also places cuts at the beginning and the end of the result...
|
|
* XXX should it just return the POSes?
|
|
* XXX Delete the empty cells at ends...
|
|
*/
|
|
static public void assimilate(ZZCursor p, ZZCell vstream) {
|
|
ZZCell prev = splitAt(p);
|
|
ZZCell next = prev.s(dim, 1);
|
|
ZZCell firstof = vstream.h(dim, -1).s(dim, 1);
|
|
ZZCell tail = firstof.h(dim, 1);
|
|
prev.disconnect(dim, 1);
|
|
firstof.disconnect(dim, -1);
|
|
prev.connect(dim, 1, firstof);
|
|
firstof.connect("d.cut", 1, firstof);
|
|
if(next != null) {
|
|
next.disconnect("d.cut", 1);
|
|
next.connect("d.cut", 1, next);
|
|
next.connect(dim, -1, tail);
|
|
}
|
|
}
|
|
|
|
/** A convenience function: delete one character prior to p0.
|
|
*/
|
|
static public void backspace(ZZCursor p0) {
|
|
// while and not if: there might be null-length
|
|
// spans in there...
|
|
while(p0.getOffs() == 0) {
|
|
ZZCell c = p0.get().s(dim, -1);
|
|
if(c == null || c.getSpan() == null || c.getSpan().length() == 0)
|
|
return;
|
|
p0 = new ZZCursorVirtual(c, (int)c.getSpan().length());
|
|
}
|
|
// Split if needed
|
|
if(p0.getOffs() != p0.get().getSpan().length()) {
|
|
ZZCell prev = splitAt(p0);
|
|
p0.set(prev);
|
|
}
|
|
// Now we know p0.offs == p0.get().getSpan().length()...
|
|
int l = (int)(p0.get().getSpan().length());
|
|
if(l==1) {
|
|
// move cursors and delete cell
|
|
// XXX AUGH! Must move EITHER forwards or backwards,
|
|
// depending on which one is there...
|
|
ZZCell to = p0.get().s(dim, 1); int offs = 0;
|
|
if(to==null) {
|
|
to = p0.get().s(dim, -1);
|
|
offs = (int)to.getSpan().length();
|
|
}
|
|
// Ouch...
|
|
moveCurs(p0.get(), 0, 0, to, offs);
|
|
moveCurs(p0.get(), 1, 1, to, offs);
|
|
p0.get().delete();
|
|
return;
|
|
}
|
|
p0.get().setSpan(p0.get().getSpan().subSpan(0, l-1));
|
|
moveCurs(p0.get(), l, l, p0.get(), l-1);
|
|
}
|
|
|
|
|
|
// XXX Maybe too heavy - always creates new cells.
|
|
// untested.
|
|
static public void delete(ZZCursor p0, ZZCursor p1) {
|
|
ZZCell[] rnk;
|
|
if(p0.get() == p1.get()) {
|
|
ZZCell n = p0.get().N(dim, 1);
|
|
p0.get().setSpan(p0.get().getSpan().subSpan(0, p0.getOffs()));
|
|
n.setSpan(p0.get().getSpan().subSpan(p1.getOffs()+1));
|
|
// Then, redo cursors
|
|
rnk = p0.get().readRank("d.cursor", 1, false);
|
|
for(int i=0; i<rnk.length; i++) {
|
|
try {
|
|
int of = Integer.parseInt(rnk[i].getText());
|
|
if(of > p1.getOffs()) {
|
|
int nof = of-p1.getOffs()-1;
|
|
rnk[i].setText(""+nof);
|
|
n.insert("d.cursor", 1, rnk[i]);
|
|
} else if(of >= p0.getOffs()) {
|
|
rnk[i].setText(""+p0.getOffs());
|
|
}
|
|
} catch(NumberFormatException e) {
|
|
// Nothin'
|
|
}
|
|
}
|
|
} else {
|
|
// 1. first cell's span & cursors
|
|
p0.get().setSpan(p0.get().getSpan().subSpan(0, p0.getOffs()));
|
|
rnk = p0.get().readRank("d.cursor", 1, false);
|
|
for(int i=0; i<rnk.length; i++) {
|
|
try {
|
|
int of = Integer.parseInt(rnk[i].getText());
|
|
if(of >= p0.getOffs()) {
|
|
rnk[i].setText(""+p0.getOffs());
|
|
}
|
|
} catch(NumberFormatException e) {
|
|
// Nothin'
|
|
}
|
|
}
|
|
// Do the cells until we get to the second cell.
|
|
ZZCell c = p0.get();
|
|
while((c = c.s(dim, 1)) != null && c != p1.get()) {
|
|
rnk = c.readRank("d.cursor", 1, false);
|
|
for(int i=0; i<rnk.length; i++) {
|
|
// Insert first - exception mustn't cancel insert.
|
|
p0.get().insert("d.cursor", 1, rnk[i]);
|
|
try {
|
|
int of = Integer.parseInt(rnk[i].getText());
|
|
// If there was an integer
|
|
rnk[i].setText(""+p0.getOffs());
|
|
} catch(NumberFormatException e) {
|
|
// Nothin'
|
|
}
|
|
}
|
|
c.delete();
|
|
}
|
|
// Then, the final cell.
|
|
if(c == null) return; // No cell - oops - deleted to end.
|
|
c.setSpan(c.getSpan().subSpan(p1.getOffs()+1));
|
|
rnk = p0.get().readRank("d.cursor", 1, false);
|
|
for(int i=0; i<rnk.length; i++) {
|
|
try {
|
|
int of = Integer.parseInt(rnk[i].getText());
|
|
if(of > p1.getOffs()) {
|
|
int nof = of-p1.getOffs()-1;
|
|
rnk[i].setText(""+nof);
|
|
} else {
|
|
p0.get().insert("d.cursor", 1, rnk[i]);
|
|
rnk[i].setText(""+p0.getOffs());
|
|
}
|
|
} catch(NumberFormatException e) {
|
|
// Nothin'
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
/** Given a blank cell, set that cell's span and add extra
|
|
* cells as necessary to copy the span between p0 and p1.
|
|
*/
|
|
static public void copyNew(ZZCursor p0, ZZCursor p1, ZZCell blank) {
|
|
if(p0.get()==p1.get()) {
|
|
blank.setSpan(p0.get().getSpan().subSpan(p0.getOffs(), p1.getOffs()+1));
|
|
} else {
|
|
// First cell
|
|
blank.setSpan(p0.get().getSpan().subSpan(p0.getOffs()));
|
|
// middle cells
|
|
ZZCell c = p0.get();
|
|
ZZCell n = blank;
|
|
while((c = c.s(dim, 1)) != null && c != p1.get()) {
|
|
n = n.N("dim", 1);
|
|
n.setSpan(c.getSpan());
|
|
}
|
|
// Last cell
|
|
if(c==null) return;
|
|
n = n.N("dim", 1);
|
|
n.setSpan(p1.get().getSpan().subSpan(0, p1.getOffs()+1));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|