Webber: A Website Construction Application


HtmlEdit.java


// A HtmlPage component with editing functionality added

package library.html;

import java.awt.*;
import java.util.*;
import java.awt.event.*;

public class HtmlEdit extends HtmlPage {
	private String linesep = System.getProperty("line.separator");
	private int curx, cury, pos;

	// Page constructors
	public HtmlEdit() { this(null); }
	public HtmlEdit(char[] text) {
		super(text);
		reader.setHtmlEnabled(false);		// Disable HTML output
	}

	// Implement handling for text-event listeners
	private TextListener textListener = null;
	public void addTextListener(TextListener l) {
		textListener = AWTEventMulticaster.add(textListener, l);
	}
	public void removeTextListener(TextListener l) {
		textListener = AWTEventMulticaster.remove(textListener, l);
	}
	public void processEvent(AWTEvent e) {
		if (e instanceof TextEvent) {
			if (textListener != null)
				textListener.textValueChanged((TextEvent)e);
		} else super.processEvent(e);
	}

	// Update text with text incremented by offset at pos (dispatches a text event)
	private void modifyText(char[] text, int offset) {
//		resetText(text);				// Reset text
		updateText(text, pos, offset);			// Update text
		processEvent(new TextEvent(this, TextEvent.TEXT_VALUE_CHANGED));
	}

	//  Override HtmlPage to ensure HtmlPage.text is not null (& reset page)
	public void setText(char[] text, boolean isPlain) {
		super.setText((text==null) ? new char[0] : text, isPlain);
		curx = cury = pos = 0;				// Reset cursor & pos
	}

	// Override HtmlPage to change the default text-formatting mode
	public boolean isPlainText() { return true; }

	// Override HtmlPage to change the default font settings
	protected Font getNormalFont() { return getTeleFont(); }

	// Override HtmlPage to add the cursor
	public void paint(Graphics g) { super.paint(g); putCursor(g); }

	// Return window coordinates for the edit cursor
	private int getWinXpos() { return getLineStart() + curx - left; }
	private int getWinYpos() { return getPageStart() + cury - top; }

	// Draw/erase cursor
	private void putCursor(Graphics g) {
		int x = getWinXpos(), y = getWinYpos();
		g.setColor(Color.black);
		g.setXORMode(Color.white);
		g.drawLine(x, y, x, y+lineheight-1);
		g.setPaintMode();
	}
	private void putCursor() { putCursor(getGraphics()); }

	// Returns true if there is a CR/NL sequence at pos in text
	private static boolean isCrNl(char[] text, int pos) {
		if ((pos<0) || (pos+1>=text.length)) return false;
		return ((text[pos]!='\r') || (text[pos+1]!='\n')) ? false : true;
	}

	// Returns true if text at pos is an end-of-line sequence
	private static boolean isEndOfLine(char[] text, int pos) {
		if (text[pos]=='\n') return true;	// Unix
		if (isCrNl(text, pos)) return true;	// DOS
		return false;
	}

	// Return the number of characters in the sequence at pos in text (1 or 2)
	private static int charSize(char[] text, int pos) {
		return isCrNl(text, pos) ? 2 : 1;	// Two chars for DOS CR/NL
	}

	// Return text with length characters from pos removed
	private static char[] deleteChars(char[] text, int pos, int length) {
		String s = new String(text, 0, pos)
			 + new String(text, pos+length, text.length-(pos+length));
		return s.toCharArray();
	}
	private static char[] deleteChar(char[] text, int pos) {
		return deleteChars(text, pos, charSize(text, pos));
	}

	// Return text with s inserted at pos
	private static char[] insertChars(char[] text, int pos, String s) {
		s = new String(text, 0, pos) + s
		  + new String(text, pos, text.length-pos);
		return s.toCharArray();
	}
	private static char[] insertChar(char[] text, int pos, char c) {
		return insertChars(text, pos, "" + c);
	}

