5. text editorsssw.jku.at/misc/ssw/05.texteditors.pdf5. text editors 5.1 data structures for texts...

44
1 5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the screen (case study) 5.2.1 Line descriptors 5.2.2 Positions 5.2.3 Input handling 5.2.4 Updating the view 5.2.5 Scrolling

Upload: others

Post on 17-Oct-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

1

5. Text Editors5.1 Data structures for texts

5.1.1 SimpleText5.1.2 GapText5.1.3 PieceListText

5.2 Text representation on the screen (case study)5.2.1 Line descriptors5.2.2 Positions5.2.3 Input handling5.2.4 Updating the view5.2.5 Scrolling

Page 2: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

2

Interface of a text type

interface Text {void loadFrom (InputStream s);void storeTo (OutputStream s);

char charAt (int pos);

void insert (int pos, char ch);void delete (int from, int to);

int indexOf (String pattern);}

These are the operations we are interested in

Alternative for insert() and delete()

...void replace (int from, int to, String s);...

replace(3, 3, "x"); ⇔ insert(3, x);replace(3, 5, ""); ⇔ delete(3, 5);replace(3, 5, "x");

Page 3: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

3

5. Text Editors5.1 Data structures for texts

5.1.1 SimpleText5.1.2 GapText5.1.3 PieceListText

5.2 Text representation on the screen (case study)5.2.1 Line descriptors5.2.2 Positions5.2.3 Input handling5.2.4 Updating the view5.2.5 Scrolling

Page 4: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

4

SimpleText• Text is a character array• When text is inserted or deleted some other text has to be moved

class SimpleText {private char[] buf = new char[64];int len = 0;

void insert (int pos, char ch) {if (pos < 0) pos = 0;if (pos > len) pos = len;if (len == buf.length) {

char[] newBuf = new char[2 * buf.length];System.arraycopy(buf, 0, newBuf, 0, len);buf = newBuf;

}System.arraycopy(buf, pos, buf, pos+1, len-pos);buf[pos] = ch;len++;

}

...void delete (int from, int to) {

if (from < 0) from = 0;if (to > len) to = len;if (from >= to) return;System.arraycopy(buf, to, buf, from, len-to);len = len - (to - from);if (len < buf.length/2 && buf.length > 64) {

char[] newBuf = new char[buf.length/2];System.arraycopy(buf, 0, newBuf, 0, len);buf = newBuf;

}}...

}

Only practical for very short texts (< 256 characters)

insert(ch) delete(from, to)

Page 5: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

5

5. Text Editors5.1 Data structures for texts

5.1.1 SimpleText5.1.2 GapText5.1.3 PieceListText

5.2 Text representation on the screen (case study)5.2.1 Line descriptors5.2.2 Positions5.2.3 Input handling5.2.4 Updating the view5.2.5 Scrolling

Page 6: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

6

GapTextObservation

The text buffer consists of a filled part and an empty part ("gap")

filled emptygap

Inserting and deleting at the gap position is efficient (nothing must be moved)

insert(ch)

delete(from, to)

Inserting and deleting in the middle of the text requires the remaining text to be moved

IdeaMove the gap to the insert/delete position!

Page 7: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

7

Inserting characters

pos

Gap is moved to the insert position

pos

Now inserting at pos is efficient!

class GapText {char[] buf = new char[4096];int len = 0;int gapPos = 0;

void insert (int pos, char ch) {if (pos != gapPos) moveGapTo(pos);// pos == gapPosbuf[pos] = ch; len++; gapPos++;

}...

}

can be done withSystem.arraycopy(...)

gap size: buf.length - len

Typically, several characters are inserted/deleted at the same position, before this position is changed

Page 8: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

8

Deleting text pieces

from toGap is moved to to

from toNow we just have to enlarge the gap (nothing must be moved).Typically, this happens if the delete key is pressed several times.

class GapText {...void delete (int from, int to) {

if (gapPos != to) moveGapTo(to);// gapPos == togapPos = from;len = len - (to - from);

}...

}

from to

gapPos +buf.length - len buf.lengthgapPos

Page 9: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

9

GapText – pros and contrasAdvantages

• Efficient insert and delete• Simple to implement

Disadvantage

• The whole text must be in memory (may be a problem with very large texts)• Text length is restricted by the array size.

