package ckelling.baukasten;

import java.awt.*;
import java.lang.*;
import java.util.*;

// Versionsgeschichte
// 0.5.2            mit appendText(), das nicht alles neu parst;
// 1.0.0, 29.06.97  mit Cache für Formatinfo., Umbruch etc.
// 1.0.1, 06.08.97  Bugfix: Blocksatz; reshape() auch bei Breitenänderung

/**
 *	RTFTextArea.java
 *
 *	Ersatz fuer java.awt.TextArea; erlaubt die Auszeichnung
 *	von Text mit den Attributen "fett" und "kursiv", bricht den
 *  Text korrekt um und unterstützt Blocksatz.
 *
 *	@author		Carsten Kelling
 *	@version	1.0.1, 06.08.97
 */
public class RTFTextArea extends Panel
{
	//// Konstanten ////

    public              Color	BACKGROUND		= Color.white;
    public final static Color	R_BACKGROUND	= new Color(200, 200, 200);
    public final static Color	MEDIUM_GREY 	= new Color(127, 127, 127);
    public final static Color	LIGHT_GREY		= new Color(223, 223, 223);
    public final static Color	LIGHTER_GREY	= new Color(239, 239, 239);

    public final static int	ALL_FLAGS		= 0xff;
    public final static int	BOLD_ON			= 0x1;
    public final static int	BOLD_OFF		= 0x2;
    public final static int	ITALIC_ON		= 0x4;
    public final static int	ITALIC_OFF		= 0x8;
    public final static int	END_OF_WORD		= 0x10;

    public final static int	SCROLLBARWIDTH 	= 18;
    public final static int	HORIZONTAL_GAP	= 4;


	private String      unwrappedText = new String("");
	private String		parsedText = new String("");
	private Font		plainFont;
	private FontMetrics plainFontMetrics;
	private Font		boldFont;
	private FontMetrics boldFontMetrics;
	private Font		italicFont;
	private FontMetrics italicFontMetrics;
	private Font		boldItalicFont;
	private FontMetrics boldItalicFontMetrics;
	private Vector		lines = new Vector(10, 3);
	private Vector		attribs = new Vector(10, 3);
	private boolean		lastBold;
	private boolean		lastItalic;
	private int			lastNumWords;
	private int			lineHeight;

	private int			topLine;
	private int			maxLine;
	private int			maxLengthPixel;
	private int			numRemovedSpaces = 0;
	private Scrollbar	scrollbar;
	private boolean		withScrollbar;
	private boolean		blockMode;
	private Hashtable textCache;


	public RTFTextArea(Font f)
	{
		this(f, new String(""), 0, 0);
	}

	public RTFTextArea(Font f, int rows, int cols)
	{
		this(f, new String(""), rows, cols);
	}

	public RTFTextArea(Font f, String text)
	{
		this(f, text, 0, 0);
	}

	public RTFTextArea(Font f, String text, int rows, int cols)
	{
		super();

		setLayout(null);
		setBackground(BACKGROUND);

		topLine = 0;
		withScrollbar = false;
        scrollbar = new Scrollbar(Scrollbar.VERTICAL);
   	    add(scrollbar);
   	    Rectangle bounds = bounds();
        scrollbar.reshape(bounds.width - 2 - SCROLLBARWIDTH, 2, SCROLLBARWIDTH, bounds.height - 4);
        scrollbar.setBackground(R_BACKGROUND);
        scrollbar.hide();

		setFont(f);
		StringBuffer s = new StringBuffer("");
		for (int i = 0; i < cols; i++)
			s.append("e");
		lineHeight = plainFontMetrics.getHeight();
		resize(plainFontMetrics.stringWidth(s.toString()), rows * plainFontMetrics.getHeight());

		blockMode = true;

		lastBold = false; lastItalic = false; lastNumWords = 0;

		textCache = new Hashtable(100);

		setText(text);
	}