	// Return the character offset of pos into it's line in text
	private int getPosInLine(char[] text, int pos) {
		int i;
		for (i=pos; i > 0; --i) if (text[i-1]=='\n') break;
		return pos - i;
	}

	// Return the width of a line of text (with tabs)
	private int getLineWidth(String s) {
		int start = getLineStart();
		return textLine(s, start, 0, null) - start;
	}

	// Return the screen offset of pos into it's line in text
	private int getLinePos(char[] text, int pos) {
		int p = getPosInLine(text, pos);
		return getLineWidth(new String(text, pos-p, p));
	}

	// Return the length of the line from pos in text
	private static int getLineLength(char[] text, int pos) {
		int i;
		for (i=pos; i<text.length; ++i)
			if (isEndOfLine(text, i)) break;
		return i - pos;
	}

	// Set the current character position in the current line
	private void setPosInLine(int p) {
		pos -= getPosInLine(text, pos);		// Move to start of line
		int len = getLineLength(text, pos);	// Get total line length
		pos += (p > len) ? len : p;		// Set actual position
		curx = getLinePos(text, pos);		// Get cursor column
	}

	// Adjust page line to ensure cursor visibility (true if adjusted)
	private boolean findCursorLine() {
		int y = getWinYpos(), h = getNumLines() * lineheight;
		if (y<0) do {
			top -= lineheight;
			y = getWinYpos();
		} while (y<0);
		else if (y>=h) do {
			top += lineheight;
			y = getWinYpos();
		} while (y>=h);
		else return false;
		return true;
	}

	// Adjust page column to ensure cursor visibility (true if adjusted)
	private boolean findCursorColumn() {
		int x = getWinXpos(), w = getSize().width;
		if (x<0) do {
			left -= tabsize;
			x = getWinXpos();
		} while (x<0);
		else if (x>=w) do {
			left += tabsize;
			x = getWinXpos();
		} while (x>=w);
		else return false;
		return true;
	}

	// Adjust page to ensure cursor visibility (true if adjusted)
	private boolean findCursor() {
		boolean y = findCursorLine(), x = findCursorColumn();
		return x || y;
	}

	// Move current character position to the start of the next line
	// Parameter p is the offset to the end of the current line
	private boolean nextLine(int p) {
		if (pos+p >= text.length) return false;	// No next line?
		pos += p + charSize(text, pos+p);
		cury += lineheight;			// Move cursor line
		return true;
	}
	private boolean nextLine() { return nextLine(getLineLength(text, pos)); }

	// Move current character position to the end of the previous line
	// Parameter p is the offset to the start of the current line
	private boolean lastLine(int p) {
		if (p==pos) return false;		// No prior line?
		pos -= p + charSize(text, pos - p - 2);
		cury -= lineheight;			// Move cursor line
		return true;
	}
	private boolean lastLine() { return lastLine(getPosInLine(text, pos)); }

	// Move position up or down by offset lines
	private void movePos(int offset) {
		while (offset<0) { lastLine(); ++offset; }
		while (offset>0) { nextLine(); --offset; }
	}

	// Move page up or down by offset lines (response to KeyEvent)
	private void movePage(int offset, KeyEvent e) {
		int p = getPosInLine(text, pos),	// Get character position
		    q = pos;				// Store current position
		putCursor();				// Erase cursor
		super.keyPressed(e);			// Move page
		if (q!=pos) putCursor();		// Erase cursor again?
		movePos(offset);			// Move cursor
	    	setPosInLine(p);			// Restore position
		putCursor();				// Redraw cursor
	}

	// Move left one character
	private void charLeft() {
		if (getPosInLine(text, pos) > 0) --pos;	// Start of line?
		else lastLine(0);			// Prior line
		curx = getLinePos(text, pos);
	}

	// Move right one character
	private void charRight() {
		if (!isEndOfLine(text, pos)) ++pos;	// End of line?
		else nextLine(0);			// Next line
		curx = getLinePos(text, pos);
	}