Array can be dynamically enlarged, but the text must be copied to the new array.

GapText is for example used in JFace of Eclipse

Page 10: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

10

5. Text Editors5.1 Data structures for texts

5.1.1 SimpleText5.1.2 GapText5.1.3 PieceListText

5.2 Text representation on the screen (case study)5.2.1 Line descriptors5.2.2 Positions5.2.3 Input handling5.2.4 Updating the view5.2.5 Scrolling

Page 11: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

11

PieceListTextIdea

The text consists of pieces that are stored in a file

descriptors

text pieces

in memory

on file

The text pieces in a file need not be stored in consecutive order.They can even be stored in different files.

file 1

file 2

The descriptors specify the text pieces and their order

class Piece { // descriptorint len; // length of this pieceFile file; // file containing this pieceint filePos; // offset from beginning of filePiece next;

}

Page 12: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

12

Inserting characters

p1

d1

pos

A text piece p2 is to be inserted at position pos

p1 is split at position pos

p11

d11

pos

d12

p12

p2 is inserted at position pos

p11

d11

pos

d12

p12

d2

p2

• Nothing must be moved on the file!• p2 can be stored in a different file

(typicaly, text that is typed in is storedin a scratch file)

• When the text is saved to diskits pieces are copied in the right order

p11 p2 p12

Page 13: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

13

Implementation of the insert operation

class PieceListText {int len; // total text lengthPiece firstPiece; // first piece of the textFile scratch; // scratch file

void insert (int pos, int ch) {Piece p = split(pos); // split piece at posif (p is not last piece on scratch file) {

Piece q = new Piece(0, scratch, scratch.length());q.next = p.next; p.next = q;p = q;

}// p is last piece on scratch filescratch.write(ch);p.len++; len++;

}...

}

pos

There must always be a p, therefore there is an empty dummy piece atthe beginning of the text

scratch file

p

ch

Further insert(pos, ch) at the sameposition do not create a new scratchpiece, but append ch to the already existing scratch piece

scratch file

p qp

Page 14: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

14

splitPiece split (int pos) {

if (pos == 0) return firstPiece;//--- set p to piece containing posPiece p = firstPiece;int len = p.len;while (pos > len) {

p = p.next;len = len + p.len;

}//--- split piece pif (pos != len) {

int len2 = len - pos;int len1 = p.len - len2;p.len = len1;Piece q = new Piece(len2, p.file, p.filePos + len1);q.next = p.next;p.next = q;

}return p;

}

5 10 3

pos = 9

firstPiecep

len = 15

5 4 3

pos = 9

firstPiecep q

6len1 len2

Page 15: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

15

Deleting text

d1 d2 d3

from to

p1 p2 p3

The text between from and to is to be deleted

void delete (int from, int to) {Piece a = split(from);Piece b = split(to);a.next = b.next;

}

d11 d2 d31

from to

p11 p2 p31

Split

p12 p32

d12 d32a b

d11 d2 d31

from to

p11 p2 p31

Unlink descriptors between from and to

p12 p32

d12 d32

Page 16: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

16

Larger exampleOpen a file with the text "abcde"

a b c d e

5

Insert "fgh" at position 3

a b c d e

3 23

f g h scratch file

3text = "abcfghde"

Delete text from 2 to 9

a b c d e

1 12

f g h

2 1

i j

2 9

2 1

text = "abe"a b c d e

2 1

Save the text and reopen it

a b e

3

Insert "ij" at position 5

a b c d e

3 22

f g h

2 1

i j5

text = "abcfgijhde"

scratch file

Page 17: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

17

Fonts and stylesAre stored in the piece descriptors

class Piece {...Font font;Style style;

}

Times12plain

a b

setFont(a, b, "Arial", 10);

Times12plain

Arial10plain

Times12plain

c d

setStyle(c, d, italic);

Times12plain

Arial10plain

Times12italic

Arial10italic

Times12plain

Page 18: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

18

Storing fonts and styles in a filePossible file format

File = textOffset {Piece} Text.Piece = length font style.

3 Times p 2 Arial i 2 Times p a b c d e f g

Font-Info ASCII-Text

After opening the file

a b c d e f g

Timesplain

Arialitalic

Timesplain