	public void setFont(Font f)
	{
	    super.setFont(f);
	    plainFont = new Font(f.getName(), Font.PLAIN, f.getSize());
	    plainFontMetrics = getFontMetrics(plainFont);
		boldFont = new Font(plainFont.getName(), Font.BOLD, plainFont.getSize());
	    boldFontMetrics = getFontMetrics(boldFont);
		italicFont = new Font(plainFont.getName(), Font.ITALIC, plainFont.getSize());
	    italicFontMetrics = getFontMetrics(italicFont);
		boldItalicFont = new Font(plainFont.getName(), Font.BOLD + Font.ITALIC, plainFont.getSize());
	    boldItalicFontMetrics = getFontMetrics(boldItalicFont);
	}
	
	public void setBackground(Color c)
	{
		super.setBackground(c);
		BACKGROUND = c;
	}

	public void paint(Graphics g)
	{
		Rectangle bounds = bounds();
		g.setColor(BACKGROUND);
		g.fillRect(0, 0, bounds.width, bounds.height);

	    g.setColor(MEDIUM_GREY);
	    g.fillRect(0, 					0, 					bounds.width - 1, 1);
	    g.fillRect(0, 					0, 					1, bounds.height - 1);
	    g.setColor(LIGHT_GREY);
	    g.fillRect(1,    				bounds.height - 2,	bounds.width - 2, 1);
	    g.fillRect(bounds.width - 2,	1,     				1, bounds.height - 3);
	    g.setColor(LIGHTER_GREY);
	    g.fillRect(0, 					bounds.height - 1,	bounds.width, 1);
	    g.fillRect(bounds.width - 1,	0,					1, bounds.height - 1);
	    g.setColor(Color.black);
	    g.fillRect(1,     				1,    				bounds.width - 3, 1);
	    g.fillRect(1,     				1,    				1, bounds.height - 3);

		int y = lineHeight;

		boolean bold = false;
		boolean italic = false;
		Vector lineAttribs;
		for (int i = 0; i < topLine; i++)
		{
			lineAttribs = (Vector) attribs.elementAt(i);
			if (lineAttribs != null)
				for (int j = 0; j < lineAttribs.size(); j++)
				{
					Rectangle p = (Rectangle) lineAttribs.elementAt(j);

					if (p.y == BOLD_ON)
						bold = true;
					else if (p.y == BOLD_OFF)
						bold = false;
					else if (p.y == ITALIC_ON)
						italic = true;
					else if (p.y == ITALIC_OFF)
						italic = false;
				}
		}

		int i = topLine;
		for (; i < Math.min(lines.size(), topLine+maxLine); i++)
		{
			if (attribs.elementAt(i) == null)
				g.drawString((String) lines.elementAt(i), HORIZONTAL_GAP, y);
			else
			{
				lineAttribs = (Vector) attribs.elementAt(i);
				String lineString = (String) lines.elementAt(i);
				//debug System.out.println("RTFTextArea.paint(): " + lineString.length());
				int stringStart = 0;
				int pixelStart = HORIZONTAL_GAP;
				Rectangle p = new Rectangle(0, 0, 0, 0);
				String subString;

				for (int j = 0; j < lineAttribs.size(); j++)
				{
					p = (Rectangle) lineAttribs.elementAt(j);

					if (bold && italic)
						g.setFont(boldItalicFont);
					else if (bold)
						g.setFont(boldFont);
					else if (italic)
						g.setFont(italicFont);
					else
						g.setFont(plainFont);

					subString = lineString.substring(stringStart, p.x);
					g.drawString(subString, pixelStart, y);

					if (bold && italic)
						pixelStart = pixelStart + boldItalicFontMetrics.stringWidth(subString);
					else if (bold)
						pixelStart = pixelStart + boldFontMetrics.stringWidth(subString);
					else if (italic)
						pixelStart = pixelStart + italicFontMetrics.stringWidth(subString);
					else
						pixelStart = pixelStart + plainFontMetrics.stringWidth(subString);
					pixelStart = pixelStart + p.width;  // der Trick fuer Blocksatz

					if (p.y == BOLD_ON)
						bold = true;
					else if (p.y == BOLD_OFF)
						bold = false;
					else if (p.y == ITALIC_ON)
						italic = true;
					else if (p.y == ITALIC_OFF)
						italic = false;
					stringStart = p.x;
				}
				if (bold && italic)
					g.setFont(boldItalicFont);
				else if (bold)
					g.setFont(boldFont);
				else if (italic)
					g.setFont(italicFont);
				else
					g.setFont(plainFont);

				subString = lineString.substring(stringStart, lineString.length());
				g.drawString(subString, pixelStart, y);
			}

			y += lineHeight;


		}
		if (withScrollbar)
		{
	        scrollbar.setValues(topLine, maxLine, 0, lines.size() - maxLine);
	        scrollbar.setLineIncrement(1);
	        scrollbar.setPageIncrement(maxLine);
		}
	}

