created mirror
This commit is contained in:
95
Java/media/Address.java
Normal file
95
Java/media/Address.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Address.java
|
||||
*
|
||||
* Copyright (c) 1999, 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.*;
|
||||
|
||||
/** An address in a stable media stream.
|
||||
* Currently just a silly pointer but will be later extended
|
||||
* to include full tumblers.
|
||||
* Format: streamid.offset, where streamid is an alphanumeric string
|
||||
* identifying a stream.
|
||||
*/
|
||||
|
||||
public class Address {
|
||||
public static final String rcsid = "$Id: Address.java,v 1.3 2000/09/19 10:32:00 ajk Exp $";
|
||||
public static final boolean dbg = false;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
|
||||
Scroll scroll;
|
||||
String stream;
|
||||
long offset;
|
||||
public static Address parse(String s) {
|
||||
StringTokenizer st = new StringTokenizer(s, ".");
|
||||
if(st.countTokens() != 2) {
|
||||
throw new ZZError("Wrong number of toks in '"+s+"'");
|
||||
}
|
||||
Address a = new Address();
|
||||
a.stream = st.nextToken();
|
||||
a.offset = Long.parseLong(st.nextToken());
|
||||
return a;
|
||||
}
|
||||
|
||||
public static Address streamOffs(String s, long offs) {
|
||||
Address a = new Address();
|
||||
a.stream = s;
|
||||
a.offset = offs;
|
||||
return a;
|
||||
}
|
||||
public static Address scrollOffs(Scroll s, long offs) {
|
||||
// return s.getId() + "." + offs;
|
||||
Address a = new Address();
|
||||
a.stream = s.getId();
|
||||
a.offset = offs;
|
||||
return a;
|
||||
}
|
||||
|
||||
public String getStream() { return stream; }
|
||||
public Scroll getScroll(ZZSpace s) {
|
||||
if(scroll==null) scroll = Scroll.obtain(s, stream);
|
||||
return scroll;
|
||||
}
|
||||
public long getOffs() { return offset; }
|
||||
|
||||
public String toString() {
|
||||
return stream.toString() + "." + offset;
|
||||
}
|
||||
|
||||
public boolean lessThan(Address a) {
|
||||
int c = stream.compareTo(a.stream);
|
||||
if(c < 0) return true;
|
||||
if(c > 0) return false;
|
||||
if(offset < a.offset) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public Address addOffs(int o) {
|
||||
Address a = new Address();
|
||||
a.scroll = scroll;
|
||||
a.stream = stream;
|
||||
a.offset = offset + o;
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
99
Java/media/ByteScroll.java
Normal file
99
Java/media/ByteScroll.java
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
ByteScroll.java
|
||||
*
|
||||
* Copyright (c) 1999, 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.io.*;
|
||||
|
||||
/** A scroll of bytes. May later have holes etc. from expunging,
|
||||
* but basically the point is that the address to content mapping
|
||||
* is stable and will not change whatever is done.
|
||||
*/
|
||||
public class ByteScroll extends Scroll{
|
||||
public static final String rcsid = "$Id: ByteScroll.java,v 1.4 2000/09/19 10:32:00 ajk Exp $";
|
||||
// Cheat: it's just a file
|
||||
private RandomAccessFile f;
|
||||
|
||||
private String encoding;
|
||||
|
||||
private boolean readonly;
|
||||
|
||||
public ByteScroll(String id, File fn, String mode, String encoding,
|
||||
boolean ro) {
|
||||
super(id);
|
||||
this.encoding = encoding;
|
||||
this.readonly = ro;
|
||||
try {
|
||||
f = new RandomAccessFile(fn, mode);
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new NullPointerException("Can't get");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized byte[] get(long start, int n) {
|
||||
try {
|
||||
f.seek(start);
|
||||
byte[] ret = new byte[n];
|
||||
int r = f.read(ret);
|
||||
if(r!=n)
|
||||
throw new NullPointerException("NOT ENOUGH!");
|
||||
return ret;
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new NullPointerException("Can't get");
|
||||
}
|
||||
}
|
||||
|
||||
// XXX ENCODING
|
||||
public String getString(long start, int n) {
|
||||
byte[] b = get(start,n);
|
||||
try {
|
||||
return new String(b, "ISO8859_1");
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new NullPointerException("Can't get");
|
||||
}
|
||||
}
|
||||
|
||||
public long curEnd() { try { return f.length();
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new NullPointerException("Can't get");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized long append(byte[] bytes) {
|
||||
if(readonly) throw new ZZError("Can't append to readonly scroll");
|
||||
try {
|
||||
long offs = curEnd();
|
||||
f.seek(offs);
|
||||
f.write(bytes);
|
||||
return offs;
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new NullPointerException("Can't get");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
100
Java/media/Capitalizer.java
Normal file
100
Java/media/Capitalizer.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
Capitalizer.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.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Capitalizing code written by Tuomas Lukka
|
||||
*/
|
||||
|
||||
package org.gzigzag;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
|
||||
/** A class to capitalize first letters of sentences.
|
||||
* A sentence is separated by two or more spaces. If you just need to
|
||||
* capitalize one string, use the static method single(String). If you need
|
||||
* to capitalize a number of concurrent strings, instantiate Capitalizer and
|
||||
* run cap(String) over them, in order.
|
||||
* <p>
|
||||
* The algorithm is tricky and probably needs a lot of adjustment.
|
||||
* The first letters of sentences are currently identified by
|
||||
* two spaces next to each other.
|
||||
*/
|
||||
|
||||
public class Capitalizer {
|
||||
public static final String rcsid = "$Id: Capitalizer.java,v 1.1 2000/12/25 19:37:09 bfallenstein Exp $";
|
||||
public static boolean dbg = false;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
static final void pa(String s) { System.out.println(s); }
|
||||
|
||||
/** Have we read a single space? */
|
||||
boolean hadSpace = false;
|
||||
|
||||
/** Are we past a sentence boundary (two spaces)? */
|
||||
boolean boundary = true;
|
||||
|
||||
public static String single(String s) {
|
||||
return new Capitalizer().cap(s);
|
||||
}
|
||||
|
||||
public String cap(String s) {
|
||||
int len = s.length();
|
||||
// Look for the first non-space character the hard way.
|
||||
int i;
|
||||
for(i=0; i<s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
if(Character.isLetter(c)) {
|
||||
if(boundary)
|
||||
s = s.substring(0,i) + Character.toUpperCase(c)
|
||||
+ s.substring(i+1);
|
||||
boundary = false;
|
||||
hadSpace = false;
|
||||
break;
|
||||
} else
|
||||
if(c == ' ') {
|
||||
if(hadSpace) {
|
||||
boundary = true;
|
||||
hadSpace = false;
|
||||
} else {
|
||||
hadSpace = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(i == s.length()) return s;
|
||||
boundary = false;
|
||||
hadSpace = false;
|
||||
if(len > 1) {
|
||||
char c1 = s.charAt(len-1);
|
||||
if(c1 == ' ') {
|
||||
char c2 = s.charAt(len-2);
|
||||
boundary = (c2 == ' ');
|
||||
hadSpace = (c2 != ' ');
|
||||
}
|
||||
}
|
||||
// Then, find the other occurrences.
|
||||
int ind = i-1;
|
||||
while((ind = s.indexOf(" ", ind+1)) >= 0) {
|
||||
if(ind == s.length() - 2) break;
|
||||
if(Character.isLetter(s.charAt(ind+2)))
|
||||
s = s.substring(0, ind+2) +
|
||||
Character.toUpperCase( s.charAt(ind+2))
|
||||
+ s.substring(ind+3);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
109
Java/media/CharScroll.java
Normal file
109
Java/media/CharScroll.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
CharScroll.java
|
||||
*
|
||||
* Copyright (c) 1999, 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.io.*;
|
||||
|
||||
/** DEPRECATED FOR STRINGSCROLL
|
||||
* A scroll of chars. May later have holes etc. from expunging,
|
||||
* but basically the point is that the address to content mapping
|
||||
* is stable and will not change whatever is done.
|
||||
* XXX copied from ByteScroll - sad.
|
||||
*/
|
||||
public class CharScroll extends Scroll{
|
||||
public static final String rcsid = "$Id: CharScroll.java,v 1.5 2000/09/19 10:32:00 ajk Exp $";
|
||||
// Cheat: it's just a file
|
||||
private RandomAccessFile f;
|
||||
// public static final boolean dbg = true;
|
||||
// static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
|
||||
|
||||
private boolean readonly;
|
||||
|
||||
public CharScroll(String id, File fn, String mode,
|
||||
boolean ro) {
|
||||
super(id);
|
||||
this.readonly = ro;
|
||||
try {
|
||||
f = new RandomAccessFile(fn, mode);
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new NullPointerException("Can't get");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized char[] get(long start, int n) {
|
||||
try {
|
||||
f.seek(start*2);
|
||||
byte[] ret = new byte[n*2];
|
||||
int r = f.read(ret);
|
||||
if(r!=n*2)
|
||||
throw new NullPointerException("NOT ENOUGH!");
|
||||
char[] c = new char[n];
|
||||
for(int i=0; i<n; i++)
|
||||
c[i] = (char)((ret[i*2]<<8) | (ret[i*2+1]<<0));
|
||||
return c;
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new NullPointerException("Can't get");
|
||||
}
|
||||
}
|
||||
|
||||
// XXX ENCODING
|
||||
public String getString(long start, int n) {
|
||||
char[] b = get(start,n);
|
||||
String s = new String(b);
|
||||
p("GETS: "+start+" "+n+" "+b+" '"+s+"'");
|
||||
return s;
|
||||
}
|
||||
|
||||
public long curEnd() { try { return f.length()/2;
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new NullPointerException("Can't get");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized long append(String b) {
|
||||
return append(b.toCharArray());
|
||||
}
|
||||
public synchronized long append(char[] bytes) {
|
||||
if(readonly) throw new ZZError("Can't append to readonly scroll");
|
||||
try {
|
||||
long offs = curEnd();
|
||||
f.seek(offs*2);
|
||||
// f.write(bytes);
|
||||
for(int i=0; i<bytes.length; i++) {
|
||||
f.writeChar(bytes[i]);
|
||||
}
|
||||
p("WRITE: R "+offs);
|
||||
return offs;
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new NullPointerException("Can't get");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
226
Java/media/FText.java
Normal file
226
Java/media/FText.java
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
FText.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 Benjamin Fallenstein
|
||||
*/
|
||||
|
||||
package org.gzigzag;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
|
||||
/** A class representing some formatted text.
|
||||
* The text is represented as FText.Part objects, which
|
||||
* contain a single string of text in a given font, from a given cell
|
||||
* (possibly with an offset and length).
|
||||
* These parts may be created by any view.
|
||||
* @see FTextLayouter
|
||||
*/
|
||||
|
||||
public class FText {
|
||||
public static final String rcsid = "$Id: FText.java,v 1.21 2001/04/02 20:02:51 bfallenstein Exp $";
|
||||
public static boolean dbg = false;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
static final void pa(String s) { System.out.println(s); }
|
||||
|
||||
public static abstract class Part {
|
||||
public Font f; public FontMetrics fm;
|
||||
public Color bg, fg;
|
||||
public String s; public int n;
|
||||
|
||||
/** Make a flob showing this part on the screen. */
|
||||
public abstract Renderable rend(int x, int y, int d, Renderable prev);
|
||||
|
||||
/** Create another instance of the same class. */
|
||||
public abstract Part subpart(int first, int last);
|
||||
|
||||
public Part[] split(int at) { return new Part[] { to(at), from(at) }; }
|
||||
public Part to(int at) { return subpart(0, at); }
|
||||
public Part from(int at) { return subpart(at, n); }
|
||||
|
||||
public int getStrX(int at) {
|
||||
return fm.stringWidth(s.substring(0, at));
|
||||
}
|
||||
public int getHit(int x) {
|
||||
return ZZUtil.findStringHit(s, x, fm, true);
|
||||
}
|
||||
public int getHitX(int x) { return getStrX(getHit(x)); }
|
||||
|
||||
private int wd = -1;
|
||||
public int width() {
|
||||
if(wd == -1) wd = fm.stringWidth(s);
|
||||
return wd;
|
||||
}
|
||||
|
||||
private int ht = -1;
|
||||
public int height() {
|
||||
if(ht == -1) ht = fm.getHeight();
|
||||
return ht;
|
||||
}
|
||||
|
||||
public static String join(Part[] ps) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for(int i=0; i<ps.length; i++) sb.append(ps[i].s);
|
||||
return sb.toString();
|
||||
}
|
||||
public static int width(Part[] ps) {
|
||||
int res = 0;
|
||||
for(int i=0; i<ps.length; i++)
|
||||
res += ps[i].width();
|
||||
return res;
|
||||
}
|
||||
public static int height(Part[] ps) {
|
||||
int res = 0;
|
||||
for(int i=0; i<ps.length; i++) {
|
||||
int h = ps[i].height();
|
||||
if(h > res) res = h;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
public static int len(Part[] ps) {
|
||||
int res = 0;
|
||||
for(int i=0; i<ps.length; i++) res += ps[i].n;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CellPart extends Part {
|
||||
public ZZCell c, handleCell;
|
||||
public int offs;
|
||||
|
||||
public CellPart(ZZCell c, ZZCell handleCell, int offs, int n, Font f,
|
||||
FontMetrics fm, Color bg, Color fg) {
|
||||
this.c = c; this.offs = offs; this.f = f; this.fm = fm;
|
||||
this.handleCell = handleCell;
|
||||
this.bg = bg; this.fg = fg;
|
||||
if(n < 0) {
|
||||
s = c.t().substring(offs);
|
||||
this.n = s.length();
|
||||
} else {
|
||||
s = c.t().substring(offs, offs+n);
|
||||
this.n = n;
|
||||
}
|
||||
}
|
||||
public CellPart(ZZCell c, int offs, int n, Font f,
|
||||
FontMetrics fm, Color bg, Color fg) {
|
||||
this(c,c,offs,n,f,fm,bg,fg);
|
||||
}
|
||||
public Part subpart(int first, int last) {
|
||||
CellPart p = new CellPart(c, handleCell, offs+first, last-first, f, fm, bg, fg);
|
||||
p.s = s.substring(first, last);
|
||||
return p;
|
||||
}
|
||||
|
||||
public Renderable rend(int x, int y, int d, Renderable prev0) {
|
||||
SplitCellFlob1 prev = null, parent = null, res;
|
||||
if(prev0 instanceof SplitCellFlob1) {
|
||||
prev = (SplitCellFlob1)prev0;
|
||||
parent = prev.parent != null ? prev.parent : prev;
|
||||
if(!parent.c.equals(c))
|
||||
parent = null;
|
||||
}
|
||||
res = new SplitCellFlob1(x, y, d, width(), height(),
|
||||
handleCell, s, f, fm, parent, offs, n, bg);
|
||||
if(prev != null) res.setPrev(prev);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/** A cell part showing cursor colors in the background. */
|
||||
public static class CursorCellPart extends CellPart {
|
||||
public CursorCellPart(ZZCell c, ZZCell handleCell, int offs, int n, Font f,
|
||||
FontMetrics fm, Color bg, Color fg) {
|
||||
super(c, handleCell, offs, n, f, fm, bg, fg);
|
||||
}
|
||||
public CursorCellPart(ZZCell c, int offs, int n, Font f,
|
||||
FontMetrics fm, Color bg, Color fg) {
|
||||
super(c, offs, n, f, fm, bg, fg);
|
||||
}
|
||||
public Renderable rend(int x, int y, int d, Renderable prev) {
|
||||
SplitCellFlob1 sf = (SplitCellFlob1)super.rend(x, y, d, prev);
|
||||
sf.showCursor();
|
||||
return sf;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringPart extends Part {
|
||||
public StringPart(String s, Font f, FontMetrics fm,
|
||||
Color bg, Color fg) {
|
||||
this.s = s; this.f = f; this.fm = fm; this.bg = bg; this.fg = fg;
|
||||
n = s.length();
|
||||
}
|
||||
public Part subpart(int first, int last) {
|
||||
return new StringPart(s.substring(first, last), f, fm, bg, fg);
|
||||
}
|
||||
|
||||
public Renderable rend(int x, int y, int d, Renderable prev) {
|
||||
int my = y - fm.getDescent() + height();
|
||||
TextDecor res = new TextDecor(x, my, s, fg, f);
|
||||
res.d = d;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
public Part[] parts;
|
||||
|
||||
public FText(Part[] ps) { parts = ps; }
|
||||
public FText(Vector v) {
|
||||
parts = new Part[v.size()];
|
||||
for(int i=0; i<parts.length; i++) parts[i] = (Part)v.elementAt(i);
|
||||
}
|
||||
|
||||
public String get() { return Part.join(parts); }
|
||||
public String get(int at, int n) { return get().substring(at, at+n); }
|
||||
|
||||
// return { part, offs }
|
||||
public int[] pos(int at) {
|
||||
int here = 0;
|
||||
for(int i=0; i<parts.length; i++) {
|
||||
Part p = parts[i];
|
||||
here += p.n;
|
||||
if(here >= at) {
|
||||
return new int[] { i, p.n-(here-at) };
|
||||
}
|
||||
}
|
||||
return new int[] { parts.length-1, parts[parts.length-1].n };
|
||||
}
|
||||
|
||||
/** Return lines laid out at a given width.
|
||||
* The dimensions of the array are lines[line][part]
|
||||
*/
|
||||
public Part[][] getLines(int width) {
|
||||
return FirstMatchBreaker.stupidBreak(this, width);
|
||||
}
|
||||
|
||||
public static int findLine(Part[][] lines, int offs) {
|
||||
int here = 0;
|
||||
for(int i=0; i<lines.length; i++) {
|
||||
here += Part.len(lines[i]);
|
||||
if(here >= offs) return i;
|
||||
}
|
||||
return lines.length-1;
|
||||
}
|
||||
|
||||
/** Capitalize the sentences in the whole FText. */
|
||||
public void capitalize() {
|
||||
Capitalizer c = new Capitalizer();
|
||||
for(int i=0; i<parts.length; i++)
|
||||
parts[i].s = c.cap(parts[i].s);
|
||||
}
|
||||
}
|
||||
143
Java/media/FirstMatchBreaker.java
Normal file
143
Java/media/FirstMatchBreaker.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
FTextBreaker.java
|
||||
*
|
||||
* Copyright (c) 2001, 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 Benjamin Fallenstein
|
||||
*/
|
||||
|
||||
package org.gzigzag;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
|
||||
/** A class doing linebreaking of FTexts with the stupid first match algorithm.
|
||||
* @see FText
|
||||
*/
|
||||
|
||||
public class FirstMatchBreaker {
|
||||
public static final String rcsid = "$Id$";
|
||||
public static boolean dbg = false;
|
||||
private static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
private static final void pa(String s) { System.out.println(s); }
|
||||
|
||||
static class Word {
|
||||
FText.Part p; int start, end;
|
||||
/** Is a line break enforced after this word? */
|
||||
boolean forced;
|
||||
FText.Part get() { return p.subpart(start, end); }
|
||||
int width() { return p.fm.stringWidth(p.s.substring(start, end)); }
|
||||
Word(FText.Part p, int s, int e, boolean f) {
|
||||
this.p=p; start=s; end=e; forced=f;
|
||||
}
|
||||
}
|
||||
|
||||
/** Internal convenience: concatenate all adjacent words in a vector. */
|
||||
private static void concat(Vector v) {
|
||||
int i=0;
|
||||
while(i+1 < v.size()) {
|
||||
Word w1 = (Word)v.elementAt(i), w2 = (Word)v.elementAt(i+1);
|
||||
if(w1.p == w2.p && w1.end == w2.start) {
|
||||
w1.end = w2.end;
|
||||
v.removeElement(w2);
|
||||
} else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/** Internal convenience: search a number of tokens in a string
|
||||
* Returns the next occurence of any of the tokens after the given
|
||||
* position.
|
||||
*/
|
||||
static int indOf(String s, int pos, char[] toks) {
|
||||
for(int i=pos+1; i<s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
for(int j=0; j<toks.length; j++)
|
||||
if(toks[j] == c) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Prepare an FText for the linebreaker (find possible breaks).
|
||||
* Returns a Vector of Word objects.
|
||||
*/
|
||||
public static Vector prepare(FText txt) {
|
||||
final char[] delims = new char[] { ' ', '\n' };
|
||||
|
||||
if(txt.parts.length == 0)
|
||||
throw new ZZError("FText has length 0");
|
||||
Vector v = new Vector();
|
||||
p("prepare: Old FText (len "+txt.parts.length+"): "+txt.get());
|
||||
|
||||
for(int i=0; i<txt.parts.length; i++) {
|
||||
FText.Part p = txt.parts[i];
|
||||
String s = p.s;
|
||||
int here, last = -1;
|
||||
while((here = indOf(s, last, delims)) >= 0) {
|
||||
char c = s.charAt(here);
|
||||
v.addElement(new Word(p, last+1, here+1, c == '\n'));
|
||||
last = here;
|
||||
}
|
||||
v.addElement(new Word(p, last+1, s.length(), false));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/** Internal convenience: Vector to array. */
|
||||
private static FText.Part[] v2a(Vector v) {
|
||||
concat(v);
|
||||
FText.Part[] res = new FText.Part[v.size()];
|
||||
for(int i=0; i<res.length; i++)
|
||||
res[i] = ((Word)v.elementAt(i)).get();
|
||||
return res;
|
||||
}
|
||||
|
||||
public static FText.Part[][] stupidBreak(FText ftxt, int width) {
|
||||
Vector prep = prepare(ftxt); int psize = prep.size();
|
||||
Vector lineset = new Vector(), line = new Vector();
|
||||
int x = 0, linestart = 0;
|
||||
p("FTextBreaker.stupidBreak...");
|
||||
for(int i=0; i<psize; i++) {
|
||||
Word w = (Word)prep.elementAt(i);
|
||||
x += w.width();
|
||||
if(!w.forced && x <= width) {
|
||||
line.addElement(w);
|
||||
continue;
|
||||
}
|
||||
if(i > linestart && x > width) {
|
||||
lineset.addElement(v2a(line));
|
||||
line.removeAllElements();
|
||||
x = w.width(); linestart = i;
|
||||
}
|
||||
line.addElement(w);
|
||||
if(x > width || w.forced) {
|
||||
/* w alone doesn't fit on our line, or forced break after w */
|
||||
lineset.addElement(v2a(line));
|
||||
line.removeAllElements();
|
||||
x = 0; linestart = i+1;
|
||||
}
|
||||
}
|
||||
if(line.size() > 0) lineset.addElement(v2a(line));
|
||||
FText.Part[][] res = new FText.Part[lineset.size()][];
|
||||
for(int j=0; j<res.length; j++) {
|
||||
res[j] = (FText.Part[])lineset.elementAt(j);
|
||||
if(dbg) pa(" "+(j+1)+". "+new FText(res[j]).get());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
112
Java/media/LineBreaker.java
Normal file
112
Java/media/LineBreaker.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
LineBreaker.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.awt.FontMetrics;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
|
||||
/** An interface to line breaking algorithms
|
||||
* This class knows absolutely nothing about characters, words, or so on.
|
||||
* It handles abstract tokens given by integers and asks the related
|
||||
* class LineInfo about the goodness of fitting a particular line
|
||||
* at a particular point.
|
||||
* <p>
|
||||
* Specific attention is paid to the billowing problem where
|
||||
* we have to render a paragraph so that the cursor is at the line with
|
||||
* the first line of the paragraph starts from the beginning of a line.
|
||||
* This is achieved by specifying the cursor position (from where the lines
|
||||
* should be counted) and the desired line number for that position.
|
||||
* This can also be used to render the paragraph starting from the end.
|
||||
*/
|
||||
|
||||
public abstract class LineBreaker {
|
||||
String rcsid = "$Id: LineBreaker.java,v 1.8.10.1 2001/08/16 13:50:01 bfallenstein Exp $";
|
||||
static private void pa(String s) { System.out.println(s); }
|
||||
/** Break the lines between the given addresses.
|
||||
* @return An array: the first element is the line index the rendering
|
||||
* starts on, and from the second element onwards the end points of the
|
||||
* lines are given.
|
||||
*/
|
||||
public abstract int[] breakLines(LineInfo li);
|
||||
|
||||
static private void test(LineBreaker b, String str, int cursor,
|
||||
SimpleLineInfo.Layout l) {
|
||||
SimpleLineInfo inf = new SimpleLineInfo(str, cursor, l);
|
||||
int[] foo = b.breakLines(inf);
|
||||
pa("Tested '"+str+"'");
|
||||
for(int i=0; i<foo.length; i++)
|
||||
pa(""+foo[i]);
|
||||
}
|
||||
|
||||
/** Doesn't compile with Kaffe's classes.
|
||||
static private class FixFM extends FontMetrics {
|
||||
FixFM() { super(null); }
|
||||
public int getAscent() { return 0; }
|
||||
public int getDescent() { return 0; }
|
||||
public int getLeading() { return 0; }
|
||||
public int getMaxAdvance() { return 10; }
|
||||
public int charWidth(char ch) { return 10; }
|
||||
public int charsWidth(char data[], int off, int len) {
|
||||
return 10 * len;
|
||||
}
|
||||
}
|
||||
**/
|
||||
|
||||
/** A test routine. Provide name of the class to test first.
|
||||
* The class to test must have a public constructor.
|
||||
*/
|
||||
/** FixFM doesn't compile with Kaffe's classes.
|
||||
static public void main(String[] argv) {
|
||||
try {
|
||||
Class cls = Class.forName("org.gzigzag."+argv[0]);
|
||||
Constructor ctr = cls.getConstructor(new Class[] {});
|
||||
LineBreaker b = (LineBreaker)ctr.newInstance(new Object[] {});
|
||||
|
||||
Vector db = new Vector();
|
||||
for(int i=0; i<argv.length; i++)
|
||||
Main.debugClass(argv[i], db);
|
||||
|
||||
final FontMetrics fixwd = new FixFM();
|
||||
|
||||
// Test 1: fixed-width lines, 10 chars each.
|
||||
SimpleLineInfo.Layout lay = new SimpleLineInfo.Layout() {
|
||||
public FontMetrics getFontMetrics(int line) {
|
||||
return fixwd;
|
||||
}
|
||||
public int getWidth(int line) {
|
||||
return 100;
|
||||
}
|
||||
public int getCenterLine() { return 0; }
|
||||
};
|
||||
|
||||
test(b, "", 0, lay);
|
||||
test(b, "A", 0, lay);
|
||||
test(b, "A B C D E F G H I J K L M N O P Q", 0, lay);
|
||||
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
pa(""+e);
|
||||
}
|
||||
}
|
||||
**/
|
||||
}
|
||||
55
Java/media/LineInfo.java
Normal file
55
Java/media/LineInfo.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
LineInfo.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;
|
||||
|
||||
/** An interface for line breaking algorithms to query about line widths.
|
||||
* The LineBreaker interface allows many different line breaking algorithms.
|
||||
* This class allows those algorithms to ask about various possible breaks
|
||||
* within the line.
|
||||
*/
|
||||
|
||||
public interface LineInfo {
|
||||
String rcsid = "$Id: LineInfo.java,v 1.5 2000/09/19 10:32:00 ajk Exp $";
|
||||
|
||||
/** The maximum token index.
|
||||
*/
|
||||
int getMax();
|
||||
|
||||
int getCursor();
|
||||
|
||||
int getCenterLine();
|
||||
|
||||
/** Give the best token between x0 and x1 that splits the interval
|
||||
* by approximately fract.
|
||||
* @return An array: first element is index, second penalty
|
||||
*/
|
||||
void split(int x0, int n, int sug, int[] ret);
|
||||
|
||||
/** Give the penalty of fitting the tokens from x0 to x1 on the
|
||||
* given line.
|
||||
* @return An array: first element 1000*width fraction, second element
|
||||
* penalty
|
||||
*/
|
||||
void widthPenalty(int x0, int n, int line, int[] ret);
|
||||
}
|
||||
|
||||
2
Java/media/README
Normal file
2
Java/media/README
Normal file
@@ -0,0 +1,2 @@
|
||||
This directory contains files related to handling various fluid media
|
||||
(text, sound, video, pictures) in ZZ.
|
||||
97
Java/media/Scroll.java
Normal file
97
Java/media/Scroll.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
Scroll.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.io.*;
|
||||
|
||||
/** A pseudo-permanent stable media storage.
|
||||
* If you put data in a scroll, it is guaranteed (well, in the development
|
||||
* stage only theoretically) that the same address will be eternal for it.
|
||||
* If you look for that particular address, you will get the data you stored
|
||||
* at it or you will get an error (e.g. if you have expunged some region
|
||||
* of a scroll) from it not being accessible.
|
||||
*/
|
||||
|
||||
public abstract class Scroll {
|
||||
public static final String rcsid = "$Id: Scroll.java,v 1.5 2000/11/03 08:01:05 ajk Exp $";
|
||||
public static boolean dbg = true;
|
||||
static public final void p(String s) { if(dbg) System.out.println(s); }
|
||||
static public final void pa(String s) { if(dbg) System.out.println(s); }
|
||||
|
||||
protected Scroll(String i) { id = i; }
|
||||
|
||||
String id;
|
||||
public String getId() { return id; }
|
||||
|
||||
|
||||
static Hashtable scrolls = new Hashtable();
|
||||
|
||||
|
||||
public interface Creator {
|
||||
Scroll create(String id, File f);
|
||||
}
|
||||
static Hashtable scrolltypes = new Hashtable(); // full of creators
|
||||
|
||||
static public void register(String id, Creator c) {
|
||||
scrolltypes.put(id, c);
|
||||
}
|
||||
|
||||
static public void register(String id, Scroll s) {
|
||||
scrolls.put(id, s);
|
||||
}
|
||||
|
||||
/** Get a scroll for the given identifier.
|
||||
* This method encapsulates the way the system finds
|
||||
* scrolls and the implementation will change in the future.
|
||||
* Currently it looks in the given ZZSpace for a file name.
|
||||
*/
|
||||
static public Scroll obtain(ZZSpace e, String id) {
|
||||
|
||||
|
||||
Scroll scr;
|
||||
if((scr=(Scroll)scrolls.get(id))!=null)
|
||||
return scr;
|
||||
|
||||
ZZCell c = e.getHomeCell();
|
||||
c = ZZDefaultSpace.findScrollCell(c, id);
|
||||
if(c==null) return null;
|
||||
ZZCell cfn = c.s("d.2",1);
|
||||
File f = new File(cfn.getText());
|
||||
ZZCell typ = cfn.s("d.2",1);
|
||||
String t = typ.getText();
|
||||
if(t.equals("Byte")) {
|
||||
scr = new ByteScroll(id, f, "r", "ISO8859_1", true);
|
||||
} else if(t.equals("Sound")) {
|
||||
ZZCell dur = typ.s("d.2", 1);
|
||||
scr = new SoundScroll(id, f, Long.parseLong(dur.getText()));
|
||||
} else {
|
||||
Creator crea = (Creator)scrolltypes.get(t);
|
||||
if(crea==null)
|
||||
throw new ZZError("No such scroll type: "+t);
|
||||
scr = crea.create(id, f);
|
||||
}
|
||||
|
||||
scrolls.put(id, scr);
|
||||
return scr;
|
||||
}
|
||||
}
|
||||
141
Java/media/SimpleLineBreaker.java
Normal file
141
Java/media/SimpleLineBreaker.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
SimpleLineBreaker.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.*;
|
||||
|
||||
public class SimpleLineBreaker extends LineBreaker {
|
||||
public static final String rcsid = "$Id: SimpleLineBreaker.java,v 1.11 2000/09/19 10:32:00 ajk Exp $";
|
||||
public static boolean dbg = false;
|
||||
final static void p(String s) { if(dbg) System.out.println(s); }
|
||||
final static void pa(String s) { System.out.println(s); }
|
||||
|
||||
public int[] breakLines(LineInfo li) {
|
||||
int n = li.getMax();
|
||||
|
||||
// Can't we do without this?
|
||||
if(n==0) return new int[] {0, 0};
|
||||
|
||||
int xc = li.getCursor();
|
||||
int l = li.getCenterLine();
|
||||
|
||||
int startmin = 0, startmax = 0;
|
||||
boolean gotmin = false, gotmax = false;
|
||||
boolean ret = false;
|
||||
int curstart = l;
|
||||
|
||||
while(true) {
|
||||
Vector res = new Vector();;
|
||||
int lenn = 0;
|
||||
int line = curstart;
|
||||
for(int cur = 0; cur < n; cur += lenn) {
|
||||
lenn = oneGoodLine(cur, n-cur, n-cur, line, li, 6);
|
||||
p("OGL RET: "+cur+" "+n+" "+line+" "+li+" : "+lenn);
|
||||
p("CURS: "+xc+" "+line+" "+l);
|
||||
if(xc >= cur && xc <= cur+lenn) {
|
||||
p("Cursor was on this line");
|
||||
// We hit the cursor here.
|
||||
if(line > l) {
|
||||
// line greater -> move upwards. This is a maximum.
|
||||
startmax = curstart; gotmax = true;
|
||||
curstart -= (line - l);
|
||||
} else if(line < l) {
|
||||
// line smaller -> move down. This is a min.
|
||||
startmin = curstart; gotmin = true;
|
||||
curstart += (l - line);
|
||||
}
|
||||
if(line == l) ret = true;
|
||||
}
|
||||
res.addElement(new Integer(cur + lenn));
|
||||
line ++;
|
||||
}
|
||||
|
||||
if(gotmin && gotmax && startmax - startmin < 2) {
|
||||
ret = true;
|
||||
curstart = startmin;
|
||||
} else {
|
||||
if(gotmin && curstart <= startmin) {
|
||||
curstart = startmin + 1;
|
||||
}
|
||||
if(gotmax && curstart >= startmax) {
|
||||
curstart = startmax - 1;
|
||||
}
|
||||
}
|
||||
|
||||
p("Ret: curstart = "+curstart);
|
||||
|
||||
if(ret) {
|
||||
int[] r = new int[res.size() + 1];
|
||||
r[0] = curstart;
|
||||
for(int i=1; i<r.length; i++) {
|
||||
r[i] = ((Integer)res.elementAt(i-1)).intValue();
|
||||
p("Line "+(i-1)+": "+r[i]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Starting at x0, find a good amount of text to include in line l.
|
||||
*/
|
||||
int oneGoodLine(int x0, int guessn, int maxn, int l, LineInfo li,
|
||||
int accept) {
|
||||
int[] res = new int[2];
|
||||
int minn = 0;
|
||||
int splitpen = 0;
|
||||
int best = 0;
|
||||
int bestpen = 1000000;
|
||||
while(true) {
|
||||
li.widthPenalty(x0, guessn, l, res);
|
||||
p("OGL iter: "+x0+" "+minn+" "+guessn+" "+maxn+" R: "+res[0]);
|
||||
int widpen = res[1];
|
||||
int pen = splitpen + widpen;
|
||||
if(pen < bestpen) {
|
||||
bestpen = pen; best = guessn;
|
||||
}
|
||||
// if(widpen <= accept) return best;
|
||||
if(res[0] > 1000) {
|
||||
p("Too wide");
|
||||
maxn = guessn;
|
||||
li.split(x0, guessn, x0+(guessn*1000/res[0]), res);
|
||||
p("Split res: "+guessn+" "+res[0]+" "+minn);
|
||||
if(guessn == res[0] || minn == guessn) return best;
|
||||
guessn = res[0];
|
||||
splitpen = res[1];
|
||||
} else {
|
||||
p("Too narrow");
|
||||
minn = guessn;
|
||||
li.split(x0+guessn, maxn-guessn,
|
||||
x0+guessn+
|
||||
((1000000/(res[0]+1) - 1000) * (maxn-guessn))/1000,
|
||||
res);
|
||||
res[0] += guessn;
|
||||
if(guessn == res[0] || maxn == guessn) return best;
|
||||
guessn = res[0];
|
||||
splitpen = res[1];
|
||||
}
|
||||
if(minn >= maxn || guessn <= minn || guessn >= maxn) return best;;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
91
Java/media/SimpleLineInfo.java
Normal file
91
Java/media/SimpleLineInfo.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
SimpleLineInfo.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.io.*;
|
||||
import java.awt.*;
|
||||
|
||||
/** A simple implementation of LineInfo, for plain strings in a list
|
||||
* of fonts.
|
||||
*/
|
||||
|
||||
public class SimpleLineInfo implements LineInfo {
|
||||
public static final String rcsid = "$Id: SimpleLineInfo.java,v 1.8 2000/09/19 10:32:00 ajk Exp $";
|
||||
public static boolean dbg = false;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
|
||||
public interface Layout {
|
||||
FontMetrics getFontMetrics(int line);
|
||||
int getWidth(int line);
|
||||
int getCenterLine();
|
||||
}
|
||||
|
||||
String s;
|
||||
Layout l;
|
||||
int cursor;
|
||||
|
||||
SimpleLineInfo(String s, int cursor, Layout l) { this.s = s; this.l = l;
|
||||
this.cursor = cursor;}
|
||||
|
||||
public int getMax() { return s.length(); }
|
||||
public int getCursor() { return cursor; }
|
||||
public int getCenterLine() { return l.getCenterLine(); }
|
||||
|
||||
public void split(int x0, int n, int sug, int[] ret) {
|
||||
int ind = s.indexOf(' ', x0+1);
|
||||
|
||||
if(ind >= x0+n || ind < 0) {
|
||||
// split word
|
||||
ind = 1;
|
||||
ret[0] = 1;
|
||||
ret[1] = 500;
|
||||
} else {
|
||||
while(true) {
|
||||
int ind2 = s.indexOf(' ', ind+1);
|
||||
if(ind2 < 0) break;
|
||||
if(ind2 >= x0+n) break;
|
||||
if(ind2 >= sug) break;
|
||||
ind = ind2;
|
||||
}
|
||||
ret[0] = ind - x0;
|
||||
ret[1] = 0;
|
||||
}
|
||||
p("Split: "+x0+" "+n+" "+sug+" "+ret[0]+" "+ret[1]);
|
||||
}
|
||||
|
||||
public void widthPenalty(int x0, int n, int line, int[] ret) {
|
||||
p("WP: "+x0+" "+n+" "+line);
|
||||
String subs = s.substring(x0, x0+n).trim();
|
||||
int w = l.getFontMetrics(line).stringWidth(subs);
|
||||
int want = l.getWidth(line);
|
||||
ret[0] = (1000*w) / want;
|
||||
if(w > want) {
|
||||
ret[1] = (w-want) * (w-want) / 3;
|
||||
} else {
|
||||
ret[1] = (want - w) / 2;
|
||||
}
|
||||
p("WP: "+x0+" "+n+" "+line+" "+want+" "+w+" Ret: "+ret[0]+" "+ret[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
63
Java/media/SoundScroll.java
Normal file
63
Java/media/SoundScroll.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
SoundScroll.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.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/** A scroll of sound.
|
||||
* The fact that you need to specify the duraction when creating is not good but
|
||||
* we can fix that later somehow.
|
||||
*/
|
||||
public class SoundScroll extends Scroll {
|
||||
public static final String rcsid = "$Id: SoundScroll.java,v 1.3 2000/09/19 10:32:00 ajk Exp $";
|
||||
|
||||
// public abstract void preparePlayer();
|
||||
/** XXX change to play(Span) and get the next at runtime?
|
||||
*/
|
||||
protected SoundScroll(String i) { super(i); }
|
||||
|
||||
Vector obses = new Vector();
|
||||
public void addObs(SoundObs o) {
|
||||
obses.addElement(o);
|
||||
}
|
||||
protected void inform(int event, long l) {
|
||||
for(int i = 0; i<obses.size(); i++)
|
||||
((SoundObs)obses.elementAt(i)).playingAt(event,l);
|
||||
}
|
||||
|
||||
// Cheat: it's currently just a file.
|
||||
File f;
|
||||
public File getFile() { return f; }
|
||||
long d;
|
||||
public long getDurationNanoseconds() { return d; }
|
||||
public SoundScroll(String id, File fn, long dur) {
|
||||
super(id);
|
||||
f = fn;
|
||||
d = dur;
|
||||
}
|
||||
public SoundScroll(String id, String fn, long dur) {
|
||||
super(id);
|
||||
f = new File(fn);
|
||||
d = dur;
|
||||
}
|
||||
}
|
||||
178
Java/media/Span.java
Normal file
178
Java/media/Span.java
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
Span.java
|
||||
*
|
||||
* Copyright (c) 1999, 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.*;
|
||||
|
||||
/** An address span in the stable media streams.
|
||||
* Currently just a silly pointer but will be later extended
|
||||
* to include full tumblers.
|
||||
* <p>
|
||||
* Spans are immutable, just like Strings: all the verb-like method
|
||||
* like join and split return new Span objects.
|
||||
*/
|
||||
|
||||
public class Span {
|
||||
public static final String rcsid = "$Id: Span.java,v 1.9 2001/03/11 19:14:38 veparkki Exp $";
|
||||
public static final boolean dbg = false;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
Address a1;
|
||||
Address a2;
|
||||
|
||||
public Address getStart() { return a1; }
|
||||
public Address getEnd() { return a2; }
|
||||
public long getStartOffs() { return a1.offset; }
|
||||
public long getEndOffs() { return a2.offset; }
|
||||
|
||||
public static Span parse(String str) {
|
||||
StringTokenizer st = new StringTokenizer(str, ":");
|
||||
if(st.countTokens() != 2)
|
||||
throw new ZZError("Wrong number of ':' toks in '"+str+"'");
|
||||
Span s = new Span();
|
||||
s.a1 = Address.parse(st.nextToken());
|
||||
s.a2 = Address.parse(st.nextToken());
|
||||
if(!s.a1.getStream().equals(s.a2.getStream()))
|
||||
throw new ZZError("Must be same stream for now '" + str
|
||||
+"' '"+s.a1.getStream()+"' '"+s.a2.getStream()+"'");
|
||||
return s;
|
||||
}
|
||||
|
||||
public static Span create(Address i1, Address i2) {
|
||||
Span s = new Span();
|
||||
s.a1 = i1; s.a2 = i2;
|
||||
return s;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return a1+":"+a2;
|
||||
}
|
||||
|
||||
public boolean overlaps(Span s) {
|
||||
if(a2.lessThan(s.a1) || s.a2.lessThan(a1)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** The string pointed to by the span.
|
||||
*/
|
||||
public String getString(ZZCell c) {
|
||||
Scroll scr //= c.getSpace().getStringScroll(a1.getStream());
|
||||
= Scroll.obtain((c==null?null:c.getSpace()),
|
||||
a1.getStream());
|
||||
p("Scroll: "+scr);
|
||||
if(scr instanceof StringScroll) {
|
||||
StringScroll s = (StringScroll) scr;
|
||||
int o1 = (int)a1.getOffs();
|
||||
int o2 = (int)a2.getOffs();
|
||||
if(o1 > o2) {
|
||||
// This is allowed
|
||||
if(o1-o2 == 1) return "";
|
||||
// This is not
|
||||
throw new ZZError("Too negative span "+ this);
|
||||
}
|
||||
return s.getString(a1.getOffs(),
|
||||
(int)(o2-o1)+1);
|
||||
} if(scr instanceof ByteScroll) {
|
||||
ByteScroll s = (ByteScroll)scr;
|
||||
return s.getString(a1.getOffs(),
|
||||
(int)(a2.getOffs()-a1.getOffs())+1);
|
||||
}
|
||||
if(scr instanceof CharScroll) {
|
||||
CharScroll s = (CharScroll)scr;
|
||||
return s.getString(a1.getOffs(),
|
||||
(int)(a2.getOffs()-a1.getOffs())+1);
|
||||
}
|
||||
if(scr instanceof SoundScroll) {
|
||||
return "SND " + toString();
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
public Span adjustEdge(int edge, long units) {
|
||||
Address adj = (edge==0?a1:a2);
|
||||
adj = Address.streamOffs(adj.getStream(), adj.getOffs()+units);
|
||||
Address x = (edge==0?adj:a1);
|
||||
Address y = (edge==1?adj:a2);
|
||||
return create(x,y);
|
||||
}
|
||||
public Span[] adjustEdgeLocked(long units, Span other, long allowfudge) {
|
||||
Address adj = a2;
|
||||
adj = Address.streamOffs(adj.getStream(), adj.getOffs()+units);
|
||||
long d = adj.getOffs() - other.a1.getOffs();
|
||||
if(d<0) d = -d;
|
||||
if(d>allowfudge)
|
||||
return new Span[] {
|
||||
create(a1, adj), other
|
||||
};
|
||||
return new Span[] {
|
||||
create(a1, adj),
|
||||
create(Address.streamOffs(adj.getStream(), adj.getOffs()+1),
|
||||
other.a2)
|
||||
};
|
||||
|
||||
}
|
||||
public Span[] splitInHalf() {
|
||||
long off = (a1.getOffs() + a2.getOffs()) / 2;
|
||||
return new Span[] {
|
||||
create(a1, Address.streamOffs(a1.getStream(), off-1)),
|
||||
create(Address.streamOffs(a1.getStream(), off), a2),
|
||||
};
|
||||
}
|
||||
public Span join(Span next, long allowfudge) {
|
||||
if(! a2.getStream().equals(next.a1.getStream()))
|
||||
return null;
|
||||
long diff = a2.getOffs() - next.a1.getOffs();
|
||||
if(diff<0) diff = -diff;
|
||||
if(diff > allowfudge)
|
||||
return null;
|
||||
return create(a1, next.a2);
|
||||
}
|
||||
|
||||
/** Does exactly what substring does to String.
|
||||
* This is in opposition to the other span routines
|
||||
* in which the last address is given, not one beyond!
|
||||
*/
|
||||
public Span subSpan(int o1, int o2) {
|
||||
return create(a1.addOffs(o1), a1.addOffs(o2-1));
|
||||
}
|
||||
public Span subSpan(int o1) {
|
||||
return create(a1.addOffs(o1), a2);
|
||||
}
|
||||
|
||||
/** Whether this span can be joined with the other span.
|
||||
*/
|
||||
public boolean isAppendable(Span s) {
|
||||
return a2.getStream().equals(s.a1.getStream())
|
||||
&& a2.getOffs() == s.a1.getOffs()-1;
|
||||
}
|
||||
|
||||
// XXX Check?
|
||||
public Span append(Span s) {
|
||||
return create(a1, s.a2);
|
||||
}
|
||||
|
||||
|
||||
public long length() {
|
||||
return a2.getOffs() - a1.getOffs() + 1;
|
||||
}
|
||||
|
||||
}
|
||||
45
Java/media/SpanSet.java
Normal file
45
Java/media/SpanSet.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
SpanSet.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.*;
|
||||
|
||||
/** An interface to Flobs that contain spans. This is more a Map than
|
||||
* a Set...
|
||||
* XXX Extend with links, i.e. one-level indirection between
|
||||
* overlaps.
|
||||
*/
|
||||
|
||||
public interface SpanSet {
|
||||
String rcsid = "$Id: SpanSet.java,v 1.4 2000/09/19 10:32:00 ajk Exp $";
|
||||
/** Add a span.
|
||||
*/
|
||||
void addSpan(Span s, Object obj);
|
||||
/** Get the objects corresponding to the spans entered that overlap
|
||||
* the given span. XXX Should be enumeration?
|
||||
*/
|
||||
Object[] overlaps(Span s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
54
Java/media/SpanTree.java
Normal file
54
Java/media/SpanTree.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
SpanTree.java
|
||||
*
|
||||
* Copyright (c) 1999, 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.*;
|
||||
|
||||
/** A structure for putting spans in and obtaining the
|
||||
* matching spans. Not actually a tree yet XXX!
|
||||
*/
|
||||
|
||||
public class SpanTree implements SpanSet {
|
||||
public static final String rcsid = "$Id: SpanTree.java,v 1.4 2000/09/19 10:32:00 ajk Exp $";
|
||||
Vector v = new Vector();
|
||||
Vector vo = new Vector();
|
||||
public void addSpan(Span s, Object uo) {
|
||||
v.addElement(s);
|
||||
vo.addElement(uo);
|
||||
}
|
||||
public Object[] overlaps(Span s) {
|
||||
Vector res = new Vector();
|
||||
int ind = 0;
|
||||
for(Enumeration e = v.elements(); e.hasMoreElements();) {
|
||||
Span s0 = (Span)e.nextElement();
|
||||
if(s.overlaps(s0)) {
|
||||
res.addElement(vo.elementAt(ind));
|
||||
}
|
||||
ind++;
|
||||
}
|
||||
Object[] r = new Object[res.size()];
|
||||
for(int i=0; i<r.length; i++)
|
||||
r[i] = res.elementAt(i);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
289
Java/media/Stream.java
Normal file
289
Java/media/Stream.java
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
Stream.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.*;
|
||||
|
||||
/** Some routines to handle plain text streams.
|
||||
*/
|
||||
|
||||
public class Stream {
|
||||
public static final String rcsid = "$Id: Stream.java,v 1.9 2000/12/04 13:01:10 tjl Exp $";
|
||||
public static boolean dbg = false;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
static final void pa(String s) { System.out.println(s); }
|
||||
|
||||
static public boolean move(ZZCursor curs, String dim, int nchars) {
|
||||
return move(curs, dim, nchars, 1);
|
||||
}
|
||||
|
||||
/** Move by an offset in a stream string.
|
||||
* The last position of the stream is actually one beyond
|
||||
* the last character.
|
||||
* @param curs The cursor to move
|
||||
* @param dim The dimension the stream is along
|
||||
* @param nchars The number of characters to move. May be
|
||||
* positive or negative.
|
||||
* @param lookingDir The direction you want to look from
|
||||
* the cursor. Matters when the cursor
|
||||
* is at the edge of two cells and
|
||||
* positive here means to put it into the
|
||||
* beginning of the next cell and negative
|
||||
* to the end of the preceding cell.
|
||||
* @return false if operation goes past beginning or end.
|
||||
*/
|
||||
static public boolean move(ZZCursor curs, String dim, int nchars,
|
||||
int lookingDir) {
|
||||
int o = curs.getOffs() + nchars;
|
||||
ZZCell nc = curs.get();
|
||||
if(nc == null)
|
||||
throw new ZZError("Moving stream cursor!");
|
||||
while(nc != null && o < 0) {
|
||||
nc = nc.s(dim, -1);
|
||||
if(nc != null)
|
||||
o += nc.getText().length();
|
||||
}
|
||||
ZZCell prev = null;
|
||||
while(nc != null && o > nc.getText().length() -
|
||||
(lookingDir > 0 ? 1 : 0)) {
|
||||
o -= nc.getText().length();
|
||||
prev = nc;
|
||||
nc = nc.s(dim);
|
||||
}
|
||||
if(nc == null) {
|
||||
if(o != 0)
|
||||
return false;
|
||||
else {
|
||||
nc = prev;
|
||||
o = nc.getText().length();
|
||||
}
|
||||
}
|
||||
if(o < 0)
|
||||
throw new ZZError("WHAT? WHAT? WHAT? Neg offset in move");
|
||||
curs.set(nc); curs.setOffs(o);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Find a position along a stream with the given string.
|
||||
* Currently relatively inefficient, unless the cells are relatively
|
||||
* long.
|
||||
*/
|
||||
static public boolean find(ZZCursor from, String dim, int dir,
|
||||
boolean includeThis, String text) {
|
||||
// First, see if there is a match inside the current cell,
|
||||
// done carefully.
|
||||
ZZCell c = from.get();
|
||||
int offs = from.getOffs();
|
||||
|
||||
p("Find: "+c+" "+offs+" "+dim+" "+dir+" "+includeThis+" '"+text+"'");
|
||||
|
||||
String txt = c.getText();
|
||||
char first = text.charAt(0);
|
||||
|
||||
if(!includeThis) offs += dir;
|
||||
|
||||
if(dir > 0) {
|
||||
while(c != null) {
|
||||
while((offs = txt.indexOf(first, offs)) >= 0) {
|
||||
if(isMatch(c, offs, text, dim, from))
|
||||
return true;
|
||||
offs ++;
|
||||
}
|
||||
c = c.s(dim, dir);
|
||||
if(c != null) {
|
||||
txt = c.getText();
|
||||
offs = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while(c != null) {
|
||||
p("Findnegloop: "+c);
|
||||
while((offs = txt.lastIndexOf(first, offs)) >= 0) {
|
||||
p("Findnegloop: try "+ offs);
|
||||
if(isMatch(c, offs, text, dim, from))
|
||||
return true;
|
||||
offs --;
|
||||
}
|
||||
c = c.s(dim, dir);
|
||||
if(c != null) {
|
||||
txt = c.getText();
|
||||
offs = txt.length()-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p("Not found!");
|
||||
|
||||
// Then, we're looking at whole cells the rest of the way.
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Check to see whether the text in the stream is equal to this text.
|
||||
*/
|
||||
static public boolean isMatch(ZZCell c, int offs, String text, String dim) {
|
||||
return isMatch(c, offs, text, dim, null);
|
||||
}
|
||||
|
||||
/** Check whether the match is correct and set the cursor if it is.
|
||||
*/
|
||||
static boolean isMatch(ZZCell c, int offs, String text,
|
||||
String dim, ZZCursor from)
|
||||
{
|
||||
p("Match: "+c+" "+offs+" '"+text+"' "+dim);
|
||||
p("Matching csubstr: '"+c.getText().substring(offs)+"'");
|
||||
ZZCell origc = c;
|
||||
int origoffs = offs;
|
||||
while(c != null) {
|
||||
String ct = c.getText().substring(offs);
|
||||
if(ct.length() >= text.length()) {
|
||||
if(ct.substring(0, text.length()).equals(text)) {
|
||||
if(from != null) {
|
||||
from.set(origc);
|
||||
from.setOffs(origoffs);
|
||||
}
|
||||
p("TRUE!");
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
if(!text.substring(0, ct.length()).equals(ct)) return false;
|
||||
text = text.substring(ct.length());
|
||||
c = c.s(dim);
|
||||
offs = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static public String getString(ZZCursor curs, String dim, int n) {
|
||||
ZZCell c = curs.get();
|
||||
int offs = curs.getOffs();
|
||||
StringBuffer res = new StringBuffer();
|
||||
while(n > 0) {
|
||||
String txt = c.getText();
|
||||
if(offs > 0) txt = txt.substring(offs);
|
||||
if(n <= txt.length()) {
|
||||
res.append(txt.substring(0, n));
|
||||
return res.toString();
|
||||
}
|
||||
res.append(txt);
|
||||
n -= txt.length();
|
||||
offs = 0;
|
||||
c = c.s(dim);
|
||||
if(c == null) return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** A class for moving along the stream, collecting characters.
|
||||
* Part of the interface might be abstracted to an interface like
|
||||
* java.text.CharacterIterator, but in a slightly more restricted subset.
|
||||
* <p>
|
||||
* This class considers the end of the stream the location when it
|
||||
* can't return any characters any more + 1.
|
||||
*/
|
||||
static public class Iterator {
|
||||
final ZZCursorVirtual c;
|
||||
final String dim;
|
||||
|
||||
Iterator(ZZCursorVirtual c, String dim) { this.c = c; this.dim = dim; }
|
||||
|
||||
public void set(ZZCursor c) { this.c.set(c); }
|
||||
|
||||
/** Get the current iterator position.
|
||||
* @return The current position. The position should not be modified.
|
||||
*/
|
||||
public ZZCursor get() { return c; }
|
||||
|
||||
public boolean move(int nsteps) {
|
||||
if(!Stream.move(c, dim, nsteps)) return false;
|
||||
if(c.get().s(dim) == null)
|
||||
// XXX Is this right?
|
||||
if(c.get().getText().length() <= c.getOffs())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean move(int nsteps, int lookingDir) {
|
||||
if(!Stream.move(c, dim, nsteps, lookingDir)) return false;
|
||||
if(c.get().s(dim) == null)
|
||||
if(c.get().getText().length() <= c.getOffs())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
c.set(c.get().h(dim));
|
||||
c.setOffs(0);
|
||||
}
|
||||
|
||||
public void end() {
|
||||
ZZCell cl = c.get().h(dim, 1);
|
||||
c.set(cl);
|
||||
c.setOffs(cl.getText().length());
|
||||
}
|
||||
|
||||
public void end(int dir) {
|
||||
if(dir < 0) start(); else end();
|
||||
}
|
||||
|
||||
public boolean find(int dir, boolean includeThis, String text) {
|
||||
return Stream.find(c, dim, dir, includeThis, text);
|
||||
}
|
||||
|
||||
/** Get the current character.
|
||||
* Returns -1 for the end-of-stream.
|
||||
*/
|
||||
public char getChar() {
|
||||
return getChar(0);
|
||||
}
|
||||
|
||||
public char getChar(int offs) {
|
||||
ZZCursorVirtual c1 = new ZZCursorVirtual(c);
|
||||
// Move even if zero, to get the right
|
||||
// directional position.
|
||||
if(!Stream.move(c1, dim, offs, 1)) return (char)-1;
|
||||
String str = c1.get().getText();
|
||||
if(c1.getOffs() >= str.length()) return (char)-1;
|
||||
return str.charAt(c1.getOffs());
|
||||
}
|
||||
|
||||
public String getString(int n, int dir) {
|
||||
// SLOW!!!!
|
||||
ZZCursorVirtual c1 = new ZZCursorVirtual(c);
|
||||
if(dir < 0) {
|
||||
if(!Stream.move(c1, dim, -n)) return null;
|
||||
}
|
||||
return Stream.getString(c1, dim, n);
|
||||
}
|
||||
}
|
||||
|
||||
static public Iterator getIterator(ZZCursor c, String dim) {
|
||||
return new Iterator(new ZZCursorVirtual(c), dim);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
310
Java/media/StringScroll.java
Normal file
310
Java/media/StringScroll.java
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
StringScroll.java
|
||||
*
|
||||
* Copyright (c) 1999-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,
|
||||
* multiformat and UTF-8 format support by Antti-Juhani Kaijanaho
|
||||
*/
|
||||
package org.gzigzag;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
/** A scroll of chars. May later have holes etc. from expunging,
|
||||
* but basically the point is that the address to content mapping
|
||||
* is stable and will not change whatever is done.
|
||||
*
|
||||
* The new StringScroll format is based on UTF-8. After the initial
|
||||
* signature described shortly, the scroll writable is a plain UTF-8
|
||||
* sequence. The whole StringScroll should be
|
||||
*
|
||||
* The signature of the new StringSroll format is the octet sequence
|
||||
* given in the "signature" attribute.
|
||||
*/
|
||||
public class StringScroll extends Scroll{
|
||||
public static final String rcsid = "$Id: StringScroll.java,v 1.8 2001/02/09 08:30:54 ajk Exp $";
|
||||
|
||||
/** Number of characters in a new-format "record". Records are
|
||||
* implicit in the actual file; they are explicit only in the
|
||||
* in-memory index. */
|
||||
static int recordsize = 1000;
|
||||
|
||||
private Writable f;
|
||||
private boolean readonly;
|
||||
|
||||
private interface SSImpl {
|
||||
char[] get(long start, int n);
|
||||
long curEnd();
|
||||
long append(char[] bytes);
|
||||
}
|
||||
|
||||
private SSImpl ss;
|
||||
|
||||
private byte[] signature = new byte[]{ (byte) 0xef, (byte) 0xbb, (byte) 0xbf,
|
||||
(byte) 0x20, (byte) 0x20, (byte) 0x5a,
|
||||
(byte) 0x5a, (byte) 0x53, (byte) 0x53,
|
||||
(byte) 0x2d, (byte) 0x30, (byte) 0x0a };
|
||||
|
||||
private synchronized void determineFormat() {
|
||||
boolean newformat;
|
||||
if (f.length() == 0) {
|
||||
if (readonly) {
|
||||
newformat = false;
|
||||
} else {
|
||||
f.write(0, signature);
|
||||
newformat = true;
|
||||
}
|
||||
} else if (f.length() < signature.length) {
|
||||
newformat = false;
|
||||
} else {
|
||||
byte[] sig = f.read(0, signature.length);
|
||||
// assume it's new format; check signature and note it's
|
||||
// old format if signature does not match
|
||||
newformat = true;
|
||||
for (int i = 0; i < sig.length; i++) {
|
||||
if (sig[i] != signature[i]) {
|
||||
newformat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newformat) ss = new UTF8Format(); else ss = new OldFormat();
|
||||
}
|
||||
|
||||
public StringScroll(String id, Writable w, boolean ro) {
|
||||
super(id);
|
||||
this.readonly = ro;
|
||||
f = w;
|
||||
determineFormat();
|
||||
}
|
||||
|
||||
/** Get an array of characters of length n starting from the
|
||||
* startth (or so) character. */
|
||||
public synchronized char[] get(long start, int n) {
|
||||
return ss.get(start, n);
|
||||
}
|
||||
|
||||
// XXX ENCODING - currently 2 bytes / char :(
|
||||
public String getString(long start, int n) {
|
||||
char[] b = get(start,n);
|
||||
String s = new String(b);
|
||||
// p("GETS: "+start+" "+n+" "+b+" '"+s+"'");
|
||||
return s;
|
||||
}
|
||||
|
||||
public long curEnd() {
|
||||
return ss.curEnd();
|
||||
}
|
||||
|
||||
public synchronized long append(String b) {
|
||||
p("Append - length: "+b.length());
|
||||
return append(b.toCharArray());
|
||||
}
|
||||
|
||||
public synchronized long append(char[] bytes) {
|
||||
return ss.append(bytes);
|
||||
}
|
||||
|
||||
private class UTF8Format implements SSImpl {
|
||||
/** A private copy of recordsize in order to avoid changing
|
||||
the parent recordsize from messing up the index. */
|
||||
private int recordsize;
|
||||
|
||||
/** We store in the index the offset - counting from the
|
||||
writable's start - of each recordsize character so that
|
||||
index[n] contains the offset of the character at the
|
||||
address n*recordsize. */
|
||||
private Vector index;
|
||||
|
||||
/** Cache the address to be given to the next appended character. */
|
||||
private long nextAddr;
|
||||
|
||||
/** Put an offset for an address (which must be a multiple of
|
||||
* recordsize) into the index. */
|
||||
private void putOffs(long addr, long offs) {
|
||||
if (addr % recordsize != 0) {
|
||||
throw new ZZError("Address is not a record boundary");
|
||||
}
|
||||
|
||||
// FIXME: Vector can index only using int's. This is bad.
|
||||
long idx = addr / recordsize;
|
||||
if (idx > Integer.MAX_VALUE) {
|
||||
throw new ZZError("Internal error: idx too big");
|
||||
}
|
||||
|
||||
if (idx >= index.size()) index.setSize((int) idx + 1);
|
||||
|
||||
index.setElementAt(new Long(offs), (int)idx);
|
||||
|
||||
// sanity check
|
||||
if (lookupOffs(addr) != offs) {
|
||||
throw new ZZError("Internal error: index add failure");
|
||||
}
|
||||
}
|
||||
|
||||
/** Look offset up by address (must be a multiple of
|
||||
* recordsize). */
|
||||
private long lookupOffs(long addr) {
|
||||
if (addr % recordsize != 0) {
|
||||
throw new ZZError("Address is not in index");
|
||||
}
|
||||
|
||||
// FIXME: Vector can index only using int's. This is bad.
|
||||
long idx = addr / recordsize;
|
||||
if (idx > Integer.MAX_VALUE) {
|
||||
throw new ZZError("Internal error: idx too big");
|
||||
}
|
||||
|
||||
return ((Long) index.elementAt((int) idx)).longValue();
|
||||
}
|
||||
|
||||
public UTF8Format() {
|
||||
index = new Vector();
|
||||
recordsize = StringScroll.this.recordsize;
|
||||
|
||||
// Build the index by scanning the whole scroll
|
||||
long offs = signature.length;
|
||||
long addr = 0;
|
||||
while (offs < f.length()) {
|
||||
UTF8Char uc = new UTF8Char(f, offs);
|
||||
|
||||
if (addr % recordsize == 0) {
|
||||
putOffs(addr, offs);
|
||||
}
|
||||
|
||||
++addr;
|
||||
offs += uc.b.length;
|
||||
}
|
||||
nextAddr = addr;
|
||||
}
|
||||
|
||||
// Implementation of SSImpl
|
||||
|
||||
public char[] get(long start, int n) {
|
||||
char[] rv = new char[n];
|
||||
|
||||
int acc = 0;
|
||||
// The loop body will read at most n characters starting
|
||||
// from address start+acc by slurping the whole record and
|
||||
// scanning there. The body is run repeatedly until we
|
||||
// have exactly n characters in rv.
|
||||
while (acc < n) {
|
||||
// Step 1: Read the current record completely into memory
|
||||
long recstart = (start + acc) - (start + acc) % recordsize;
|
||||
long recoffs = lookupOffs(recstart);
|
||||
byte[] record = f.read(recoffs, recordsize);
|
||||
// Step 2: Scan the record for the start address
|
||||
long sad = recstart;
|
||||
long sof = 0;
|
||||
while (sof < record.length) {
|
||||
if (sad == start + acc) break;
|
||||
UTF8Char uc = new UTF8Char(record, (int) sof);
|
||||
sof += uc.b.length;
|
||||
sad++;
|
||||
}
|
||||
// Step 3: Convert at most n bytes and at most to the
|
||||
// end of the record from record[sad] into rv, using acc as
|
||||
// the rv index.
|
||||
for (int i = (int) sof; i < record.length;) {
|
||||
if (acc == n) break;
|
||||
UTF8Char uc = new UTF8Char(record, i);
|
||||
rv[acc++] = uc.c;
|
||||
i += uc.b.length;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
public long curEnd() {
|
||||
return nextAddr;
|
||||
}
|
||||
|
||||
public long append(char[] chs) {
|
||||
// We want to avoid doing unnecessary writes. Therefore,
|
||||
// we first build an array of UTF-8 characters. Then we
|
||||
// flatten it into an onedimensional array containing the
|
||||
// UTF-8 representations in a row and write that.
|
||||
UTF8Char[] ucs = new UTF8Char[chs.length];
|
||||
|
||||
long rv = nextAddr;
|
||||
|
||||
int len = 0;
|
||||
for (int i = 0; i < chs.length; i++) {
|
||||
ucs[i] = new UTF8Char(chs[i]);
|
||||
len += ucs[i].b.length;
|
||||
}
|
||||
|
||||
byte[] block = new byte[len];
|
||||
int bi = 0;
|
||||
for (int i = 0; i < ucs.length; i++) {
|
||||
// Update index
|
||||
if ((nextAddr + i) % recordsize == 0) {
|
||||
putOffs(nextAddr + i, f.length() + bi);
|
||||
}
|
||||
// Copy UTF-8 octets to block.
|
||||
for (int j = 0; j < ucs[i].b.length; j++) {
|
||||
block[bi++] = ucs[i].b[j];
|
||||
}
|
||||
}
|
||||
f.write(f.length(), block);
|
||||
nextAddr += ucs.length;
|
||||
|
||||
if (nextAddr - nextAddr % recordsize
|
||||
!= (index.size() - 1) * recordsize) {
|
||||
throw new ZZError("Internal error: index not consistent");
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class OldFormat implements SSImpl {
|
||||
public synchronized char[] get(long start, int n) {
|
||||
byte[] b = f.read(start*2, n*2);
|
||||
char[] c = new char[n];
|
||||
for(int i=0; i<n; i++)
|
||||
c[i] = (char)((b[i*2]<<8) | (b[i*2+1]<<0));
|
||||
return c;
|
||||
}
|
||||
|
||||
public long curEnd() {
|
||||
return f.length() / 2;
|
||||
}
|
||||
|
||||
public synchronized long append(char[] bytes) {
|
||||
if(readonly) throw new ZZError("Can't append to readonly scroll");
|
||||
|
||||
byte[] byt = new byte[bytes.length * 2];
|
||||
for(int i=0; i<bytes.length; i++) {
|
||||
byt[i*2] = (byte)((bytes[i] >> 8) & 0xff);
|
||||
byt[i*2+1] = (byte)((bytes[i] >> 0) & 0xff);
|
||||
}
|
||||
|
||||
// XXX race?
|
||||
long c = f.length();
|
||||
if(c%1 != 0) throw new Error("Argh! Odd number of bytes");
|
||||
f.write(c, byt);
|
||||
|
||||
return c / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
189
Java/media/TestLines.java
Normal file
189
Java/media/TestLines.java
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
TestLines.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.io.*;
|
||||
import java.awt.*;
|
||||
|
||||
/** Some tests for line breaking.
|
||||
*/
|
||||
|
||||
public class TestLines {
|
||||
public static final String rcsid = "$Id: TestLines.java,v 1.10 2001/02/23 15:01:10 tjl Exp $";
|
||||
static final boolean dbg = false;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
|
||||
Frame f = new Frame();
|
||||
|
||||
/* Jikes won't eat this any more in new versions due to äö.
|
||||
static final String str = "Pikku stringi testataksemme rivinpilkkomista. "+
|
||||
"Tällä kertaa kirjoitammekin sen suomeksi - englanninkielisiä lukijoitamme "+
|
||||
"varmaankin hämmästyttää. Etenkin ääkköset. Tämä merkkijono piirretään "+
|
||||
"näytölle monta kertaa erilaisena, siis \"kursori\" eri kohdalle laitettuna. "+
|
||||
"Tästä voidaan sitten nähdä, toimiiko rivien pilkkominen palasiksi oikein. " +
|
||||
"Itse asiassa merkkijonoa tulee vielä jonkin verran pidentää koska muuten " +
|
||||
"emme ehdi nähdä kaikkia efektejä. Hauskaahan tästä tulee vasta sitten " +
|
||||
"kun voimme oikeasti muokata näin näytettyä tekstiä mutta tämä testi on " +
|
||||
"tärkeä askel siihen suuntaan mentäessä."
|
||||
;
|
||||
|
||||
*/
|
||||
|
||||
static final String str = "lsjifs lefjis elfj sef jsle fjslf ";
|
||||
|
||||
class MyLayout implements SimpleLineInfo.Layout {
|
||||
int c;
|
||||
MyLayout(int c) { this.c = c; }
|
||||
public FontMetrics getFontMetrics(int line) {
|
||||
return fm[find(c, line)];
|
||||
}
|
||||
public int getWidth(int line) {
|
||||
return width(c, line);
|
||||
}
|
||||
public int getCenterLine() { return 0; }
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] argv) {
|
||||
TestLines t = new TestLines();
|
||||
t.br();
|
||||
}
|
||||
|
||||
int NTESTS = 1;
|
||||
|
||||
int[][] lines = new int[NTESTS][];
|
||||
Font[] fonts = new Font[64];
|
||||
FontMetrics[] fm = new FontMetrics[fonts.length];
|
||||
{ for(int i=0; i<fonts.length; i++) {
|
||||
fonts[i] = new Font("SansSerif", Font.PLAIN, i+1);
|
||||
// fm[i] = Toolkit.getDefaultToolkit().getFontMetrics(fonts[i]);
|
||||
fm[i] = f.getFontMetrics(fonts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Give the index to the fonts[] array for the given line of
|
||||
* the given case.
|
||||
*/
|
||||
int find(int cas, int line) {
|
||||
if(cas == 0)
|
||||
return 10 + line;
|
||||
else if(cas == 1) {
|
||||
int w = 30 - line;
|
||||
if(w < 3) return 3;
|
||||
return w;
|
||||
} else if(cas == 2) {
|
||||
return (int)(8 + 10 / (1 + (line * line)/30.0));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int width(int cas, int line) {
|
||||
if(cas == 0) {
|
||||
int w = 100 + 20 * line;
|
||||
if(w > 400) w = 400;
|
||||
return w;
|
||||
} else if(cas == 1) {
|
||||
int w =300 - 20 * line;
|
||||
if(w < 50) return 50;
|
||||
return w;
|
||||
} else if(cas == 2) {
|
||||
return (int)(100 + 200.0 / (1 + (line * line)/40.0));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int curs = 0;
|
||||
int dir = 1;
|
||||
|
||||
public TestLines() {
|
||||
}
|
||||
|
||||
public void br() {
|
||||
|
||||
|
||||
Component cp;
|
||||
f.add(
|
||||
cp= new Component() {
|
||||
Image cache;
|
||||
public void paint(Graphics g0) {
|
||||
Thread.dumpStack();
|
||||
if(lines == null) return;
|
||||
if(cache==null) {
|
||||
cache = createImage(800,800);
|
||||
}
|
||||
Graphics g = cache.getGraphics();
|
||||
g.setColor(getBackground());
|
||||
g.fillRect(0, 0, 800, 800);
|
||||
for(int set = 0; set < lines.length; set++) {
|
||||
if(lines[set] == null) return;
|
||||
int cur = 0;
|
||||
int x = 20 + 400 * set;
|
||||
int y = 100;
|
||||
int line = lines[set][0];
|
||||
for(int i=0; i<lines[set].length-1; i++) {
|
||||
|
||||
int cas = 2;
|
||||
|
||||
FontMetrics metr = fm[find(cas, line)];
|
||||
y += metr.getLeading() + metr.getAscent();
|
||||
g.setColor(Color.black);
|
||||
g.setFont(fonts[find(cas, line)]);
|
||||
g.drawString(str.substring(cur, lines[set][i+1]).trim(), x, y);
|
||||
if(curs >= cur && curs < lines[set][i+1]) {
|
||||
// Trim is wrong :(
|
||||
int cw = metr.stringWidth(str.substring(cur, curs).trim());
|
||||
g.setColor(Color.blue);
|
||||
g.drawLine(x+cw, y-metr.getAscent(),
|
||||
x+cw, y+metr.getDescent());
|
||||
}
|
||||
|
||||
g.setColor(Color.red);
|
||||
g.drawLine(x+width(cas, line), y-metr.getAscent(),
|
||||
x+width(cas,line), y+metr.getDescent());
|
||||
cur = lines[set][i+1];
|
||||
y += metr.getDescent();
|
||||
line ++;
|
||||
}
|
||||
}
|
||||
g0.drawImage(cache, 0, 0, null);
|
||||
}
|
||||
});
|
||||
f.setSize(800,800);
|
||||
|
||||
SimpleLineBreaker slb = new SimpleLineBreaker();
|
||||
f.show();
|
||||
|
||||
while(true) {
|
||||
for(int i=0; i<lines.length; i++) {
|
||||
int[] brk = slb.breakLines(
|
||||
new SimpleLineInfo(str, curs, new MyLayout(2)));
|
||||
lines[i] = brk;
|
||||
}
|
||||
cp.paint(cp.getGraphics());
|
||||
for(int k = 0; k<5; k++) {
|
||||
curs += dir;
|
||||
if(curs <= 0 || curs >= str.length()-5) dir = -dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
245
Java/media/UTF8Char.java
Normal file
245
Java/media/UTF8Char.java
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
UTF8Char.java
|
||||
*
|
||||
* 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 Antti-Juhani Kaijanaho
|
||||
*/
|
||||
package org.gzigzag;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class UTF8Char {
|
||||
public static final String rcsid = "$Id: UTF8Char.java,v 1.3 2001/03/21 10:01:21 ajk Exp $";
|
||||
|
||||
public char c;
|
||||
public byte[] b;
|
||||
|
||||
/* UTF-8 <-> Java char conversion is table-driven. This code is
|
||||
* adapted from CatDVI. */
|
||||
|
||||
private static class ConvOctet {
|
||||
/** The number of variable bits, 1-8 */
|
||||
public int numbits;
|
||||
/** The template for this octet */
|
||||
public byte octet;
|
||||
|
||||
public ConvOctet(int n, byte o) {
|
||||
numbits = n;
|
||||
octet = o;
|
||||
}
|
||||
|
||||
public ConvOctet(int n, int o) {
|
||||
this(n, (byte) o);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConvEntry {
|
||||
/** Maximum UCS-4 value encodable using this entry. */
|
||||
public char maxval;
|
||||
/** Info on each octet. */
|
||||
ConvOctet[] template;
|
||||
|
||||
public ConvEntry(char maxval, ConvOctet[] template) {
|
||||
this.maxval = maxval;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public ConvEntry(int maxval, ConvOctet[] template) {
|
||||
this((char) maxval, template);
|
||||
}
|
||||
|
||||
public final int len() { return template.length; }
|
||||
}
|
||||
|
||||
private static final ConvEntry[] convtbl =
|
||||
new ConvEntry[] {
|
||||
new ConvEntry (0x7f,
|
||||
new ConvOctet[] {
|
||||
new ConvOctet(7, 0)
|
||||
}),
|
||||
new ConvEntry (0x7ff,
|
||||
new ConvOctet[] {
|
||||
new ConvOctet(5, 0xc0),
|
||||
new ConvOctet(6, 0x80)
|
||||
}),
|
||||
new ConvEntry (0xffff,
|
||||
new ConvOctet[] {
|
||||
new ConvOctet(4, 0xe0),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80)
|
||||
}),
|
||||
new ConvEntry (0x1fffff,
|
||||
new ConvOctet[] {
|
||||
new ConvOctet(3, 0xf0),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80)
|
||||
}),
|
||||
new ConvEntry (0x3ffffff,
|
||||
new ConvOctet[] {
|
||||
new ConvOctet(2, 0xf4),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80)
|
||||
}),
|
||||
new ConvEntry (0x7fffffff,
|
||||
new ConvOctet[] {
|
||||
new ConvOctet(1, 0xfc),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80),
|
||||
new ConvOctet(6, 0x80),
|
||||
})
|
||||
};
|
||||
|
||||
/** Convert a Java char into an UTF-8 octet stream. */
|
||||
public static byte[] charToUTF8(char c) {
|
||||
// Stage 1: Determine which ConvEntry to use. We use the
|
||||
// maxval attribute for this: the ConvEntry with smallest
|
||||
// maxval where the char fits is used.
|
||||
ConvEntry e = null;
|
||||
for (int i = 0; i < convtbl.length; i++) {
|
||||
if (c <= convtbl[i].maxval) {
|
||||
e = convtbl[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (e == null) throw new ZZError("character has no UTF-8 representation");
|
||||
|
||||
// Stage 2: Do the conversion from right to left.
|
||||
byte[] rv = new byte[e.len()];
|
||||
for (int i = rv.length - 1; i >= 0; --i) {
|
||||
/* At each iteration we first apply the initial bit
|
||||
pattern and then patch the rest with the indicated
|
||||
number of lower-order bits in code. When we are done,
|
||||
we shift these out. */
|
||||
int numbits = e.template[i].numbits;
|
||||
rv[i] = e.template[i].octet;
|
||||
rv[i] |= ((1 << numbits) - 1) & c;
|
||||
c = (char) (c >> numbits);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static class UTF8ToCharRV {
|
||||
public char c;
|
||||
public int len;
|
||||
public UTF8ToCharRV(char c, int len) {
|
||||
this.c = c;
|
||||
this.len = len;
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidChar extends ZZError {
|
||||
public InvalidChar(String s) { super(s); }
|
||||
}
|
||||
|
||||
/** Determine the ConvEntry to be used. We determine this
|
||||
using the first octet's template. */
|
||||
private static ConvEntry UTF8ConvEntry(byte o) {
|
||||
for (int i = 0; i < convtbl.length; i++) {
|
||||
byte b = (byte) (o & ~((1 << convtbl[i].template[0].numbits) - 1));
|
||||
if (convtbl[i].template[0].octet == b) {
|
||||
return convtbl[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/** Find out the length of an UTF-8 sequence based on the first
|
||||
* octet. */
|
||||
public static int UTF8Len(byte o) {
|
||||
ConvEntry e = UTF8ConvEntry(o);
|
||||
if (e == null) throw new InvalidChar("this is no UTF-8 character");
|
||||
return e.len();
|
||||
}
|
||||
|
||||
private static UTF8ToCharRV UTF8ToChar(byte[] array, int start) {
|
||||
ConvEntry e = UTF8ConvEntry(array[start]);
|
||||
if (e == null) return null;
|
||||
|
||||
// Decode the octet stram.
|
||||
char rv = 0;
|
||||
for (int i = 0; i < e.template.length; i++) {
|
||||
byte mask = (byte) ((1 << e.template[i].numbits) - 1);
|
||||
byte fixed = (byte) (array[start + i] & ~mask);
|
||||
byte bits = (byte) (array[start + i] & mask);
|
||||
if (fixed != e.template[i].octet) throw new ZZError("Invalid UTF-8 character");
|
||||
rv = (char) ((rv << e.template[i].numbits) | bits);
|
||||
}
|
||||
return new UTF8ToCharRV(rv, e.template.length);
|
||||
}
|
||||
|
||||
private static void init(UTF8Char c, UTF8ToCharRV r, byte[] a, int start) {
|
||||
if (r == null) throw new InvalidChar("Invalid UTF-8 character");
|
||||
c.c = r.c;
|
||||
c.b = new byte[r.len];
|
||||
for (int i = 0; i < c.b.length; i++) {
|
||||
byte b = a[start + i];
|
||||
c.b[i] = b;
|
||||
}
|
||||
}
|
||||
|
||||
private UTF8Char(UTF8ToCharRV r, byte[] a, int start) {
|
||||
init(this, r, a, start);
|
||||
}
|
||||
|
||||
public UTF8Char tryFromUTF8(byte[] a, int start) {
|
||||
UTF8ToCharRV r = UTF8ToChar(a, start);
|
||||
if (r == null) return null;
|
||||
return new UTF8Char(r, a, start);
|
||||
}
|
||||
|
||||
/** Create an UTF-8 char from the byte stream (bytes after the
|
||||
* character are ignored). You can determine how many bytes was
|
||||
* used by invoking UTF8Len on the created object. */
|
||||
public UTF8Char(byte[] a) { this(a, 0); }
|
||||
public UTF8Char(byte[] a, int start) {
|
||||
init(this, UTF8ToChar(a, start), a, start);
|
||||
}
|
||||
|
||||
public UTF8Char(char c) {
|
||||
this.c = c;
|
||||
b = charToUTF8(c);
|
||||
}
|
||||
|
||||
public UTF8Char(Writable w, long offs) {
|
||||
long len = (w.length() - offs < 6) ? w.length() - offs : 6;
|
||||
byte[] a = w.read(offs, (int)len);
|
||||
init(this, UTF8ToChar(a, 0), a, 0);
|
||||
}
|
||||
|
||||
static public void main(String argv[]) {
|
||||
FileWritable fw;
|
||||
try {
|
||||
RandomAccessFile raf = new RandomAccessFile("test.utf8", "rw");
|
||||
fw = new FileWritable(raf);
|
||||
} catch (IOException e) {
|
||||
throw new ZZError("" + e);
|
||||
}
|
||||
|
||||
long offs = 0;
|
||||
while (offs < fw.length()) {
|
||||
UTF8Char uc = new UTF8Char(fw, offs);
|
||||
System.out.println("H: " + (long) uc.c);
|
||||
offs += uc.b.length;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
655
Java/media/VStream.java
Normal file
655
Java/media/VStream.java
Normal file
@@ -0,0 +1,655 @@
|
||||
/*
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
100
Java/media/ZZDefaultText.java
Normal file
100
Java/media/ZZDefaultText.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
ZZDefaultText.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.awt.*;
|
||||
|
||||
/** A simple implementation of ZZText.
|
||||
*/
|
||||
|
||||
public class ZZDefaultText extends ZZText {
|
||||
String rcsid = "$Id: ZZDefaultText.java,v 1.2 2000/10/19 17:04:26 tjl Exp $";
|
||||
|
||||
public String getText(ZZCell c) {
|
||||
return c.getText();
|
||||
}
|
||||
|
||||
public void setText(ZZCell c, String s) {
|
||||
c.disconnect("d.reftext", 1);
|
||||
// XXX Delete all cells there too?
|
||||
c.setText(s);
|
||||
}
|
||||
|
||||
public boolean isRef(ZZCell c) {
|
||||
return c.s("d.reftext") != null;
|
||||
}
|
||||
|
||||
public void delete(ZZCell c, int start) {
|
||||
// XXX faster
|
||||
delete(c, start, getText(c).length());
|
||||
}
|
||||
|
||||
public void delete(ZZCell c, int start, int end) {
|
||||
if(isRef(c)) {
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
public void insertNewRef(ZZCell c, String txt, int offs) {
|
||||
ensureRef(c);
|
||||
}
|
||||
|
||||
public void insertRef(ZZCell c, Span sp, int offs) {
|
||||
ensureRef(c);
|
||||
}
|
||||
|
||||
public Span[] getSpans(ZZCell c) {
|
||||
LoopDetector ld = new LoopDetector();
|
||||
ZZCell v = c.s("d.reftext");
|
||||
return null;
|
||||
}
|
||||
public Span[] getSpans(ZZCell c, int start) {
|
||||
LoopDetector ld = new LoopDetector();
|
||||
ZZCell v = c.s("d.reftext");
|
||||
return null;
|
||||
}
|
||||
public Span[] getSpans(ZZCell c, int start, int end) {
|
||||
LoopDetector ld = new LoopDetector();
|
||||
ZZCell v = c.s("d.reftext");
|
||||
return null;
|
||||
}
|
||||
public void setSpans(ZZCell c, Span[] spans) {
|
||||
}
|
||||
|
||||
|
||||
Span makeSpan(ZZCell c, String s) {
|
||||
StringScroll sc = c.getSpace().getStringScroll();
|
||||
long offs = sc.append(s);
|
||||
return Span.create(Address.scrollOffs(sc, offs),
|
||||
Address.scrollOffs(sc, offs+s.length()-1));
|
||||
}
|
||||
|
||||
void ensureRef(ZZCell c) {
|
||||
if(c.s("d.reftext") == null) {
|
||||
Span sp = makeSpan(c, getText(c));
|
||||
ZZCell n = c.N("d.reftext", 1);
|
||||
n.setSpan(sp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
57
Java/media/ZZHumber.java
Normal file
57
Java/media/ZZHumber.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
ZZCellScroll.java
|
||||
*
|
||||
* Copyright (c) 1999, 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.io.*;
|
||||
|
||||
/** A package for representing, reading and writing huge numbers.
|
||||
* Humbers are described in Ted Nelson's Literary Machines.
|
||||
* The ZZHumber objects are immutable, like the Java String class.
|
||||
* XXX Not yet working
|
||||
*/
|
||||
|
||||
// Immutable
|
||||
public class ZZHumber {
|
||||
public static final String rcsid = "$Id: ZZHumber.java,v 1.3 2000/09/19 10:32:00 ajk Exp $";
|
||||
byte[] bytes; // The raw humber bytes.
|
||||
public boolean equals(Object o) {
|
||||
ZZHumber h = (ZZHumber) o;
|
||||
if(h.bytes.length != bytes.length) return false;
|
||||
for(int i=0; i<bytes.length; i++) {
|
||||
if(h.bytes[i] != bytes[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
byte[] getBytes() { return bytes; }
|
||||
|
||||
public static ZZHumber read(DataInput d) {
|
||||
// XXX
|
||||
return null;
|
||||
}
|
||||
/** Returns a humber one greater than the current one */
|
||||
ZZHumber next() {
|
||||
// XXX
|
||||
return null;
|
||||
}
|
||||
}
|
||||
115
Java/media/ZZSoundView.java
Normal file
115
Java/media/ZZSoundView.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
ZZSoundView.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.awt.*;
|
||||
|
||||
/** A view showing a sound vstream on a sound scroll.
|
||||
* Assumes that all cells in the d.2 rank come from the same scroll.
|
||||
*/
|
||||
|
||||
public class ZZSoundView extends ZZViewComponent {
|
||||
public static final String rcsid = "$Id: ZZSoundView.java,v 1.8 2000/11/01 08:12:49 tjl Exp $";
|
||||
public static boolean dbg = true;
|
||||
void p(String s) { if(dbg) System.out.println(s); }
|
||||
void pa(String s) { System.out.println(s); }
|
||||
|
||||
public ZZSoundView(ZZCell viewCell0) {
|
||||
super(viewCell0);
|
||||
setBackground(new Color(150,150,255));
|
||||
}
|
||||
|
||||
ZZCell[] rank;
|
||||
int[] t0; int[] t1; // in pixels
|
||||
|
||||
int top = 10; int bottom = 10;
|
||||
int right = 10;
|
||||
|
||||
public boolean reraster() { return false; }
|
||||
|
||||
public void paintInto(Graphics gr) {
|
||||
synchronized(viewCell.getSpace()) {
|
||||
Dimension size = getSize();
|
||||
|
||||
Insets ins = getInsets();
|
||||
gr.setColor(getBackground());
|
||||
gr.fillRect(ins.left, ins.top,
|
||||
size.width-ins.left-ins.right, size.height-ins.top-ins.bottom);
|
||||
gr.setColor(Color.black);
|
||||
|
||||
// assume vertical display - that way putting in transcription text is easy
|
||||
|
||||
ZZCell cursor = viewCell.h("d.cursor-cargo",-1).
|
||||
h("d.cursor", -1);
|
||||
Span s = cursor.getSpan();
|
||||
if(s==null) {
|
||||
gr.drawString("Not a span", 0, size.height/2);
|
||||
return;
|
||||
}
|
||||
Address start = s.getStart();
|
||||
Address end = s.getEnd();
|
||||
|
||||
Scroll scr0 = start.getScroll(viewCell.getSpace());
|
||||
if(!(scr0 instanceof SoundScroll)) {
|
||||
gr.drawString("Wrong type:"+scr0, 0, size.height/2);
|
||||
return;
|
||||
}
|
||||
SoundScroll scr = (SoundScroll)scr0;
|
||||
|
||||
long len = scr.getDurationNanoseconds();
|
||||
|
||||
ZZCell h = cursor.h("d.2", -1);
|
||||
rank = h.readRank("d.2", 1, true, null);
|
||||
|
||||
t0 = new int[rank.length];
|
||||
t1 = new int[rank.length];
|
||||
|
||||
int l = size.height - top - bottom;
|
||||
|
||||
gr.drawLine(right, top, right, size.height-bottom);
|
||||
|
||||
for(int i=0; i<rank.length; i++) {
|
||||
Span sp = rank[i].getSpan();
|
||||
if(sp==null) return;
|
||||
Address curstart = sp.getStart();
|
||||
Address curend = sp.getEnd();
|
||||
t0[i] = (int)((l*curstart.getOffs())/len);
|
||||
t1[i] = (int)((l*curend.getOffs())/len);
|
||||
|
||||
|
||||
if(rank[i] == cursor)
|
||||
gr.setColor(Color.white);
|
||||
|
||||
gr.drawLine(right, t0[i], right+5, t0[i]);
|
||||
gr.drawLine(right, t1[i], right+5, t1[i]);
|
||||
gr.drawLine(right+1, t0[i], right+1, t1[i]);
|
||||
gr.drawLine(right+2, t0[i], right+2, t1[i]);
|
||||
|
||||
if(rank[i] == cursor)
|
||||
gr.setColor(Color.black);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
117
Java/media/ZZText.java
Normal file
117
Java/media/ZZText.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
ZZText.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.awt.*;
|
||||
|
||||
/** An interface for getting or putting text in cells.
|
||||
* Used e.g. to implement multilingual text.
|
||||
* Handles referential text as well.
|
||||
*/
|
||||
|
||||
public abstract class ZZText {
|
||||
public static final String rcsid = "$Id: ZZText.java,v 1.2 2000/10/19 17:04:26 tjl Exp $";
|
||||
|
||||
/** Get the string in a given cell, whether referential or non-referential.
|
||||
*/
|
||||
public abstract String getText(ZZCell c);
|
||||
|
||||
/** Set the string in the given cell non-referentially.
|
||||
*/
|
||||
public abstract void setText(ZZCell c, String s);
|
||||
|
||||
/** Whether a given cell is referential.
|
||||
*/
|
||||
public abstract boolean isRef(ZZCell c);
|
||||
|
||||
/** Insert the given text into the cell.
|
||||
* If the cell is referential, insert referentially by creating
|
||||
* a new Span for this text. Else just handle characters.
|
||||
*/
|
||||
public void insert(ZZCell c, String txt, int offs) {
|
||||
if(isRef(c)) {
|
||||
insertNewRef(c, txt, offs);
|
||||
} else {
|
||||
String s = getText(c);
|
||||
setText(c, s.substring(0, offs) + txt + s.substring(offs));
|
||||
}
|
||||
}
|
||||
|
||||
/** Delete a span of text from this cell.
|
||||
*/
|
||||
public abstract void delete(ZZCell c, int start);
|
||||
|
||||
/** Delete a span of text from this cell.
|
||||
*/
|
||||
public abstract void delete(ZZCell c, int start, int end);
|
||||
|
||||
/** Split a cell into two along a dimension.
|
||||
* 0..offs-1 goes into first, offs..end goes to next.
|
||||
* All connections remain in the first cell.
|
||||
*/
|
||||
public void split(ZZCell c, int offs, String dim) {
|
||||
ZZCell n = c.N(dim);
|
||||
if(isRef(c)) {
|
||||
Span[] sps = getSpans(c, offs);
|
||||
setSpans(n, sps);
|
||||
delete(c, offs);
|
||||
} else {
|
||||
String s = getText(c);
|
||||
setText(c, s.substring(0, offs));
|
||||
setText(n, s.substring(offs));
|
||||
}
|
||||
}
|
||||
|
||||
/** Insert a string of typed-in text referentially.
|
||||
* A Span in the current cell's space is automatically constructed, etc.
|
||||
* This is at this level because we *may* want to fudge things later if
|
||||
* the user corrects typing errors before saving. However, that's a
|
||||
* bit tricky
|
||||
* so we won't try it yet.
|
||||
* <p>
|
||||
* Calling this function on a cell that only has text content
|
||||
* makes the whole
|
||||
* current text content referential as well.
|
||||
*/
|
||||
public abstract void insertNewRef(ZZCell c, String txt, int offs);
|
||||
|
||||
/** Insert a referential span of text.
|
||||
* <p>
|
||||
* Calling this function on a cell that only has text content
|
||||
* makes the whole
|
||||
* current text content referential as well.
|
||||
*/
|
||||
public abstract void insertRef(ZZCell c, Span sp, int offs);
|
||||
|
||||
/** Obtain the referential contents of this cell.
|
||||
* @return List of spans, or null if not referential.
|
||||
*/
|
||||
public abstract Span[] getSpans(ZZCell c);
|
||||
public abstract Span[] getSpans(ZZCell c, int start);
|
||||
public abstract Span[] getSpans(ZZCell c, int start, int end);
|
||||
|
||||
/** Set the spans of the cell to the given spans.
|
||||
*/
|
||||
public abstract void setSpans(ZZCell c, Span[] spans);
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user