Pure text tools (compiler, grep, ...)can ignore the font information

Page 19: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

19

Images and other objectsAre stored in a special piece of length 1

class ImagePiece extends Piece {Image img;

}

6 1 9

img

• An image is treated like a single character (the text contains a special character (e.g. ESC) at the position of the image)

• The image "floats" in the text while it is edited• When the text is saved the image is stored (serialized) together with the fonts and styles• In addition to images, any other objects can float in the text (buttons, page breaks, ...)

Page 20: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

20

Pros and contras of PieceListTextAdvantages

• Only the descriptors are kept in memory; the text is always stored on file=> allows arbitrarily large texts, because they do not have to be kept in memory

• The text in the file is never modified.Nothing must be moved.

• Opening a text in the editor is fast, because the text does not have to be readinto memory

• Fonts and styles can be handled easily• Objects (images, ...) can float in the text

Disadvantage

• For displaying the text in a window it must be read from the file.But this is efficient due to buffering.Only the text which is displayed in the window has to be read.

Page 21: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

21

5. Text Editors5.1 Data structures for texts

5.1.1 SimpleText5.1.2 GapText5.1.3 PieceListText

5.2 Text representation on the screen (case study)5.2.1 Line descriptors5.2.2 Positions5.2.3 Input handling5.2.4 Updating the view5.2.5 Scrolling

Page 22: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

22

Line descriptors

class Viewer extends Canvas {Text text;Line firstLine;int firstTpos;int lastTpos;...

}

abc defg h cr lf

ij klmn cr lf

opq rst uvwx yz cr lf

TOP

BOTTOM

LEFT

getHeight()

firstLine firstTpos

lastTpos

Text window

Line descriptor

class Line {String text;int len; int x, y, w, h;int base;Line prev, next;

}

i j k l m n(x, y)

h

w

basetext = "ij klmn\r\n"len = 9 (incl. \r, \n)

• Descriptors are only kept for visible lines• The text positions of lines are not stored so that they do not

have be updated during editing

getWidth()

(0,0)

Page 23: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

23

Font metrics

p ascent

descent

width

height

lead

Graphics g = viewer.getGraphics();FontMetrics m = g.getFontMetrics();// m = new FontMetrics(font);

int ascent = m.getAscent();int descent = m.getDescent();int height = m.getHeight();int lead = m.getLead();int width = m.charWidth(ch);int swidth = m.stringWidth(string);

Page 24: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

24

Filling the line descriptorsprivate Line fill (int top, int bottom, int pos) {

Line first = null, line = null;lastTpos = pos;char ch = text.charAt(pos);int y = top;while (y < bottom) {

if (first == null) { line = new Line(); first = line; }else {

Line prev = line;line.next = new Line(); line = line.next; line.prev = prev;

}StringBuffer buf = new StringBuffer();while (ch != '\n' && ch != EOF) {

buf.append(ch); pos++; ch = text.charAt(pos);}boolean eol = ch == '\n';if (eol) { buf.append(ch); pos++; ch = text.charAt(pos); }line.len = buf.length();line.text = buf.toString();line.x = LEFT;line.y = y;line.w = m.stringWidth(line.text);line.h = m.getHeight();line.base = y + m.getAscent();y += line.h;lastTpos += line.len;if (!eol) break;

}return first;

}

top

bottom

(x, y)

base h

w

...text

Viewer

pos

LEFT

Page 25: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

25

Drawing the lines

class Viewer extends Canvas {...public void paint (Graphics g) {

if (firstLine == null) {firstLine = fill(TOP, getHeight() - BOTTOM, 0);caret = Pos(0);

}for (Line line = firstLine; line != null, line = line.next) {

g.drawString(line.text, line.x, line.base);}if (caret != null) invertCaret();if (sel != null) invertSelection(sel.beg, sel.end);

}}

paint() is automatically called by Java, if the window is to be redrawn

Page 26: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

26

5. Text Editors5.1 Data structures for texts

5.1.1 SimpleText5.1.2 GapText5.1.3 PieceListText

5.2 Text representation on the screen (case study)5.2.1 Line descriptors5.2.2 Positions5.2.3 Input handling5.2.4 Updating the view5.2.5 Scrolling

Page 27: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

27

Positions