	public void update(Graphics g)
	{
        paint(g);
	}


	public void resize(int width, int height)
	{
		reshape(bounds().x, bounds().y, width, height);
    }

	public void resize(Dimension d)
	{
		reshape(bounds().x, bounds().y, d.width, d.height);
	}


    public void reshape(int x, int y, int width, int height)
    {
    	int oldWidth = bounds().width;
    	super.reshape(x, y, width, height);

   	    Rectangle bounds = bounds();
   	    if (scrollbar != null)
	        scrollbar.reshape(bounds.width - 2 - SCROLLBARWIDTH, 2, SCROLLBARWIDTH, bounds.height - 4);
		maxLine = (bounds.height - 2) / lineHeight;
		
		if (oldWidth != bounds.width)  // Breite geändert, alle Umbrüche werden ungültig!
		{
			maxLengthPixel = bounds.width - SCROLLBARWIDTH - 2*HORIZONTAL_GAP - 4;
			textCache = new Hashtable(100);
			setText(getText());
		}
		else  // allenfalls die Höhe wurde geändert
		{
			if (lines.size() > maxLine)
			{
				withScrollbar = true;
				scrollbar.show();
			}
			else
			{
				topLine = 0;
				withScrollbar = false;
				scrollbar.hide();
			}
		}

		repaint();
    } /* end reshape */

    private String[] parseText(String text)
    {
    	StringBuffer parsedText = new StringBuffer(text.length());
    	StringBuffer tokens = new StringBuffer(text.length());
    	for (int i = 0; i < text.length(); i++)
    		tokens.append(0);

    	int i = 0;
    	int j;
    	String token;
    	int parsedTextLength = 0;
    	String letter;

    	Fortfahren: while(i < text.length() )
    	{
    		letter = new String( new Character( text.charAt(i) ).toString() );

    		if (letter.equals("<"))
    		{
    			j = i+1;
    			for (; j < text.length(); j++)
    				if ( (new String( new Character( text.charAt(j) ).toString() ) ).equals(">"))
    					break;

    			if (j >= text.length())
    			{
    				Rechner.out("FEHLER in RTFTextArea: Kein passendes '>' für '<' an Position " + i);
    				break Fortfahren;
    			}
    			else
    				token = text.substring(i+1, j);

    			if ( token.equalsIgnoreCase("b") || token.equalsIgnoreCase("strong") )
    			{
    				tokens.setCharAt(parsedTextLength, (char) (tokens.charAt(parsedTextLength) | BOLD_ON & (ALL_FLAGS - BOLD_OFF)));
    			}
    			else if ( token.equalsIgnoreCase("/b") || token.equalsIgnoreCase("/strong") )
    			{
    				tokens.setCharAt(parsedTextLength, (char) (tokens.charAt(parsedTextLength) | BOLD_OFF & (ALL_FLAGS - BOLD_ON)));
    			}
    			else if (token.equalsIgnoreCase("i"))
    			{
    				tokens.setCharAt(parsedTextLength, (char) (tokens.charAt(parsedTextLength) | ITALIC_ON & (ALL_FLAGS - ITALIC_OFF)));
    			}
    			else if (token.equalsIgnoreCase("/i"))
    			{
    				tokens.setCharAt(parsedTextLength, (char) (tokens.charAt(parsedTextLength) | ITALIC_OFF & (ALL_FLAGS - ITALIC_ON)));
    			}
    			else if ( token.equalsIgnoreCase("br") || token.equalsIgnoreCase("p") )
    			{
	    			parsedText.append("\n"); parsedTextLength++;
    			}

    			i = i + token.length() + 1;
    		}
    		else if (letter.equals("&"))
    		// "quote": '&<' wird ersetzt zu '<'
    		{
    			if (i >= text.length() - 1)
    			// letztes Zeichen, kann nur "woertlich" genommen werden
    			{
	    			parsedText.append("&"); parsedTextLength++;
	    		}
    			else if ( ( new String( new Character( text.charAt(i+1) ).toString() ) ).equals("<"))
    			{
    				i++;
    				parsedText.append("<"); parsedTextLength++;
   				}
   				else
   				{
	    			parsedText.append("&"); parsedTextLength++;
	    		}
    		}
    		else
    		// "normale" Buchstaben; an den geparsten Text anhaengen
    		{
    			parsedText.append(letter); parsedTextLength++;
    		}

    		i++;
    	}

    	String parseResult[] = new String[2];
    	parseResult[0] = parsedText.toString();
    	parseResult[1] = tokens.toString();
    	return parseResult;
    } /* end parseText */