	// Process special keys (overrides HtmlPage)
	public void keyPressed(KeyEvent e) {
		int p, q;
		switch (e.getKeyCode()) {
		    case KeyEvent.VK_UP:
		    	p = getPosInLine(text, pos);	// Get character position
		    	if (p==pos) break;		// Top line?
		    	putCursor();			// Erase cursor
		    	lastLine(p);			// Move to prior line
		    	setPosInLine(p);		// Restore position
			if (!findCursor()) putCursor();	// Redraw cursor
			else repaint();			// Redraw page
			break;
		    case KeyEvent.VK_DOWN:
			q = getLineLength(text, pos);	// Get end of line
			if (pos+q>=text.length) break;	// Bottom line?
			p = getPosInLine(text, pos);	// Get character position
		    	putCursor();			// Erase cursor
		    	nextLine(q);			// Move to next line
		    	setPosInLine(p);		// Restore position
			if (!findCursor()) putCursor();	// Redraw cursor
			else repaint();			// Redraw page
			break;
		    case KeyEvent.VK_LEFT:
			if (pos<1) break;		// Start of text?
		    	putCursor();			// Erase cursor
		    	charLeft();			// Left one character
			if (!findCursor()) putCursor();	// Redraw cursor
			else repaint();			// Redraw page
			break;
		    case KeyEvent.VK_RIGHT:
			if (pos>=text.length) break;	// End of text?
			putCursor();			// Erase cursor
			charRight();			// Right one character
			if (!findCursor()) putCursor();	// Redraw cursor
			else repaint();			// Redraw page
			break;
		    case KeyEvent.VK_PAGE_UP:
		    	movePage(-getNumLines(), e);	// Move page & cursor
			break;
		    case KeyEvent.VK_PAGE_DOWN:
			movePage(getNumLines(), e);	// Move page & cursor
			break;
		    case KeyEvent.VK_HOME:
			putCursor();			// Erase cursor
			pos -= getPosInLine(text, pos);
			curx = 0;
			if (!findCursor()) putCursor();	// Redraw cursor
			else repaint();			// Redraw page
			break;
		    case KeyEvent.VK_END:
			putCursor();			// Erase cursor
		    	pos += getLineLength(text, pos);// Move to end of line
		    	curx = getLinePos(text, pos);	// Calculate screen pos
			if (!findCursor()) putCursor();	// Redraw cursor
			else repaint();			// Redraw page
			break;
		    case KeyEvent.VK_BACK_SPACE:
			if (pos<1) break;
			charLeft();			// Proceed using DELETE
		    case KeyEvent.VK_DELETE:
			if (pos>=text.length) break;
			p = charSize(text, pos);	// Get deletion count
			if (isEndOfLine(text, pos))	// Decrement total height?
				addHtmlHeight(-lineheight);
			modifyText(deleteChar(text, pos), -p);
			findCursor();			// Adjust page to cursor
			repaint();			// Redraw page
			break;
		    case KeyEvent.VK_ENTER:
		    	p = linesep.length();
		    	modifyText(insertChars(text, pos, linesep), p);
		    	addHtmlHeight(lineheight);	// Increment total height
		    	pos += p;
		    	curx = 0;
		    	cury += lineheight;
			findCursor();			// Adjust page to cursor
			repaint();			// Redraw page
		    	break;
		    case KeyEvent.VK_TAB:		// Block focus transfer
		    	e.setKeyCode(KeyEvent.VK_SPACE);
		    	break;
		    default:
		    	super.keyPressed(e);
		}
	}

	// Read text characters
	public void keyTyped(KeyEvent e) {
		char c = e.getKeyChar();
		if ((c!='\t') && Character.isISOControl(c)) return;
		modifyText(insertChar(text, pos, c), 1);// Update text
		curx = getLinePos(text, ++pos);		// Get new cursor pos
		findCursor();				// Adjust page to cursor
		repaint();				// Redraw page
	}
}

Go To: Source Code