class Position {Line line; // line containing this positionint x, y; // base line point corresponding to this positionint tpos; // text position (offset relative to start of text)int org; // origin (text position of first character in this line)int off; // text offset from org

}

a b c d e f g h i j koff

(e.g. 7)

(x, y)

org(e.g. 100)

tpos(e.g. 107)

Information about the position of a character on the screen

Page 28: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

28

Finding a positionprivate Position Pos (int x, int y) {

Position pos = new Position();if (y >= getHeight()-BOTTOM) y = getHeight()-BOTTOM-1;Line line = firstLine, last = null;pos.org = firstTpos;while (line != null && y >= line.y + line.h) {

pos.org += line.len; last = line; line = line.next;}if (line == null) { line = last; pos.org -= last.len; }pos.line = line;pos.y = line.base;if (x >= line.x + line.w) {

pos.x = line.x + line.w;pos.off = line.len;if (pos.org + line.len < text.length()) pos.off -= 2; // CR, LF

} else {pos.x = line.x;int i = pos.org;char ch = text.charAt(i);int w = m.charWidth(ch);while (x >= pos.x + w) {

pos.x += w;i++; ch = text.charAt(i);w = m.charWidth(ch);

}pos.off = i - pos.org;

}pos.tpos = pos.org + pos.off;return pos;

}

a b c d y

x

a b c dpos.off

(pos.x, pos.y)

pos.tpospos.org

pos.line

line.y

line.h

line.w

line.y

line.h

line.w

private Position Pos (int tpos) { ...}

Page 29: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

29

CaretPosition caret = null;

private void setCaret (Position pos) {removeCaret(); removeSelection();caret = pos;invertCaret();

}

a b c d

public void setCaret (int x, int y) {setCaret (Pos(x, y));

}

public void setCaret (int tpos) {if (tpos >= firstTpos && tpos <= lastTpos) {

setCaret (Pos(tpos));} else removeCaret();

}

public void removeCaret () {if (caret != null) invertCaret();caret = null;

}

private void invertCaret () {g.setXORMode(Color.WHITE);int x = caret.x, y = caret.y;g.drawLine(x, y, x + 0, y); y++;g.drawLine(x, y, x + 1, y); y++;g.drawLine(x, y, x + 2, y); y++;g.drawLine(x, y, x + 3, y);g.setPaintMode();

}

(x,y)

Page 30: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

30

Selectionclass Selection {

Position beg, end;Selection (Position a, Position b) {

beg = a; end = b;}

}

a b cj k l m no p q r s t u

d e f g h i

v w x

beg

end

private void invertSelection (Position beg, Position end) {g.setXORMode(Color.WHITE);Line line = beg.line;int x = beg.x;int y = line.y;int w;int h = line.h;while (line != end.line) {

w = LEFT + line.w - x;g.fillRect(x, y, w, h);line = line.next;x = line.x; y = line.y;

}w = end.x - x;g.fillRect(x, y, w, h);g.setPaintMode();

}

public void setSelection (int from, int to) {if (from < to) {

removeCaret(); removeSelection();Position beg = Pos(from);Position end = Pos(to);sel = new Selection(beg, end);invertSelection(beg, end);

} else removeSelection();}

public void removeSelection () {if (sel != null)

invertSelection(sel.beg, sel.end);sel = null;

}

Page 31: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

31

5. Text Editors5.1 Data structures for texts

5.1.1 SimpleText5.1.2 GapText5.1.3 PieceListText

5.2 Text representation on the screen (case study)5.2.1 Line descriptors5.2.2 Positions5.2.3 Input handling5.2.4 Updating the view5.2.5 Scrolling

Page 32: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

32

Mouse inputRegister a listener for mouse events at the viewer

class Viewer extends Canvas {...public Viewer (...) {

...this.addMouseListener(new MouseAdapter() {

public void mousePressed (MouseEvent e) { doMousePressed(e); }public void mouseReleased (MouseEvent e) { doMouseReleased(e); }

});this.addMouseMotionListener(new MouseMotionAdapter() {

public void mouseDragged (MouseEvent e) { doMouseDragged(e); }});

}...

}

mouse was pressed

mouse was released

mouse was movedwhile it was pressed

class MouseEvent extends InputEvent {int getX() {...}int getY() {...}...

}