    private Vector makeBlock(Vector lineAttribs, int lineLengthPixel, int numWords, int lineLength)
    {
    	if (numWords <= 1)
    		return lineAttribs;
    	else
    	{
    		numWords--;
	    	Vector returnAttribs = new Vector(lineAttribs.size());
	    	Rectangle r;
	    	int commonGap = (maxLengthPixel - lineLengthPixel) / numWords;
	    	int extraGap = (maxLengthPixel - lineLengthPixel) % numWords;
	    	//debug System.out.println("RTFTextArea.makeBlock: " + numWords+1 + " W, " + (maxLengthPixel - lineLengthPixel) + " L, " + commonGap + " C, " + extraGap + " E");
	    	for (int i = 0; i < lineAttribs.size(); i++)
	    	{
	    		r = (Rectangle) lineAttribs.elementAt(i);
	    		if (r.x > lineLength)
	    		// Durch das Entfernen von Leerzeichen am Ende der Zeile
	    		// koennen ungueltige Token entstehen.
	    			r.x = lineLength;

	    		if (r.y != END_OF_WORD)
	    			returnAttribs.addElement(r);
    			else
    			{
    				if (extraGap > 0)
    				{
	    				extraGap--;
		    			returnAttribs.addElement(new Rectangle(r.x, r.y, commonGap + 1, 0));
		    		}
	    			else
	    				returnAttribs.addElement(new Rectangle(r.x, r.y, commonGap, 0));
		    	}
	    	}

	    	return returnAttribs;
	    }

    } /* end makeBlock */


    private Vector removeBlock(Vector lineAttribs)
    {
    	Vector returnAttribs = new Vector(lineAttribs.size());
    	Rectangle r;

    	for (int i = 0; i < lineAttribs.size(); i++)
    	{
    		r = (Rectangle) lineAttribs.elementAt(i);
    		if (r.y != END_OF_WORD)
    			returnAttribs.addElement(r);
    	}

    	return returnAttribs;
    } /* end removeBlock */


    private Vector newLineAttribs()
    {
    	if (blockMode)
    		return new Vector(10, 2);
    	else
    		return null;
    }

    private String removeTrailingSpaces(String str)
    {
    	if ( ! str.startsWith(" ") )
    	{
    		String trimmed = str.trim();
    		numRemovedSpaces = str.length() - trimmed.length();
    		return trimmed;
    	}
    	else
    	{
    		numRemovedSpaces = 0;
    		StringBuffer leadingSpaces = new StringBuffer("");
    		Character space = new Character(' ');
    		Character current = new Character(str.charAt(numRemovedSpaces));
    		while (current.equals(space))
    		{
    			leadingSpaces.append(current);
    			numRemovedSpaces++;
    			current = new Character(str.charAt(numRemovedSpaces));
    		}
    		return new String(leadingSpaces.toString() + str.trim());
    	}
    } /* end removeTrailingSpaces */


