Package org.fife.ui.rtextarea

Source Code of org.fife.ui.rtextarea.IconRowHeader$GutterIconImpl

/*
* 02/17/2009
*
* IconRowHeader.java - Renders icons in the gutter.
*
* 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.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JPanel;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.Position;
import javax.swing.text.View;

import org.fife.ui.rsyntaxtextarea.FoldingAwareIconRowHeader;


/**
* Renders icons in the {@link Gutter}.  This can be used to visually mark
* lines containing syntax errors, lines with breakpoints set on them, etc.<p>
*
* This component has built-in support for displaying icons representing
* "bookmarks;" that is, lines a user can cycle through via F2 and Shift+F2.
* Bookmarked lines are toggled via Ctrl+F2, or by clicking in the icon area
* at the line to bookmark.  In order to enable bookmarking, you must first
* assign an icon to represent a bookmarked line, then actually enable the
* feature.  This is actually done on the parent {@link Gutter} component:<p>
*
* <pre>
* Gutter gutter = scrollPane.getGutter();
* gutter.setBookmarkIcon(new ImageIcon("bookmark.png"));
* gutter.setBookmarkingEnabled(true);
* </pre>
*
* @author Robert Futrell
* @version 1.0
* @see FoldingAwareIconRowHeader
*/
public class IconRowHeader extends AbstractGutterComponent implements MouseListener {

  /**
   * The icons to render.
   */
  protected List<GutterIconImpl> trackingIcons;

  /**
   * The width of this component.
   */
  protected int width;

  /**
   * Whether this component listens for mouse clicks and toggles "bookmark"
   * icons on them.
   */
  private boolean bookmarkingEnabled;

  /**
   * The icon to use for bookmarks.
   */
  private Icon bookmarkIcon;

  /**
   * Used in {@link #paintComponent(Graphics)} to prevent reallocation on
   * each paint.
   */
  protected Rectangle visibleRect;

  /**
   * Used in {@link #paintComponent(Graphics)} to prevent reallocation on
   * each paint.
   */
  protected Insets textAreaInsets;

  /**
   * The first line in the active line range.
   */
  protected int activeLineRangeStart;

  /**
   * The end line in the active line range.
   */
  protected int activeLineRangeEnd;

  /**
   * The color used to highlight the active code block.
   */
  private Color activeLineRangeColor;

  /**
   * Whether this component should use the gutter's background color (as
   * opposed to using a LookAndFeel-dependent color, which is the default
   * behavior).
   */
  private boolean inheritsGutterBackground;


  /**
   * Constructor.
   *
   * @param textArea The parent text area.
   */
  public IconRowHeader(RTextArea textArea) {
    super(textArea);
  }


  /**
   * Adds an icon that tracks an offset in the document, and is displayed
   * adjacent to the line numbers.  This is useful for marking things such
   * as source code errors.
   *
   * @param offs The offset to track.
   * @param icon The icon to display.  This should be small (say 16x16).
   * @return A tag for this icon.
   * @throws BadLocationException If <code>offs</code> is an invalid offset
   *         into the text area.
   * @see #removeTrackingIcon(Object)
   */
  public GutterIconInfo addOffsetTrackingIcon(int offs, Icon icon)
                        throws BadLocationException {
    return addOffsetTrackingIcon(offs, icon, null);
  }


  /**
   * Adds an icon that tracks an offset in the document, and is displayed
   * adjacent to the line numbers.  This is useful for marking things such
   * as source code errors.
   *
   * @param offs The offset to track.
   * @param icon The icon to display.  This should be small (say 16x16).
   * @param tip A tool tip for the icon.
   * @return A tag for this icon.
   * @throws BadLocationException If <code>offs</code> is an invalid offset
   *         into the text area.
   * @see #removeTrackingIcon(Object)
   */
  public GutterIconInfo addOffsetTrackingIcon(int offs, Icon icon, String tip)
                        throws BadLocationException {
    Position pos = textArea.getDocument().createPosition(offs);
    GutterIconImpl ti = new GutterIconImpl(icon, pos, tip);
    if (trackingIcons==null) {
      trackingIcons = new ArrayList<GutterIconImpl>(1); // Usually small
    }
    int index = Collections.binarySearch(trackingIcons, ti);
    if (index<0) {
      index = -(index+1);
    }
    trackingIcons.add(index, ti);
    repaint();
    return ti;
  }