(x, y) is relative to the viewer

Page 33: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

33

Handling mouse eventsprivate void doMousePressed (MouseEvent e) {

removeCaret(); removeSelection();Position pos = Pos(e.getX(), e.getY());sel = new Selection(pos, pos);lastPos = pos;

}

private void doMouseDragged (MouseEvent e) {... // adjust sel.beg and sel.end

}

private void doMouseReleased (MouseEvent e) {if (sel.beg.tpos == sel.end.tpos) setCaret(sel.beg);lastPos = null;

}

Page 34: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

34

Mouse draggingprivate void doMouseDragged (MouseEvent e) {

Position pos = Pos(e.getX(), e.getY());if (pos.tpos < sel.beg.tpos) {

if (lastPos.tpos == sel.end.tpos) {invertSelection(sel.beg, lastPos);sel.end = sel.beg;

}invertSelection(pos, sel.beg);sel.beg = pos;

} else if (pos.tpos > sel.end.tpos) {if (lastPos.tpos == sel.beg.tpos) {

invertSelection(lastPos, sel.end);sel.beg = sel.end;

}invertSelection(sel.end, pos);sel.end = pos;

} else if (pos.tpos < lastPos.tpos) { // beg <= pos <= end; clear pos..endinvertSelection(pos, sel.end);sel.end = pos;

} else if (lastPos.tpos < pos.tpos) { // beg <= pos <= end; clear beg..posinvertSelection(sel.beg, pos);sel.beg = pos;

}lastPos = pos;

}

a b c d e f gh i j k l m nbeg end

lastPos

pos

a b c d e f gh i j k l m nend

beg

a b c d e f gh i j k l m npos

endlastPos

beg

a b c d e f gh i j k l m nend

beg

a b c d e f g

lastPosendbeg pos

a b c d e f gbeg end

a b c d e f gend

lastPosbeg pos

a b c d e f gendbeg

Page 35: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

35

Keyboard input

class Viewer extends Canvas {...public Viewer (...) {

...this.addKeyListener(new KeyAdapter() {

public void keyTyped (KeyEvent e) { doKeyTyped(e); }});...

}...

}

class KeyEvent extends InputEvent {char getKeyChar() {...}...

}

Register a listener for keyboard events at the viewer

Page 36: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

36

Reacting to keyboard events

private void doKeyTyped (KeyEvent e) {boolean selection = sel != null;if (selection) {

text.delete(sel.beg.tpos, sel.end.tpos);// selection is removed// caret is set at sel.beg.pos

}if (caret != null) {

char ch = e.getKeyChar();

if (ch == BACKSPACE) {if (caret.tpos > 0 && !selection) {

int d = caret.off == 0 ? 2 : 1;text.delete(caret.tpos - d, caret.tpos);

}

} else if (ch == RETURN) {text.insert(caret.tpos, "\r\n");

} else { // normal character typedtext.insert(caret.tpos, String.valueOf(ch));

}}

}

a b c d e f gendbeg

a e f g

• Modifications are done in the text• The text notifies all its views

about the modification (MVC pattern)

Page 37: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

37

5. Text Editors5.1 Data structures for texts

5.1.1 SimpleText5.1.2 GapText5.1.3 PieceListText

5.2 Text representation on the screen (case study)5.2.1 Line descriptors5.2.2 Positions5.2.3 Input handling5.2.4 Updating the view5.2.5 Scrolling

Page 38: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

38

MVC principle (Model View Controller)

void doKeyTyped (KeyEvent e) {...text.insert(pos, string);...

}

void insert (int pos, String s) {...fireUpdateEvent(new UpdateEvent(pos, pos, s));

}

void update (UpdateEvent e) {... // update screen area

}

void fireUpdateEvent (UpdateEvent e) {for (all listeners x) x.update(e);

}

Viewer

Text

...

Model

Controller + View

Page 39: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

39

Implementation of the MVC principleclass UpdateEvent { // [from..to[ was replaced by text

int from, to;String text;UpdateEvent(int a, int b, String t) { from = a; to = b; text = t; }

}interface UpdateEventListener {

void update (UpdateEvent e);}