	public void appendText(String text)
	{
		unwrappedText = new String(unwrappedText + text);

		//noStats long startTime = System.currentTimeMillis();
		RTFParsedText cached = (RTFParsedText) textCache.get(unwrappedText);
		if (cached == null)  // noch nicht im Cache
		{
			//String parseResult[] = parseText(unwrappedText);
			String parseResult[] = parseText(text);
			String newParsedText = parseResult[0];
			parsedText = new String(parsedText + newParsedText);
			String tokens = parseResult[1];

			StringBuffer line;
			if (lines.isEmpty())
				line = new StringBuffer("");
			else
			{
				line = new StringBuffer((String) lines.elementAt(lines.size()-1));
				lines.removeElementAt(lines.size()-1);
			}
			StringBuffer word = new StringBuffer("");
			String letter;
			int token;
			boolean bold = lastBold; boolean italic = lastItalic;
			int numWords = lastNumWords;
			int position = 0;
			int lineLengthPixel = 0; int wordLengthPixel = 0; int letterLengthPixel = 0;
			int spaceLength = plainFontMetrics.stringWidth(" ");
			Rectangle bounds = bounds();
			Vector lineAttribs;
			if (attribs.isEmpty())
				lineAttribs = newLineAttribs();
			else
			{
				lineAttribs = (Vector) attribs.elementAt(attribs.size()-1);
				attribs.removeElementAt(attribs.size()-1);
			}


			for (int i = 0; i < newParsedText.length(); i++)
			{
				letter = new String( new Character( newParsedText.charAt(i) ).toString() );
				token  = (int) tokens.charAt(i);
				// naechsten Buchstaben und naechstes Token holen

			//// Token-Auswertung ////
				position = line.length() + word.length();
				if ( (token != 0) && (lineAttribs == null) )
					lineAttribs = new Vector(4, 2);

				if ( (token & BOLD_ON) == BOLD_ON )
				{
					lineAttribs.addElement(new Rectangle(position, BOLD_ON, 0, 0));
					bold = true;
				}
				else if ( (token & BOLD_OFF) == BOLD_OFF )
				{
					lineAttribs.addElement(new Rectangle(position, BOLD_OFF, 0, 0));
					bold = false;
				}

				if ( (token & ITALIC_ON) == ITALIC_ON )
				{
					lineAttribs.addElement(new Rectangle(position, ITALIC_ON, 0, 0));
					italic = true;
				}
				else if ( (token & ITALIC_OFF) == ITALIC_OFF )
				{
					lineAttribs.addElement(new Rectangle(position, ITALIC_OFF, 0, 0));
					italic = false;
				}

				if (bold && italic)
				{
					letterLengthPixel = boldItalicFontMetrics.stringWidth(letter.toString());
				}
				else if (bold)
				{
					letterLengthPixel = boldFontMetrics.stringWidth(letter.toString());
				}
				else if (italic)
				{
					letterLengthPixel = italicFontMetrics.stringWidth(letter.toString());
				}
				else
				{
					letterLengthPixel = plainFontMetrics.stringWidth(letter.toString());
				}

			//// Zeichen-Auswertung ////
				if (! ( letter.equals(" ") || letter.equals("\n") ) )
				// kein Trennzeichen, aktuellen Buchstaben zu aktuellem Wort hinzufuegen
				{
					word.append(letter); wordLengthPixel = wordLengthPixel + letterLengthPixel;
				}
				else
				// aktuelles Wort endet, paßt es auf die Zeile?
				{
					//lineLength = plainFontMetrics.stringWidth(line.toString() + word.toString());

					if ( (letter.equals(" ")) && (lineLengthPixel + wordLengthPixel + letterLengthPixel <= maxLengthPixel) )
					// aktuelles Wort und das Trennzeichen passen noch auf Zeile, Zeile soll noch nicht beendet werden
					{
						numWords++;
						line.append(word);
						line.append(letter); lineLengthPixel = lineLengthPixel + wordLengthPixel + letterLengthPixel;
						if (blockMode)
							lineAttribs.addElement(new Rectangle(position, END_OF_WORD, 0, 0));

						word = new StringBuffer(""); wordLengthPixel = 0;
					}
					else if (lineLengthPixel + wordLengthPixel <= maxLengthPixel)
					// entweder: das Trennzeichen ist "\n"
					// oder: aktuelles Wort paßt nur ohne das Trennzeichen auf die Zeile
					{
						line.append(word); lineLengthPixel = lineLengthPixel + wordLengthPixel;
				    	//debug System.out.println(maxLengthPixel + ", " + plainFontMetrics.stringWidth(line.toString()));
						if (blockMode)
						{
							//lineAttribs.addElement(new Rectangle(position, END_OF_WORD, 0, 0));
							if (letter.equals("\n"))
								lineAttribs = removeBlock(lineAttribs);
							else
								lineAttribs = makeBlock(lineAttribs, lineLengthPixel, numWords + 1, line.length());
						}
						numWords = 0;

						// Trennzeichen fällt weg
						word = new StringBuffer("");  wordLengthPixel = 0;

						// neue Zeile anfangen
						lines.addElement(line.toString());
						attribs.addElement(lineAttribs); lineAttribs = newLineAttribs();
						line = new StringBuffer(""); lineLengthPixel = 0;
					}
					else
					// Wort passt nicht mehr auf Zeile, auf die naechste uebernehmen
					{
					   	//debug System.out.println(maxLengthPixel + ", " + plainFontMetrics.stringWidth(line.toString()));
						if (blockMode)
						{
							line = new StringBuffer(removeTrailingSpaces(line.toString()));
							lineLengthPixel = lineLengthPixel - numRemovedSpaces*spaceLength;
							lineAttribs = makeBlock(lineAttribs, lineLengthPixel, numWords, line.length());
						}
						numWords = 0;

						lines.addElement(line.toString());
						attribs.addElement(lineAttribs); lineAttribs = newLineAttribs();
						line = word; lineLengthPixel = wordLengthPixel;
						word = new StringBuffer(""); wordLengthPixel = 0;

						if (blockMode)
						{
							lineAttribs.addElement(new Rectangle(line.length(), END_OF_WORD, 0, 0));
							numWords++;
						}

						if (letter.equals("\n"))
						{
							lineAttribs = removeBlock(lineAttribs);
							lines.addElement(line.toString());
							attribs.addElement(lineAttribs); lineAttribs = newLineAttribs();
							line = new StringBuffer(""); lineLengthPixel = 0;
							letter = new String(""); letterLengthPixel = 0;
						}

						line.append(letter); lineLengthPixel = lineLengthPixel + letterLengthPixel;
					}
				}
			}

			/**
			if (bold && italic)
				wordLengthPixel = boldItalicFontMetrics.stringWidth(word.toString());
			else if (bold)
				wordLengthPixel = boldFontMetrics.stringWidth(word.toString());
			else if (italic)
				wordLengthPixel = italicFontMetrics.stringWidth(word.toString());
			else
				wordLengthPixel = plainFontMetrics.stringWidth(word.toString());
			*/

			if (lineLengthPixel + wordLengthPixel > maxLengthPixel)
			{
				if (blockMode)
				{
					line = new StringBuffer(removeTrailingSpaces(line.toString()));
					lineLengthPixel = lineLengthPixel - numRemovedSpaces*spaceLength;
					lineAttribs = makeBlock(lineAttribs, lineLengthPixel, numWords, line.length());
				}
				lines.addElement(line.toString());
				attribs.addElement(lineAttribs); lineAttribs = newLineAttribs();
				line = new StringBuffer("");
			}

			line.append(word);
			lines.addElement(line.toString());
			attribs.addElement(lineAttribs);

			lastBold = bold; lastItalic = italic; lastNumWords = numWords;

			if (lines.size() > maxLine)
			{
				withScrollbar = true;
				scrollbar.show();
			}
			else
			{
				topLine = 0;
				withScrollbar = false;
				scrollbar.hide();
			}

			textCache.put(unwrappedText, getParsedText());

			repaint();

			//noStats long endTime = System.currentTimeMillis();
			//noStats System.out.println("RTFTextArea: Parsed text in " + ((int) (endTime - startTime)) + " ms.");
		}
		else  // dieser Text ist schon einmal geparst worden und das Ergebnis befindet sich im Cache.
		{
			setText(cached);  // ruft repaint() auf

			//noStats long endTime = System.currentTimeMillis();
			//noStats System.out.println("RTFTextArea: Redisplayed text from cache in " + ((int) (endTime - startTime)) + " ms.");
		}

	} /* end appendText */