  /**
   * Clears the active line range.
   *
   * @see #setActiveLineRange(int, int)
   */
  public void clearActiveLineRange() {
    if (activeLineRangeStart!=-1 || activeLineRangeEnd!=-1) {
      activeLineRangeStart = activeLineRangeEnd = -1;
      repaint();
    }
  }


  /**
   * Returns the color used to paint the active line range, if any.
   *
   * @return The color.
   * @see #setActiveLineRangeColor(Color)
   */
  public Color getActiveLineRangeColor() {
    return activeLineRangeColor;
  }


  /**
   * Returns the icon to use for bookmarks.
   *
   * @return The icon to use for bookmarks.  If this is <code>null</code>,
   *         bookmarking is effectively disabled.
   * @see #setBookmarkIcon(Icon)
   * @see #isBookmarkingEnabled()
   */
  public Icon getBookmarkIcon() {
    return bookmarkIcon;
  }


  /**
   * Returns the bookmarks known to this gutter.
   *
   * @return The bookmarks.  If there are no bookmarks, an empty array is
   *         returned.
   */
  public GutterIconInfo[] getBookmarks() {

    List<GutterIconInfo> retVal = new ArrayList<GutterIconInfo>(1);

    if (trackingIcons!=null) {
      for (int i=0; i<trackingIcons.size(); i++) {
        GutterIconImpl ti = getTrackingIcon(i);
        if (ti.getIcon()==bookmarkIcon) {
          retVal.add(ti);
        }
      }
    }

    GutterIconInfo[] array = new GutterIconInfo[retVal.size()];
    return retVal.toArray(array);

  }


