created mirror
This commit is contained in:
479
Modules/nile/Nile1Ops.java
Normal file
479
Modules/nile/Nile1Ops.java
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
Nile1Ops.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.module;
|
||||
import org.gzigzag.*;
|
||||
import java.util.*;
|
||||
|
||||
/** A library of routines for operating on Nile1 streams.
|
||||
* @see Nile1
|
||||
* @deprecated Use Nile2Ops.
|
||||
*/
|
||||
|
||||
public abstract class Nile1Ops {
|
||||
public static final String rcsid = "$Id: Nile1Ops.java,v 1.16 2000/12/07 00:37:19 tjl Exp $";
|
||||
public static boolean dbg = true;
|
||||
static void p(String s) { if(dbg) System.out.println(s); }
|
||||
static void pa(String s) { System.out.println(s); }
|
||||
|
||||
/** Split the given cell into two at the offset offset.
|
||||
* The original cell will remain the first.
|
||||
* Returns the cell that is after the split.
|
||||
* If offset is zero or greater than or equal to the number of characters
|
||||
* in c, nothing is done and either the current cell or the next cell is
|
||||
* returned.
|
||||
* <p>
|
||||
* The most special case involves doing this at the very end of the stream,
|
||||
* in which case an empty new cell is created and returned.
|
||||
* @param c The cursor to split at
|
||||
* @param always Whether to split even if the offset is at the beginning
|
||||
* or end of a cell. Used e.g. for inserting a paragraph.
|
||||
* @return Never null.
|
||||
*/
|
||||
static public ZZCell split(ZZCursor c, boolean always) {
|
||||
// XXX Adjust cursors!!!
|
||||
ZZCell c0 = c.get();
|
||||
int offs = c.getOffs();
|
||||
if(always) {
|
||||
ZZCell c1 = c0.N("d.nile");
|
||||
String s = c0.getText();
|
||||
c0.setText(s.substring(0, offs));
|
||||
c1.setText(s.substring(offs));
|
||||
return c1;
|
||||
} else {
|
||||
if(offs == 0) return c0;
|
||||
if(offs == c0.getText().length())
|
||||
return c0.getOrNewCell("d.nile");
|
||||
return split(c, true);
|
||||
}
|
||||
}
|
||||
|
||||
/** Break a paragraph at the given position.
|
||||
* Returns the first cell of the (possibly empty) new paragraph.
|
||||
*/
|
||||
static public ZZCell breakParagraph(ZZCursor c) {
|
||||
ZZCell n = split(c, true);
|
||||
if(n.s("d.nile-struct") != null)
|
||||
throw new ZZError("split structure already!");
|
||||
ZZCell str = n.N("d.nile-struct");
|
||||
setStrLevel(str, 0);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Change the structural level of a paragraph.
|
||||
* @param c Any cell in the paragraph - does not need to be the first.
|
||||
* @param level The new level.
|
||||
*/
|
||||
static public void setLevel(ZZCell c, int level) {
|
||||
ZZCell para = findStruct(c, -1, true);
|
||||
ZZCell str = para.s("d.nile-struct");
|
||||
if(str == null) return;
|
||||
setStrLevel(str, level);
|
||||
}
|
||||
|
||||
/** Get the level of a paragraph.
|
||||
* @param c Any cell in the paragraph - does not need to be the first.
|
||||
*/
|
||||
static public int getLevel(ZZCell c) {
|
||||
ZZCell para = findStruct(c, -1, true);
|
||||
ZZCell str = para.s("d.nile-struct");
|
||||
if(str == null) return 6;
|
||||
return getStrLevel(str);
|
||||
}
|
||||
|
||||
/** Insert the given string into the stream at cursor.
|
||||
*/
|
||||
static public void insert(ZZCursor c, String txt) {
|
||||
throw new ZZError("Not implemented");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** The level of structure the given structure cell is.
|
||||
* Note that the levels are a bit interesting: it returns
|
||||
* zero for paragraphs, 1 for H6, 2 for H5 and so on.
|
||||
* -1 is returned for cells that are not at a structural border.
|
||||
*/
|
||||
static int getStrLevel(ZZCell str) {
|
||||
String txt = str.getText();
|
||||
if(txt.equals("MP")) // Middle of paragraph - special level.
|
||||
return -1;
|
||||
if(txt.equals("P"))
|
||||
return 0;
|
||||
if(txt.equals("H1"))
|
||||
return 6;
|
||||
if(txt.equals("H2"))
|
||||
return 5;
|
||||
if(txt.equals("H3"))
|
||||
return 4;
|
||||
if(txt.equals("H4"))
|
||||
return 3;
|
||||
if(txt.equals("H5"))
|
||||
return 2;
|
||||
if(txt.equals("H6"))
|
||||
return 1;
|
||||
throw new ZZError("Invalid nile-struct "+txt);
|
||||
}
|
||||
|
||||
static String[] levels = new String[] {
|
||||
"P", "H6", "H5", "H4", "H3", "H2", "H1"
|
||||
};
|
||||
|
||||
/** Set the level of a structural cell.
|
||||
*/
|
||||
static void setStrLevel(ZZCell str, int level) {
|
||||
if(level < 0 || level > levels.length)
|
||||
throw new ZZError("Request to set invalid level! "+level);
|
||||
str.setText(levels[level]);
|
||||
}
|
||||
|
||||
/** Find an angle in the rank, i.e.the next cell on a rank with
|
||||
* a connection into a certain direction.
|
||||
*/
|
||||
static ZZCell findAngle(ZZCell c, String dim, int dir,
|
||||
String adim, int adir, boolean includeThis) {
|
||||
LoopDetector ld = new LoopDetector();
|
||||
if(includeThis && c.s(adim, adir) != null) return c;
|
||||
c = c.s(dim, dir);
|
||||
while(c != null) {
|
||||
if(c.s(adim, adir) != null) return c;
|
||||
ld.detect(c);
|
||||
c = c.s(dim, dir);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Find the next or previous cell that is a structural level element.
|
||||
*/
|
||||
static ZZCell findStruct(ZZCell c, int dir, boolean includeThis) {
|
||||
ZZCell ret = findAngle(c, "d.nile", dir, "d.nile-struct", 1, includeThis);
|
||||
if(ret == null && dir == -1) {
|
||||
if(!includeThis && c.s("d.nile", -1) == null)
|
||||
return null;
|
||||
return c.h("d.nile", -1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** An editing mode, i.e.the definition of what are the breaks
|
||||
* that are being operated on in this mode.
|
||||
*/
|
||||
public interface Mode {
|
||||
/** Set the mode cursor, and possibly selection cursor, to the
|
||||
* given cursor.
|
||||
* This is called in response to e.g. mouse click, so the position
|
||||
* may be adjusted to the beginning of the previous unit.
|
||||
*/
|
||||
void setCursor(ZZCell view, ZZCursor c);
|
||||
|
||||
/** Move the cursor nsteps units.
|
||||
*/
|
||||
void moveCursor(ZZCell view, int nsteps);
|
||||
|
||||
/** Extend/shrink the selection by n units in given direction.
|
||||
*/
|
||||
void adjust(ZZCell view, int end, int nsteps);
|
||||
|
||||
/** Hop the selection.
|
||||
*/
|
||||
void hop(ZZCell view, int nsteps);
|
||||
|
||||
/** Delete the current selection, move cursor backwards or forwerds.
|
||||
*/
|
||||
// void delete(ZZCell view, int movedir);
|
||||
}
|
||||
|
||||
public static class EdgeMode implements Mode {
|
||||
Nile1Text.Edger edger;
|
||||
EdgeMode(Nile1Text.Edger edger) { this.edger = edger; }
|
||||
|
||||
public void setCursor(ZZCell view, ZZCursor c) {
|
||||
Stream.Iterator iter = giter(c);
|
||||
edger.edge(iter, true, -1, Nile1Text.START);
|
||||
curs(view).set(iter.get());
|
||||
edger.edge(iter, false, 1, Nile1Text.END);
|
||||
endcurs(view).set(iter.get());
|
||||
}
|
||||
// Move from end of area if forwards, from start if backwards.
|
||||
public void moveCursor(ZZCell view, int nsteps) {
|
||||
if(nsteps <= 0) {
|
||||
Stream.Iterator iter = giter(curs(view));
|
||||
if(!edger.edge(iter, false, nsteps, Nile1Text.START))
|
||||
return;
|
||||
curs(view).set(iter.get());
|
||||
edger.edge(iter, false, 1, Nile1Text.END);
|
||||
endcurs(view).set(iter.get());
|
||||
} else {
|
||||
Stream.Iterator iter = giter(endcurs(view));
|
||||
if(!edger.edge(iter, false, nsteps, Nile1Text.END))
|
||||
return;
|
||||
endcurs(view).set(iter.get());
|
||||
edger.edge(iter, false, -1, Nile1Text.START);
|
||||
curs(view).set(iter.get());
|
||||
}
|
||||
}
|
||||
public void adjust(ZZCell view, int end, int nsteps) {
|
||||
ZZCursor c1 = curs(view);
|
||||
ZZCursor c2 = endcurs(view);
|
||||
if(end < 0) {
|
||||
Stream.Iterator iter = Stream.getIterator(c1, "d.nile");
|
||||
if(!edger.edge(iter, false, nsteps, Nile1Text.START))
|
||||
return;
|
||||
ZZCursor curs = iter.get();
|
||||
if(!isOrdered(curs, c2)) return;
|
||||
c1.set(curs);
|
||||
} else {
|
||||
Stream.Iterator iter = Stream.getIterator(c2, "d.nile");
|
||||
if(!edger.edge(iter, false, nsteps, Nile1Text.END))
|
||||
return;
|
||||
ZZCursor curs = iter.get();
|
||||
if(!isOrdered(c1, curs)) return;
|
||||
c2.set(curs);
|
||||
}
|
||||
// XXX Check that they do not cross...
|
||||
}
|
||||
public void hop(ZZCell view, int nsteps) {
|
||||
p("Cut out the selection for hop");
|
||||
ZZCell selec = cutSelection(view);
|
||||
if(selec == null) return;
|
||||
|
||||
ZZCursor c1 = curs(view);
|
||||
|
||||
p("Now, find place to paste at hopped location");
|
||||
Stream.Iterator iter = Stream.getIterator(c1, "d.nile");
|
||||
edger.edge(iter, false, nsteps, Nile1Text.START);
|
||||
c1.set(iter.get());
|
||||
p("And paste");
|
||||
paste(view, selec, true);
|
||||
|
||||
}
|
||||
}
|
||||
static Mode wordmode = new EdgeMode(new Nile1Text.WordEdger());
|
||||
static Mode sentencemode = new EdgeMode(new Nile1Text.SentenceEdger());
|
||||
|
||||
static public Mode getMode(ZZCell view) {
|
||||
// return wordmode;
|
||||
return sentencemode;
|
||||
}
|
||||
|
||||
// XXX
|
||||
static ZZCell adjStart(ZZCell c, int adj) {
|
||||
if(adj > 0) {
|
||||
// XXX Easily screws up font change!
|
||||
ZZCursor c1 = new ZZCursorVirtual(c, 0);
|
||||
if(!Stream.move(c1, "d.nile", adj))
|
||||
throw new ZZError("ARRRRGH!");
|
||||
if(c1.get().equals(c)) {
|
||||
c.setText(c.getText().substring(adj));
|
||||
} else {
|
||||
c = split(c1, false);
|
||||
c.disconnect("d.nile", -1);
|
||||
}
|
||||
} else if(adj < 0) {
|
||||
// XXX Spans
|
||||
String s = "";
|
||||
while(adj++ < 0) s = s + " "; // XXX
|
||||
ZZCell n = c.N("d.nile", -1);
|
||||
n.setText(s);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static ZZCell adjEnd(ZZCell c, int adj) {
|
||||
if(adj > 0) {
|
||||
ZZCursor c1 = new ZZCursorVirtual(c, c.getText().length());
|
||||
if(!Stream.move(c1, "d.nile", -adj))
|
||||
throw new ZZError("ARRRRGH!");
|
||||
// XXX
|
||||
|
||||
c = c1.get();
|
||||
c.setText(c.getText().substring(0, c1.getOffs()));
|
||||
c.disconnect("d.nile", 1);
|
||||
} else if(adj < 0) {
|
||||
c.setText(c.getText()+" ");
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static void adjustSelection(Stream.Iterator start, Stream.Iterator end) {
|
||||
Nile1Text.wordEdge(start, true, 1, Nile1Text.START);
|
||||
Nile1Text.wordEdge(end, true, -1, Nile1Text.END);
|
||||
}
|
||||
|
||||
static ZZCell cutSelection(ZZCell view) {
|
||||
ZZCursor curs1 = curs(view);
|
||||
|
||||
p("Cut");
|
||||
dump(curs1.get());
|
||||
|
||||
ZZCursor curs2 = endcurs(view);
|
||||
if(!isOrdered(curs1, curs2)) return null;
|
||||
Stream.Iterator iter1 = Stream.getIterator(curs1, "d.nile");
|
||||
Stream.Iterator iter2 = Stream.getIterator(curs2, "d.nile");
|
||||
int[] adj = new int[2];
|
||||
Nile1Text.adjustCut(iter1, iter2, adj);
|
||||
ZZCursor c1 = iter1.get();
|
||||
ZZCursor c2 = iter2.get();
|
||||
|
||||
ZZCell after = split(c2, false);
|
||||
p("\nAFTER SPLIT:");
|
||||
dump(after);
|
||||
|
||||
ZZCell first = split(c1, false);
|
||||
p("\nFIRST SPLIT:");
|
||||
dump(first);
|
||||
|
||||
|
||||
ZZCell prev = first.s("d.nile", -1);
|
||||
ZZCell last = after.s("d.nile", -1);
|
||||
after.disconnect("d.nile", -1);
|
||||
first.disconnect("d.nile", -1);
|
||||
|
||||
if(prev != null) prev.connect("d.nile", after);
|
||||
|
||||
p("AFTER RECONNECT");
|
||||
dump(prev);
|
||||
|
||||
curs(view).set(after);
|
||||
curs(view).setOffs(0);
|
||||
|
||||
// Now, if more characters need to be left out, do it.
|
||||
first = adjStart(first, adj[0]);
|
||||
last = adjEnd(last, adj[1]);
|
||||
if(adj[1] != 0) throw new ZZError("End adj not implemented");
|
||||
|
||||
p("AFTER CUTADJ");
|
||||
dump(first);
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
/** Paste the given stream into the given cursor.
|
||||
* The range and the text are adjusted for word-by-word
|
||||
* insertion.
|
||||
* @param view The viewcell that gives the location to
|
||||
* paste into. Used later to set the new range,
|
||||
* if desired.
|
||||
* @param what The first cell of the stream to paste in.
|
||||
* @param setRange Whether to set the selection of the given
|
||||
* view to the pasted range afterwards.
|
||||
*/
|
||||
static void paste(ZZCell view, ZZCell what, boolean setRange) {
|
||||
|
||||
ZZCursor v = curs(view);
|
||||
|
||||
p("PASTE");
|
||||
dump(v.get());
|
||||
p("PASTING WHAT");
|
||||
dump(what);
|
||||
|
||||
int[] adj = new int[2];
|
||||
Stream.Iterator to = Stream.getIterator(v, "d.nile");
|
||||
Stream.Iterator start = giter(new ZZCursorVirtual(what, 0));
|
||||
ZZCell last = what.h("d.nile", 1);
|
||||
Stream.Iterator end = giter(new ZZCursorVirtual(last,
|
||||
last.getText().length()));
|
||||
|
||||
Nile1Text.adjustPaste(to, start, end, adj);
|
||||
|
||||
what = adjStart(start.get().get(), adj[0]);
|
||||
adjEnd(end.get().get(), adj[1]);
|
||||
|
||||
p("WHAT ADJUSTED");
|
||||
dump(what);
|
||||
|
||||
ZZCell after = split(v, false);
|
||||
ZZCell before = after.s("d.nile", -1);
|
||||
after.disconnect("d.nile", -1);
|
||||
after.connect("d.nile", -1, what.h("d.nile", 1));
|
||||
if(before != null)
|
||||
before.connect("d.nile", 1, what);
|
||||
|
||||
if(setRange) {
|
||||
v.set(what);
|
||||
v.setOffs(0);
|
||||
|
||||
start = giter(v);
|
||||
|
||||
ZZCursor ev = endcurs(view);
|
||||
ev.set(after);
|
||||
ev.setOffs(0);
|
||||
|
||||
end = giter(ev);
|
||||
|
||||
adjustSelection(start, end);
|
||||
|
||||
v.set(start.get());
|
||||
ev.set(end.get());
|
||||
}
|
||||
|
||||
p("AFTER EVERYTHING");
|
||||
dump(what);
|
||||
}
|
||||
|
||||
// XXX Should use the tree for help...
|
||||
static public boolean isOrdered(ZZCursor cu1, ZZCursor cu2) {
|
||||
ZZCell c1 = cu1.get();
|
||||
ZZCell c2 = cu2.get();
|
||||
if(c1 == null || c2 == null) return false;
|
||||
if(c1.equals(c2))
|
||||
return cu1.getOffs() <= cu2.getOffs();
|
||||
for(; c1 != null && !c1.equals(c2); c1 = c1.s("d.nile"));
|
||||
if(c1 == null) return false;
|
||||
return (c1.equals(c2));
|
||||
}
|
||||
|
||||
// Shorthand...
|
||||
static public ZZCursorReal curs(ZZCell view) {
|
||||
return new ZZCursorReal(view);
|
||||
}
|
||||
static public Stream.Iterator giter(ZZCursor c) {
|
||||
return Stream.getIterator(c, "d.nile");
|
||||
}
|
||||
|
||||
static public ZZCursorReal endcurs(ZZCell view) {
|
||||
ZZCell end = view.getOrNewCell("d.nile-sel");
|
||||
return new ZZCursorReal(end);
|
||||
}
|
||||
|
||||
static public void dump(ZZCell start) {
|
||||
if(start == null) {
|
||||
pa("Nile stream Null start!");
|
||||
return;
|
||||
}
|
||||
ZZCell init = start.h("d.nile", -1);
|
||||
pa("Nile stream! "+start);
|
||||
boolean first = true;
|
||||
for(ZZCell c = init; c != null; c=c.s("d.nile")) {
|
||||
pa((c.s("d.nile-struct") != null ? "***S*** " : " ") +
|
||||
" Cell "+c+" "+
|
||||
(c.equals(start) ? " <----------------START" : ""));
|
||||
if(!first && c.equals(init)) {
|
||||
pa(" WAS A LOOOOOOOP!!!!!!!!!!");
|
||||
throw new ZZFatalError("LOOPING NILE STREAM! BAD BAD TROUBLE!");
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user