	public void setText(String newText)
	{
		// Es muessen nachfolgend neue Objekte erzeugt werden (kein Vector.removeAllElements())!
		lines = new Vector(10, 3);
		attribs = new Vector(10, 3);
		unwrappedText = new String("");

		lastBold = false; lastItalic = false; lastNumWords = 0;

		topLine = 0;
		appendText(newText);
	}

	public void setText(RTFParsedText r)
	{
		unwrappedText = r.unwrappedText;
		parsedText = r.parsedText;
		lines = r.lines;
		attribs = r.attribs;

		lastBold = false; lastItalic = false; lastNumWords = 0;

		topLine = 0;

		if (lines.size() > maxLine)
		{
			withScrollbar = true;
			scrollbar.show();
		}
		else
		{
			topLine = 0;
			withScrollbar = false;
			scrollbar.hide();
		}

		repaint();
	}

	public void setBlockMode(boolean b)
	{
		if (b != blockMode)
		{
			blockMode = b;
			setText(unwrappedText);
		}
	}

	public boolean isBlockMode()
	{
		return blockMode;
	}


	public String getText()
	{
		return unwrappedText;
	}

	public RTFParsedText getParsedText()
	{
		Vector linesClone = new Vector(lines.size());
		Vector attribsClone = new Vector(attribs.size());

		for (int i = 0; i < lines.size(); i++)
			linesClone.addElement(new String((String) lines.elementAt(i)));

		for (int i = 0; i < attribs.size(); i++)
		{
			if (attribs.elementAt(i) == null)
				attribsClone.addElement(null);
			else
			{
				Vector lineAttribs = (Vector) attribs.elementAt(i);
				Vector lineAttribsClone = new Vector(lineAttribs.size());
				lineAttribsClone = new Vector(lineAttribs.size());
				for (int j = 0; j < lineAttribs.size(); j++)
				{
					Rectangle r = (Rectangle) lineAttribs.elementAt(j);
					lineAttribsClone.addElement(new Rectangle(r.x, r.y, r.width, r.height));
				}
				attribsClone.addElement(lineAttribsClone);
			}
		}

		RTFParsedText r = new RTFParsedText(unwrappedText, parsedText, linesClone, attribsClone);
		return r;
	}