  /**
   * {@inheritDoc}
   */
  @Override
  void handleDocumentEvent(DocumentEvent e) {
    int newLineCount = textArea.getLineCount();
    if (newLineCount!=currentLineCount) {
      currentLineCount = newLineCount;
      repaint();
    }
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public Dimension getPreferredSize() {
    int h = textArea!=null ? textArea.getHeight() : 100; // Arbitrary
    return new Dimension(width, h);
  }


  /**
   * Overridden to display the tool tip of any icons on this line.
   *
   * @param e The location the mouse is hovering over.
   */
  @Override
  public String getToolTipText(MouseEvent e) {
    try {
      int line = viewToModelLine(e.getPoint());
      if (line>-1) {
        GutterIconInfo[] infos = getTrackingIcons(line);
        if (infos.length>0) {
          // TODO: Display all messages?
          return infos[infos.length-1].getToolTip();
        }
      }
    } catch (BadLocationException ble) {
      ble.printStackTrace(); // Never happens
    }
    return null;
  }


  protected GutterIconImpl getTrackingIcon(int index) {
    return trackingIcons.get(index);
  }


  /**
   * Returns the tracking icons at the specified line.
   *
   * @param line The line.
   * @return The tracking icons at that line.  If there are no tracking
   *         icons there, this will be an empty array.
   * @throws BadLocationException If <code>line</code> is invalid.
   */
  public GutterIconInfo[] getTrackingIcons(int line)
                throws BadLocationException {

    List<GutterIconInfo> retVal = new ArrayList<GutterIconInfo>(1);

    if (trackingIcons!=null) {
      int start = textArea.getLineStartOffset(line);
      int end = textArea.getLineEndOffset(line);
      if (line==textArea.getLineCount()-1) {
        end++; // Hack
      }
      for (int i=0; i<trackingIcons.size(); i++) {
        GutterIconImpl ti = getTrackingIcon(i);
        int offs = ti.getMarkedOffset();
        if (offs>=start && offs<end) {
          retVal.add(ti);
        }
        else if (offs>=end) {
          break; // Quit early
        }
      }
    }

    GutterIconInfo[] array = new GutterIconInfo[retVal.size()];
    return retVal.toArray(array);

  }


  @Override
  protected void init() {

    super.init();

    visibleRect = new Rectangle();
    width = 16;
    addMouseListener(this);
    activeLineRangeStart = activeLineRangeEnd = -1;
    setActiveLineRangeColor(null);

    // Must explicitly set our background color, otherwise we inherit that
    // of the parent Gutter.
    updateBackground();

    ToolTipManager.sharedInstance().registerComponent(this);

  }


  /**
   * Returns whether bookmarking is enabled.
   *
   * @return Whether bookmarking is enabled.
   * @see #setBookmarkingEnabled(boolean)
   */
  public boolean isBookmarkingEnabled() {
    return bookmarkingEnabled;
  }


  /**
   * {@inheritDoc}
   */
  @Override
  void lineHeightsChanged() {
    repaint();
  }


  public void mouseClicked(MouseEvent e) {
  }


  public void mouseEntered(MouseEvent e) {
  }


  public void mouseExited(MouseEvent e) {
  }


  public void mousePressed(MouseEvent e) {
    if (bookmarkingEnabled && bookmarkIcon!=null) {
      try {
        int line = viewToModelLine(e.getPoint());
        if (line>-1) {
          toggleBookmark(line);
        }
      } catch (BadLocationException ble) {
        ble.printStackTrace(); // Never happens
      }
    }
  }


  public void mouseReleased(MouseEvent e) {
  }


  /**
   * {@inheritDoc}
   */
  @Override
  protected void paintComponent(Graphics g) {

    if (textArea==null) {
      return;
    }

    visibleRect = g.getClipBounds(visibleRect);
    if (visibleRect==null) { // ???
      visibleRect = getVisibleRect();
    }
    //System.out.println("IconRowHeader repainting: " + visibleRect);
    if (visibleRect==null) {
      return;
    }
    paintBackgroundImpl(g, visibleRect);

    if (textArea.getLineWrap()) {
      paintComponentWrapped(g);
      return;
    }

    Document doc = textArea.getDocument();
    Element root = doc.getDefaultRootElement();
    textAreaInsets = textArea.getInsets(textAreaInsets);
    if (visibleRect.y<textAreaInsets.top) {
      visibleRect.height -= (textAreaInsets.top - visibleRect.y);
      visibleRect.y = textAreaInsets.top;
    }

    // Get the first and last lines to paint.
    int cellHeight = textArea.getLineHeight();
    int topLine = (visibleRect.y-textAreaInsets.top)/cellHeight;
    int bottomLine = Math.min(topLine+visibleRect.height/cellHeight+1,
              root.getElementCount());

    // Get where to start painting (top of the row).
    // We need to be "scrolled up" up just enough for the missing part of
    // the first line.
    int y = topLine*cellHeight + textAreaInsets.top;

    if ((activeLineRangeStart>=topLine&&activeLineRangeStart<=bottomLine) ||
      (activeLineRangeEnd>=topLine && activeLineRangeEnd<=bottomLine) ||
      (activeLineRangeStart<=topLine && activeLineRangeEnd>=bottomLine)) {

      g.setColor(activeLineRangeColor);
      int firstLine = Math.max(activeLineRangeStart, topLine);
      int y1 = firstLine * cellHeight + textAreaInsets.top;
      int lastLine = Math.min(activeLineRangeEnd, bottomLine);
      int y2 = (lastLine+1) * cellHeight + textAreaInsets.top - 1;

      int j = y1;
      while (j<=y2) {
        int yEnd = Math.min(y2, j+getWidth());
        int xEnd = yEnd-j;
        g.drawLine(0,j, xEnd,yEnd);
        j += 2;
      }

      int i = 2;
      while (i<getWidth()) {
        int yEnd = y1 + getWidth() - i;
        g.drawLine(i,y1, getWidth(),yEnd);
        i += 2;
      }

      if (firstLine==activeLineRangeStart) {
        g.drawLine(0,y1, getWidth(),y1);
      }
      if (lastLine==activeLineRangeEnd) {
        g.drawLine(0,y2, getWidth(),y2);
      }

    }

    if (trackingIcons!=null) {
      int lastLine = bottomLine;
      for (int i=trackingIcons.size()-1; i>=0; i--) { // Last to first
        GutterIconInfo ti = getTrackingIcon(i);
        int offs = ti.getMarkedOffset();
        if (offs>=0 && offs<=doc.getLength()) {
          int line = root.getElementIndex(offs);
          if (line<=lastLine && line>=topLine) {
            Icon icon = ti.getIcon();
            if (icon!=null) {
              int y2 = y + (line-topLine)*cellHeight;
              y2 += (cellHeight-icon.getIconHeight())/2;
              ti.getIcon().paintIcon(this, g, 0, y2);
              lastLine = line-1; // Paint only 1 icon per line
            }
          }
          else if (line<topLine) {
            break;
          }
        }
      }
    }

  }


  /**
   * Paints the background of this component.
   *
   * @param g The graphics context.
   * @param visibleRect The visible bounds of this component.
   */
  protected void paintBackgroundImpl(Graphics g, Rectangle visibleRect) {
    Color bg = getBackground();
    if (inheritsGutterBackground && getGutter()!=null) {
      bg = getGutter().getBackground();
    }
    g.setColor(bg);
    g.fillRect(0,visibleRect.y, width,visibleRect.height);
  }


  /**
   * Paints icons when line wrapping is enabled.
   *
   * @param g The graphics context.
   */
  private void paintComponentWrapped(Graphics g) {

    // The variables we use are as follows:
    // - visibleRect is the "visible" area of the text area; e.g.
    // [0,100, 300,100+(lineCount*cellHeight)-1].
    // actualTop.y is the topmost-pixel in the first logical line we
    // paint.  Note that we may well not paint this part of the logical
    // line, as it may be broken into many physical lines, with the first
    // few physical lines scrolled past.  Note also that this is NOT the
    // visible rect of this line number list; this line number list has
    // visible rect == [0,0, insets.left-1,visibleRect.height-1].
    // - offset (<=0) is the y-coordinate at which we begin painting when
    // we begin painting with the first logical line.  This can be
    // negative, signifying that we've scrolled past the actual topmost
    // part of this line.

    // The algorithm is as follows:
    // - Get the starting y-coordinate at which to paint.  This may be
    //   above the first visible y-coordinate as we're in line-wrapping
    //   mode, but we always paint entire logical lines.
    // - Paint that line's line number and highlight, if appropriate.
    //   Increment y to be just below the are we just painted (i.e., the
    //   beginning of the next logical line's view area).
    // - Get the ending visual position for that line.  We can now loop
    //   back, paint this line, and continue until our y-coordinate is
    //   past the last visible y-value.

    // We avoid using modelToView/viewToModel where possible, as these
    // methods trigger a parsing of the line into syntax tokens, which is
    // costly.  It's cheaper to just grab the child views' bounds.

    RTextAreaUI ui = (RTextAreaUI)textArea.getUI();
    View v = ui.getRootView(textArea).getView(0);
//    boolean currentLineHighlighted = textArea.getHighlightCurrentLine();
    Document doc = textArea.getDocument();
    Element root = doc.getDefaultRootElement();
    int lineCount = root.getElementCount();
    int topPosition = textArea.viewToModel(
                new Point(visibleRect.x,visibleRect.y));
    int topLine = root.getElementIndex(topPosition);

    // Compute the y at which to begin painting text, taking into account
    // that 1 logical line => at least 1 physical line, so it may be that
    // y<0.  The computed y-value is the y-value of the top of the first
    // (possibly) partially-visible view.
    Rectangle visibleEditorRect = ui.getVisibleEditorRect();
    Rectangle r = IconRowHeader.getChildViewBounds(v, topLine,
                        visibleEditorRect);
    int y = r.y;

    int visibleBottom = visibleRect.y + visibleRect.height;

    // Get the first possibly visible icon index.
    int currentIcon = -1;
    if (trackingIcons!=null) {
      for (int i=0; i<trackingIcons.size(); i++) {
        GutterIconImpl icon = getTrackingIcon(i);
        int offs = icon.getMarkedOffset();
        if (offs>=0 && offs<=doc.getLength()) {
          int line = root.getElementIndex(offs);
          if (line>=topLine) {
            currentIcon = i;
            break;
          }
        }
      }
    }

    // Keep painting lines until our y-coordinate is past the visible
    // end of the text area.
    g.setColor(getForeground());
    int cellHeight = textArea.getLineHeight();
    while (y < visibleBottom) {

      r = getChildViewBounds(v, topLine, visibleEditorRect);
//      int lineEndY = r.y+r.height;

      /*
      // Highlight the current line's line number, if desired.
      if (currentLineHighlighted && topLine==currentLine) {
        g.setColor(textArea.getCurrentLineHighlightColor());
        g.fillRect(0,y, width,lineEndY-y);
        g.setColor(getForeground());
      }
      */

      // Possibly paint an icon.
      if (currentIcon>-1) {
        // We want to paint the last icon added for this line.
        GutterIconImpl toPaint = null;
        while (currentIcon<trackingIcons.size()) {
          GutterIconImpl ti = getTrackingIcon(currentIcon);
          int offs = ti.getMarkedOffset();
          if (offs>=0 && offs<=doc.getLength()) {
            int line = root.getElementIndex(offs);
            if (line==topLine) {
              toPaint = ti;
            }
            else if (line>topLine) {
              break;
            }
          }
          currentIcon++;
        }
        if (toPaint!=null) {
          Icon icon = toPaint.getIcon();
          if (icon!=null) {
            int y2 = y + (cellHeight-icon.getIconHeight())/2;
            icon.paintIcon(this, g, 0, y2);
          }
        }
      }

      // The next possible y-coordinate is just after the last line
      // painted.
      y += r.height;

      // Update topLine (we're actually using it for our "current line"
      // variable now).
      topLine++;
      if (topLine>=lineCount)
        break;

    }

  }


  /**
   * Removes the specified tracking icon.
   *
   * @param tag A tag for a tracking icon.
   * @see #removeAllTrackingIcons()
   * @see #addOffsetTrackingIcon(int, Icon)
   */
  public void removeTrackingIcon(Object tag) {
    if (trackingIcons!=null && trackingIcons.remove(tag)) {
      repaint();
    }
  }


  /**
   * Removes all tracking icons.
   *
   * @see #removeTrackingIcon(Object)
   * @see #addOffsetTrackingIcon(int, Icon)
   */
  public void removeAllTrackingIcons() {
    if (trackingIcons!=null && trackingIcons.size()>0) {
      trackingIcons.clear();
      repaint();
    }
  }


  /**
   * Removes all bookmark tracking icons.
   */
  private void removeBookmarkTrackingIcons() {
    if (trackingIcons!=null) {
      for (Iterator<GutterIconImpl> i=trackingIcons.iterator();
          i.hasNext(); ) {
        GutterIconImpl ti = i.next();
        if (ti.getIcon()==bookmarkIcon) {
          i.remove();
        }
      }
    }
  }


  /**
   * Highlights a range of lines in the icon area.
   *
   * @param startLine The start of the line range.
   * @param endLine The end of the line range.
   * @see #clearActiveLineRange()
   */
  public void setActiveLineRange(int startLine, int endLine) {
    if (startLine!=activeLineRangeStart ||
        endLine!=activeLineRangeEnd) {
      activeLineRangeStart = startLine;
      activeLineRangeEnd = endLine;
      repaint();
    }
  }


  /**
   * Sets the color to use to render active line ranges.
   *
   * @param color The color to use.  If this is null, then the default
   *        color is used.
   * @see #getActiveLineRangeColor()
   * @see Gutter#DEFAULT_ACTIVE_LINE_RANGE_COLOR
   */
  public void setActiveLineRangeColor(Color color) {
    if (color==null) {
      color = Gutter.DEFAULT_ACTIVE_LINE_RANGE_COLOR;
    }
    if (!color.equals(activeLineRangeColor)) {
      activeLineRangeColor = color;
      repaint();
    }
  }


  /**
   * Sets the icon to use for bookmarks.  Any previous bookmark icons
   * are removed.
   *
   * @param icon The new bookmark icon.  If this is <code>null</code>,
   *        bookmarking is effectively disabled.
   * @see #getBookmarkIcon()
   * @see #isBookmarkingEnabled()
   */
  public void setBookmarkIcon(Icon icon) {
    removeBookmarkTrackingIcons();
    bookmarkIcon = icon;
    repaint();
  }


  /**
   * Sets whether bookmarking is enabled.  Note that a bookmarking icon
   * must be set via {@link #setBookmarkIcon(Icon)} before bookmarks are
   * truly enabled.
   *
   * @param enabled Whether bookmarking is enabled.  If this is
   *        <code>false</code>, any bookmark icons are removed.
   * @see #isBookmarkingEnabled()
   * @see #setBookmarkIcon(Icon)
   */
  public void setBookmarkingEnabled(boolean enabled) {
    if (enabled!=bookmarkingEnabled) {
      bookmarkingEnabled = enabled;
      if (!enabled) {
        removeBookmarkTrackingIcons();
      }
      repaint();
    }
  }


  /**
   * Sets whether the icon area inherits the gutter background (as opposed
   * to painting with its own, default "panel" color, which is the default).
   *
   * @param inherits Whether the gutter background should be used in the icon
   *        row header.  If this is <code>false</code>, a default,
   *        Look-and-feel-dependent color is used.
   */
  public void setInheritsGutterBackground(boolean inherits) {
    if (inherits!=inheritsGutterBackground) {
      inheritsGutterBackground = inherits;
      repaint();
    }
  }


  /**
   * Sets the text area being displayed.  This will clear any tracking
   * icons currently displayed.
   *
   * @param textArea The text area.
   */
  @Override
  public void setTextArea(RTextArea textArea) {
    removeAllTrackingIcons();
    super.setTextArea(textArea);
  }


  /**
   * Programatically toggles whether there is a bookmark for the specified
   * line.  If bookmarking is not enabled, this method does nothing.
   *
   * @param line The line.
   * @return Whether a bookmark is now at the specified line.
   * @throws BadLocationException If <code>line</code> is an invalid line
   *         number in the text area.
   */
  public boolean toggleBookmark(int line) throws BadLocationException {

    if (!isBookmarkingEnabled() || getBookmarkIcon()==null) {
      return false;
    }

    GutterIconInfo[] icons = getTrackingIcons(line);
    if (icons.length==0) {
      int offs = textArea.getLineStartOffset(line);
      addOffsetTrackingIcon(offs, bookmarkIcon);
      return true;
    }

    boolean found = false;
    for (int i=0; i<icons.length; i++) {
      if (icons[i].getIcon()==bookmarkIcon) {
        removeTrackingIcon(icons[i]);
        found = true;
        // Don't quit, in case they manipulate the document so > 1
        // bookmark is on a single line (kind of flaky, but it
        // works...).  If they delete all chars in the document,
        // AbstractDocument gets a little flaky with the returned line
        // number for viewToModel(), so this is just us trying to save
        // face a little.
      }
    }
    if (!found) {
      int offs = textArea.getLineStartOffset(line);
      addOffsetTrackingIcon(offs, bookmarkIcon);
    }

    return !found;

  }


  /**
   * Sets our background color to that of standard "panels" in this
   * LookAndFeel.  This is necessary because, otherwise, we'd inherit the
   * background color of our parent component (the Gutter).
   */
  private void updateBackground() {
    Color bg = UIManager.getColor("Panel.background");
    if (bg==null) { // UIManager properties aren't guaranteed to exist
      bg = new JPanel().getBackground();
    }
    setBackground(bg);
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public void updateUI() {
    super.updateUI(); // Does nothing
    updateBackground();
  }


  /**
   * Returns the line rendered at the specified location.
   *
   * @param p The location in this row header.
   * @return The corresponding line in the editor.
   * @throws BadLocationException ble If an error occurs.
   */
  private int viewToModelLine(Point p) throws BadLocationException {
    int offs = textArea.viewToModel(p);
    return offs>-1 ? textArea.getLineOfOffset(offs) : -1;
  }


  /**
   * Implementation of the icons rendered.
   */
  private static class GutterIconImpl implements GutterIconInfo,
      Comparable<GutterIconInfo> {

    private Icon icon;
    private Position pos;
    private String toolTip;

    public GutterIconImpl(Icon icon, Position pos, String toolTip) {
      this.icon = icon;
      this.pos = pos;
      this.toolTip = toolTip;
    }

    public int compareTo(GutterIconInfo other) {
      if (other!=null) {
        return pos.getOffset() - other.getMarkedOffset();
      }
      return -1;
    }

    @Override
    public boolean equals(Object o) {
      return o==this;
    }

    public Icon getIcon() {
      return icon;
    }

    public int getMarkedOffset() {
      return pos.getOffset();
    }

    public String getToolTip() {
      return toolTip;
    }

    @Override
    public int hashCode() {
      return icon.hashCode(); // FindBugs
    }

  }


}
TOP

Related Classes of org.fife.ui.rtextarea.IconRowHeader$GutterIconImpl

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.