Package org.fife.ui.rtextarea

Source Code of org.fife.ui.rtextarea.RTextAreaHighlighter

/*
* 10/13/2013
*
* RTextAreaHighlighter.java - Highlighter for RTextAreas.
*
* This library is distributed under a modified BSD license.  See the included
* RSyntaxTextArea.License.txt file for details.
*/
package org.fife.ui.rtextarea;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.util.ArrayList;
import java.util.List;
import javax.swing.plaf.TextUI;
import javax.swing.plaf.basic.BasicTextUI.BasicHighlighter;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.LayeredHighlighter;
import javax.swing.text.Position;
import javax.swing.text.View;

import org.fife.ui.rsyntaxtextarea.DocumentRange;


/**
* The highlighter implementation used by {@link RTextArea}s.  It knows to
* always paint "mark all" highlights below selection highlights.<p>
*
* Most of this code is copied from javax.swing.text.DefaultHighlighter;
* unfortunately, we cannot re-use much of it since it is package private.
*
* @author Robert Futrell
* @version 1.0
*/
public class RTextAreaHighlighter extends BasicHighlighter {

  /**
   * The text component we are the highlighter for.
   */
  protected RTextArea textArea;

  /**
   * The "mark all" highlights (to be painted separately from other
   * highlights).
   */
  private List<HighlightInfo> markAllHighlights;

  /**
   * Constructor.
   */
  public RTextAreaHighlighter() {
    markAllHighlights = new ArrayList<HighlightInfo>();
  }


  /**
   * Adds a special "marked occurrence" highlight.
   *
   * @param start
   * @param end
   * @param p
   * @return A tag to reference the highlight later.
   * @throws BadLocationException
   * @see #clearMarkAllHighlights()
   */
  Object addMarkAllHighlight(int start, int end, HighlightPainter p)
      throws BadLocationException {
    Document doc = textArea.getDocument();
    TextUI mapper = textArea.getUI();
    // Always layered highlights for marked occurrences.
    HighlightInfoImpl i = new LayeredHighlightInfoImpl();
    i.setPainter(p);
    i.p0 = doc.createPosition(start);
    // HACK: Use "end-1" to prevent chars the user types at the "end" of
    // the highlight to be absorbed into the highlight (default Highlight
    // behavior).
    i.p1 = doc.createPosition(end-1);
    markAllHighlights.add(i);
    mapper.damageRange(textArea, start, end);
    return i;
  }