    public boolean handleEvent(Event event)
    {
        if (event.id == Event.SCROLL_PAGE_UP && event.target == scrollbar) {
            scrollPageUp(event);
            return true;
        }
        else if (event.id == Event.SCROLL_PAGE_DOWN && event.target == scrollbar) {
            scrollPageDown(event);
            return true;
        }
        else if (event.id == Event.SCROLL_LINE_UP && event.target == scrollbar) {
            scrollLineUp(event);
            return true;
        }
        else if (event.id == Event.SCROLL_LINE_DOWN && event.target == scrollbar) {
            scrollLineDown(event);
            return true;
        }
        else if (event.id == Event.SCROLL_ABSOLUTE && event.target == scrollbar) {
            scrollAbsolute(event);
            return true;
        }

        return super.handleEvent(event);
    } /* end handleEvent */

    public synchronized void scrollAbsolute(Event ev) {
        topLine = scrollbar.getValue();
        repaint();
    }
    public void scrollLineDown(Event ev) {
        topLine = scrollbar.getValue();
        repaint();
    }
    public void scrollLineUp(Event ev) {
        topLine = scrollbar.getValue();
        repaint();
    }
    public void scrollPageDown(Event ev) {
        topLine = scrollbar.getValue();
        repaint();
        // Bug im appletviewer: es wird immer um 10 abwaerts gescrollt
        /*if (topLine + numRows <= maxLine)
            scrollTo(topLine + numRows);
        else
            scrollTo(scrollbar.getValue());
        scrollbar.setValue(topLine);
        */
    }
    public void scrollPageUp(Event ev) {
        topLine = scrollbar.getValue();
        repaint();
        // Bug im appletviewer: es wird immer um 10 aufwaerts gescrollt
        /*if (topLine - numRows >= 0)
            scrollTo(topLine - numRows);
        else
            scrollTo(scrollbar.getValue());
        scrollbar.setValue(topLine);
        */
    }

} /* end RTFTextArea */