ArrayList listeners = new ArrayList();public void addUpdateEventListener (UpdateEventListener listener) {

listeners.add(listener);}public void removeUpdateEventListener (UpdateEventListener listener) {

listeners.remove(listener);}private void fireUpdateEvent (UpdateEvent e) {

Iterator iter = listeners.iterator();while (iter.hasNext()) {

UpdateEventListener listener = (UpdateEventListener)iter.next();listener.update(e);

}}

in class Text

public Viewer (...) {text.addUpdateEventListener(this);...

}

in class Viewer

Page 40: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

40

Updating the viewer (insert)class Viewer extends Canvas implements UpdateEventListener {

...public void update (UpdateEvent e) {

if (e.from == e.to) { // insertPosition pos = Pos(e.from);int newCaretPos = pos.tpos + e.text.length();if (e.text.indexOf("\r\n") >= 0) { // insert across lines

rebuildFrom(pos);} else { // insert within a line

StringBuffer b = new StringBuffer(pos.line.text);b.insert(pos.off, e.text);pos.line.text = b.toString();pos.line.w += m.stringWidth(e.text);pos.line.len += e.text.length();lastTpos += e.text.length();repaint(pos.line.x, pos.line.y, getWidth(), pos.line.h);

}setCaret(newCaretPos);

} else if (e.text == null) { // delete...

}}...

}

rebuilds line descriptors starting atthe position pos and calls repaint()for the modified text area

Page 41: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

41

Updating the viewer (delete)class Viewer extends Canvas implements UpdateListener {

...public void update (UpdateEvent e) {

if (e.from == e.to) { // insert...

} else if (e.text == null) { // deletePosition pos = Pos(e.to);int d = e.to - e.from;if (pos.off - d < 0) { // delete across lines

rebuildFrom(Pos(e.from));} else { // delete within a line

StringBuffer b = new StringBuffer(pos.line.text);b.delete(pos.off - d, pos.off);pos.line.text = b.toString();pos.line.w = m.stringWidth(pos.line.text);pos.line.len -= d;lastTpos -= d;repaint(pos.line.x, pos.line.y, getWidth(), pos.line.h);

}setCaret(e.from);

}}...

}

e.from e.to

posd

Page 42: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

42

5. Text Editors5.1 Data structures for texts

5.1.1 SimpleText5.1.2 GapText5.1.3 PieceListText

5.2 Text representation on the screen (case study)5.2.1 Line descriptors5.2.2 Positions5.2.3 Input handling5.2.4 Updating the view5.2.5 Scrolling

Page 43: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

43

ScrollBar and Viewer

JScrollBar scrollBar = new JScrollBar(Adjustable.VERTICAL, 0, 0, 0, 0);Viewer viewer = new Viewer(new Text(), scrollBar);

JPanel panel = new JPanel(new BorderLayout());panel.add("Center", viewer);panel.add("East", scrollBar);

scrollBar.addAdjustmentListener(viewer);

viewer.adjustmentValueChanged(e);

interface AdjustmentListener {void adjustmentValueChanged (AdjustmentEvent e);

}

class AdjustmentEvent {int getValue (); // new scrollbar value...

}

class JScrollBar {void setMinimum (int min);void setMaximum (int max);void setValue (int val);void setValues (int val, int extent,

int min, int max);...

}

Participating types

Interaction

value extent min max

Page 44: 5. Text Editorsssw.jku.at/Misc/SSW/05.TextEditors.pdf5. Text Editors 5.1 Data structures for texts 5.1.1 SimpleText 5.1.2 GapText 5.1.3 PieceListText 5.2 Text representation on the

44

Reaction to scroll eventsclass Viewer extends Canvas implements AdjustmentListener, ... {

...void adjustmentValueChanged (AdjustmentEvent e) {

int pos = e.getValue();if (pos > 0) { // find start of line

char ch;do { pos--; ch = text.charAt(pos); } while (pos > 0 && ch != '\n');if (pos > 0) pos++;

}if (pos != firstTpos) { // scroll

Position caret0 = caret;Selection sel0 = sel;removeSelection();removeCaret();firstTpos = pos;firstLine = fill(TOP, getHeight() - BOTTOM, firstTpos);repaint();if (caret0 != null) setCaret(caret0.tpos);if (sel0 != null) setSelection(sel0.beg.tpos, sel0.end.tpos);

}}...

}