  /**
   * Removes all "mark all" highlights from the view.
   *
   * @see #addMarkAllHighlight(int, int, javax.swing.text.Highlighter.HighlightPainter)
   */
  void clearMarkAllHighlights() {
    // Don't remove via an iterator; since our List is an ArrayList, this
    // implies tons of System.arrayCopy()s
    for (HighlightInfo info : markAllHighlights) {
      repaintListHighlight(info);
    }
    markAllHighlights.clear();
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public void deinstall(JTextComponent c) {
    this.textArea = null;
    markAllHighlights.clear();
  }


  /**
   * Returns the number of "mark all" highlights currently shown in the
   * editor.
   *
   * @return The "mark all" highlight count.
   */
  public int getMarkAllHighlightCount() {
    return markAllHighlights.size();
  }


  /**
   * Returns a list of "mark all" highlights in the text area.  If there are
   * no such highlights, this will be an empty list.
   *
   * @return The list of "mark all" highlight ranges.
   */
  public List<DocumentRange> getMarkAllHighlightRanges() {
    List<DocumentRange> list = new ArrayList<DocumentRange>(
        markAllHighlights.size());
    for (HighlightInfo info : markAllHighlights) {
      int start = info.getStartOffset();
      int end = info.getEndOffset() + 1; // HACK
      DocumentRange range = new DocumentRange(start, end);
      list.add(range);
    }
    return list;
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public void install(JTextComponent c) {
    super.install(c);
    this.textArea = (RTextArea)c;
  }


  /**
   * When leaf Views (such as LabelView) are rendering they should
   * call into this method. If a highlight is in the given region it will
   * be drawn immediately.
   *
   * @param g Graphics used to draw
   * @param lineStart starting offset of view
   * @param lineEnd ending offset of view
   * @param viewBounds Bounds of View
   * @param editor JTextComponent
   * @param view View instance being rendered
   */
  @Override
  public void paintLayeredHighlights(Graphics g, int lineStart, int lineEnd,
            Shape viewBounds, JTextComponent editor, View view) {
    paintListLayered(g, lineStart,lineEnd, viewBounds, editor, view,
        markAllHighlights);
    super.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds, editor,
        view);
  }


  protected void paintListLayered(Graphics g, int lineStart, int lineEnd,
      Shape viewBounds, JTextComponent editor, View view,
      List<? extends HighlightInfo> highlights) {
    for (int i=highlights.size()-1; i>=0; i--) {
      HighlightInfo tag = highlights.get(i);
      if (tag instanceof LayeredHighlightInfo) {
        LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag;
        int highlightStart = lhi.getStartOffset();
        int highlightEnd = lhi.getEndOffset() + 1; // "+1" workaround for Java highlight issues
        if ((lineStart < highlightStart && lineEnd > highlightStart) ||
            (lineStart >= highlightStart && lineStart < highlightEnd)) {
          lhi.paintLayeredHighlights(g, lineStart, lineEnd, viewBounds,
                  editor, view);
        }
      }
    }
  }


  protected void repaintListHighlight(HighlightInfo info) {
    // Note: We're relying on implementation here, not interface.  Yuck...
    if (info instanceof LayeredHighlightInfoImpl) {
      LayeredHighlightInfoImpl lhi = (LayeredHighlightInfoImpl)info;
        if (lhi.width > 0 && lhi.height > 0) {
          textArea.repaint(lhi.x, lhi.y, lhi.width, lhi.height);
        }
    }
    else {
      TextUI ui = textArea.getUI();
      ui.damageRange(textArea, info.getStartOffset(),info.getEndOffset());
      //safeDamageRange(info.p0, info.p1);
    }
  }


  /**
   * Information about a highlight being painted by this highlighter.
   */
  public static interface HighlightInfo extends Highlighter.Highlight {}


  /**
   * Information about a layered highlight being painted by this highlighter.
   */
  public static interface LayeredHighlightInfo extends HighlightInfo {

    /**
     * Restricts the region based on the receivers offsets and messages
     * the painter to paint the region.
     */
    void paintLayeredHighlights(Graphics g, int p0, int p1,
          Shape viewBounds, JTextComponent editor, View view);

  }


  /**
   * A straightforward implementation of <code>HighlightInfo</code>.
   */
  protected static class HighlightInfoImpl implements HighlightInfo {
 
    private Position p0;
    private Position p1;
    private Highlighter.HighlightPainter painter;

    /** To be extended by subclasses. */
    public Color getColor() {
      return null;
    }

    public int getStartOffset() {
      return p0.getOffset();
    }
   
    public int getEndOffset() {
      return p1.getOffset();
    }
   
    public Highlighter.HighlightPainter getPainter() {
      return painter;
    }

    public void setStartOffset(Position startOffset) {
      this.p0 = startOffset;
    }

    public void setEndOffset(Position endOffset) {
      this.p1 = endOffset;
    }

    public void setPainter(Highlighter.HighlightPainter painter) {
      this.painter = painter;
    }
   
  }


  /**
   * A straightforward implementation of <code>HighlightInfo</code> for
   * painting layered highlights.
   */
  /*
   * NOTE: This implementation is a "hack" so typing at the "end" of the highlight
   * does not extend it to include the newly-typed chars, which is the standard
   * behavior of Swing Highlights.  It assumes that the "p1" Position set is
   * actually 1 char too short, and will render the selection as if that "extra"
   * char should be highlighted.
   */
  protected static class LayeredHighlightInfoImpl extends HighlightInfoImpl
      implements LayeredHighlightInfo {
 
    public int x;
    public int y;
    public int width;
    public int height;

    void union(Shape bounds) {
      if (bounds == null) {
        return;
      }
      Rectangle alloc = (bounds instanceof Rectangle) ?
          (Rectangle)bounds : bounds.getBounds();
      if (width == 0 || height == 0) {
        x = alloc.x;
        y = alloc.y;
        width = alloc.width;
        height = alloc.height;
      }
      else {
        width = Math.max(x + width, alloc.x + alloc.width);
        height = Math.max(y + height, alloc.y + alloc.height);
        x = Math.min(x, alloc.x);
        width -= x;
        y = Math.min(y, alloc.y);
        height -= y;
      }
    }
 
    /**
     * {@inheritDoc}
     */
    public void paintLayeredHighlights(Graphics g, int p0, int p1,
                  Shape viewBounds, JTextComponent editor,
                  View view) {
      int start = getStartOffset();
      int end = getEndOffset();
      end++; // Workaround for Java highlight issues
      // Restrict the region to what we represent
      p0 = Math.max(start, p0);
      p1 = Math.min(end, p1);
      if (getColor()!=null &&
          (getPainter() instanceof ChangeableHighlightPainter)) {
        ((ChangeableHighlightPainter)getPainter()).setPaint(getColor());
      }
      // Paint the appropriate region using the painter and union
      // the effected region with our bounds.
      union(((LayeredHighlighter.LayerPainter)getPainter()).paintLayer
                (g, p0, p1, viewBounds, editor, view));
    }
 
  }
 
 
}
TOP

Related Classes of org.fife.ui.rtextarea.RTextAreaHighlighter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.