content: /*
   * SyntaxDocument.java - Document that can be tokenized Copyright (C) 1999 Slava
   * Pestov
   *
   * You may use and modify this package for any purpose. Redistribution is
   * permitted, in both source and binary form, provided that this notice remains
   * intact in all source distributions of this package.
   */
  
  package mars.venus.editors.jeditsyntax;
  
  import javax.swing.event.DocumentEvent;
  import javax.swing.text.BadLocationException;
  import javax.swing.text.Element;
  import javax.swing.text.PlainDocument;
  import javax.swing.text.Segment;
  import javax.swing.undo.UndoableEdit;
  
  import mars.venus.editors.jeditsyntax.tokenmarker.TokenMarker;
  
  /**
   * A document implementation that can be tokenized by the syntax highlighting
   * system.
   *
   * @author Slava Pestov
   * @version $Id: SyntaxDocument.java,v 1.14 1999/12/13 03:40:30 sp Exp $
   */
  public class SyntaxDocument extends PlainDocument {
  
  	/**
  	 *
  	 */
  	private static final long serialVersionUID = 7222918425881723251L;
  
  	/**
  	 * Returns the token marker that is to be used to split lines of this document
  	 * up into tokens. May return null if this document is not to be colorized.
  	 */
  	public TokenMarker getTokenMarker() { return tokenMarker; }
  
  	/**
  	 * Sets the token marker that is to be used to split lines of this document up
  	 * into tokens. May throw an exception if this is not supported for this type of
  	 * document.
  	 *
  	 * @param tm The new token marker
  	 */
  	public void setTokenMarker(final TokenMarker tm) {
  		tokenMarker = tm;
  		if (tm == null) { return; }
  		tokenMarker.insertLines(0, getDefaultRootElement().getElementCount());
  		tokenizeLines();
  	}
  
  	/**
  	 * Reparses the document, by passing all lines to the token marker. This should
  	 * be called after the document is first loaded.
  	 */
  	public void tokenizeLines() {
  		tokenizeLines(0, getDefaultRootElement().getElementCount());
  	}
  
  	/**
  	 * Reparses the document, by passing the specified lines to the token marker.
  	 * This should be called after a large quantity of text is first inserted.
  	 *
  	 * @param start The first line to parse
  	 * @param len   The number of lines, after the first one to parse
  	 */
  	public void tokenizeLines(final int start, int len) {
  		if (tokenMarker == null || !tokenMarker.supportsMultilineTokens()) { return; }
  
  		final Segment lineSegment = new Segment();
  		final Element map = getDefaultRootElement();
  
  		len += start;
  
  		try {
  			for (int i = start; i < len; i++) {
  				final Element lineElement = map.getElement(i);
  				final int lineStart = lineElement.getStartOffset();
  				getText(lineStart, lineElement.getEndOffset() - lineStart - 1, lineSegment);
  				tokenMarker.markTokens(lineSegment, i);
  			}
  		} catch (final BadLocationException bl) {
  			bl.printStackTrace();
  		}
  	}
  
  	/**
  	 * Starts a compound edit that can be undone in one operation. Subclasses that
  	 * implement undo should override this method; this class has no undo
  	 * functionality so this method is empty.
  	 */
  	public void beginCompoundEdit() {}
  
  	/**
  	 * Ends a compound edit that can be undone in one operation. Subclasses that
  	 * implement undo should override this method; this class has no undo
  	 * functionality so this method is empty.
  	 */
  	public void endCompoundEdit() {}
  
  	/**
  	 * Adds an undoable edit to this document's undo list. The edit should be
  	 * ignored if something is currently being undone.
  	 *
  	 * @param edit The undoable edit
  	 * @since jEdit 2.2pre1
  	 */
  	public void addUndoableEdit(final UndoableEdit edit) {}
  
  	// protected members
  	protected TokenMarker tokenMarker;
  
  	/**
  	 * We overwrite this method to update the token marker state immediately so that
  	 * any event listeners get a consistent token marker.
  	 */
  	@Override
  	protected void fireInsertUpdate(final DocumentEvent evt) {
  		if (tokenMarker != null) {
  			final DocumentEvent.ElementChange ch = evt.getChange(getDefaultRootElement());
  			if (ch != null) {
  				tokenMarker.insertLines(ch.getIndex() + 1, ch.getChildrenAdded().length - ch
  						.getChildrenRemoved().length);
  			}
  		}
  
  		super.fireInsertUpdate(evt);
  	}
  
  	/**
  	 * We overwrite this method to update the token marker state immediately so that
  	 * any event listeners get a consistent token marker.
  	 */
  	@Override
  	protected void fireRemoveUpdate(final DocumentEvent evt) {
  		if (tokenMarker != null) {
  			final DocumentEvent.ElementChange ch = evt.getChange(getDefaultRootElement());
  			if (ch != null) {
  				tokenMarker.deleteLines(ch.getIndex() + 1, ch.getChildrenRemoved().length - ch
  						.getChildrenAdded().length);
  			}
  		}
  
  		super.fireRemoveUpdate(evt);
  	}
  }
  