Package processing.mode.experimental

Source Code of processing.mode.experimental.TextAreaPainter

/*
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package processing.mode.experimental;
import static processing.mode.experimental.ExperimentalMode.log;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.text.BadLocationException;
import javax.swing.text.Segment;
import javax.swing.text.Utilities;

import processing.app.syntax.TextAreaDefaults;
import processing.app.syntax.TokenMarker;

/**
* Customized line painter. Adds support for background colors, left hand gutter
* area with background color and text.
*
* @author Martin Leopold <m@martinleopold.com>
*/
public class TextAreaPainter extends processing.app.syntax.TextAreaPainter {

  protected TextArea ta; // we need the subclassed textarea

  protected ErrorCheckerService errorCheckerService;

  /**
   * Error line underline color
   */
  public Color errorColor = new Color(0xED2630);

  /**
   * Warning line underline color
   */

  public Color warningColor = new Color(0xFFC30E);

  /**
   * Color of Error Marker
   */
  public Color errorMarkerColor = new Color(0xED2630);

  /**
   * Color of Warning Marker
   */
  public Color warningMarkerColor = new Color(0xFFC30E);

  static int ctrlMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();

  public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) {
    super(textArea, defaults);
    ta = textArea;
    addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent evt) {
//            log( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask));
        if (evt.getButton() == MouseEvent.BUTTON1) {
          if (evt.isControlDown() || evt.isMetaDown())
            handleCtrlClick(evt);
        }
      }
    });

  }

//    public void processKeyEvent(KeyEvent evt) {
//      log(evt);
//    }

  void handleCtrlClick(MouseEvent evt) {
    log("--handleCtrlClick--");
    int off = ta.xyToOffset(evt.getX(), evt.getY());
    if (off < 0)
      return;
    int line = ta.getLineOfOffset(off);
    if (line < 0)
      return;
    String s = ta.getLineText(line);
    if (s == null)
      return;
    else if (s.length() == 0)
      return;
    else {
      int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1;
      log("x="+x);
      int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line);
      if (x < 0 || x >= s.length())
        return;
      String word = s.charAt(x) + "";
      if (s.charAt(x) == ' ')
        return;
      if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s
          .charAt(x) == '$'))
        return;
      int i = 0;
      while (true) {
        i++;
        if (x1 >= 0 && x1 < s.length()) {
          if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') {
            word = s.charAt(x1--) + word;
            xLS--;
          } else
            x1 = -1;
        } else
          x1 = -1;

        if (x2 >= 0 && x2 < s.length()) {
          if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_'
              || s.charAt(x2) == '$')
            word = word + s.charAt(x2++);
          else
            x2 = -1;
        } else
          x2 = -1;

        if (x1 < 0 && x2 < 0)
          break;
        if (i > 200) {
          // time out!
          // System.err.println("Whoopsy! :P");
          break;
        }
      }
      if (Character.isDigit(word.charAt(0)))
        return;
     
      log(errorCheckerService.mainClassOffset + line +
      "|" + line + "| offset " + xLS + word + " <= \n");
      errorCheckerService.getASTGenerator()
          .scrollToDeclaration(line, word, xLS);
    }
  }

  private void loadTheme(ExperimentalMode mode) {
    errorColor = mode.getThemeColor("editor.errorcolor", errorColor);
    warningColor = mode.getThemeColor("editor.warningcolor", warningColor);
    errorMarkerColor = mode.getThemeColor("editor.errormarkercolor",
                                          errorMarkerColor);
    warningMarkerColor = mode.getThemeColor("editor.warningmarkercolor",
                                            warningMarkerColor);
  }

  /**
   * Paint a line. Paints the gutter (with background color and text) then the
   * line (background color and text).
   *
   * @param gfx
   *          the graphics context
   * @param tokenMarker
   * @param line
   *          0-based line number
   * @param x
   *          horizontal position
   */
  @Override
  protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line,
                           int x) {
    try {
      //TODO: This line is causing NPE's randomly ever since I added the toggle for
      //Java Mode/Debugger toolbar.
      super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth());
    } catch (Exception e) {
      log(e.getMessage());
    }
    if(ta.editor.debugToolbarEnabled != null && ta.editor.debugToolbarEnabled.get()){
      // paint gutter
      paintGutterBg(gfx, line, x);
 
      // disabled line background after P5 2.1, since it adds highlight by default
      //paintLineBgColor(gfx, line, x + ta.getGutterWidth());
 
      paintGutterLine(gfx, line, x);
 
      // paint gutter symbol
      paintGutterText(gfx, line, x);
     
    }  
    paintErrorLine(gfx, line, x);
  }

  /**
   * Paint the gutter background (solid color).
   *
   * @param gfx
   *          the graphics context
   * @param line
   *          0-based line number
   * @param x
   *          horizontal position
   */
  protected void paintGutterBg(Graphics gfx, int line, int x) {
    gfx.setColor(ta.gutterBgColor);
    int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent();
    gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight());
  }

  /**
   * Paint the vertical gutter separator line.
   *
   * @param gfx
   *          the graphics context
   * @param line
   *          0-based line number
   * @param x
   *          horizontal position
   */
  protected void paintGutterLine(Graphics gfx, int line, int x) {
    int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent();
    gfx.setColor(ta.gutterLineColor);
    gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(),
                 y + fm.getHeight());
  }

  /**
   * Paint the gutter text.
   *
   * @param gfx
   *          the graphics context
   * @param line
   *          0-based line number
   * @param x
   *          horizontal position
   */
  protected void paintGutterText(Graphics gfx, int line, int x) {
    String text = ta.getGutterText(line);
    if (text == null) {
      return;
    }

    gfx.setFont(getFont());
    Color textColor = ta.getGutterTextColor(line);
    if (textColor == null) {
      gfx.setColor(getForeground());
    } else {
      gfx.setColor(textColor);
    }
    int y = ta.lineToY(line) + fm.getHeight();

    // draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right.
    //int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length();
    Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()),
                             ta.getGutterMargins(), y, gfx, this, 0);
    Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()),
                             ta.getGutterMargins() + 1, y, gfx, this, 0);
    Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()),
                             ta.getGutterMargins(), y + 1, gfx, this, 0);
    Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()),
                             ta.getGutterMargins() + 1, y + 1, gfx, this, 0);
  }

  /**
   * Paint the background color of a line.
   *
   * @param gfx
   *          the graphics context
   * @param line
   *          0-based line number
   * @param x
   */
  protected void paintLineBgColor(Graphics gfx, int line, int x) {
    int y = ta.lineToY(line);
    y += fm.getLeading() + fm.getMaxDescent();
    int height = fm.getHeight();

    // get the color
    Color col = ta.getLineBgColor(line);
    //System.out.print("bg line " + line + ": ");
    // no need to paint anything
    if (col == null) {
      //log("none");
      return;
    }
    // paint line background
    gfx.setColor(col);
    gfx.fillRect(0, y, getWidth(), height);
  }

  /**
   * Paints the underline for an error/warning line
   *
   * @param gfx
   *          the graphics context
   * @param tokenMarker
   * @param line
   *          0-based line number: NOTE
   * @param x
   */
  protected void paintErrorLine(Graphics gfx, int line, int x) {
    if (errorCheckerService == null) {
      return;
    }

    if (errorCheckerService.problemsList == null) {
      return;
    }

    boolean notFound = true;
    boolean isWarning = false;
    Problem problem = null;
   
    // Check if current line contains an error. If it does, find if it's an
    // error or warning
    for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) {
      if (emarker.getProblem().getLineNumber() == line) {
        notFound = false;
        if (emarker.getType() == ErrorMarker.Warning) {
          isWarning = true;
        }
        problem = emarker.getProblem();
        //log(problem.toString());
        break;
      }
    }

    if (notFound) {
      return;
    }

    // Determine co-ordinates
    // log("Hoff " + ta.getHorizontalOffset() + ", " +
    // horizontalAdjustment);
    int y = ta.lineToY(line);
    y += fm.getLeading() + fm.getMaxDescent();
    int height = fm.getHeight();
    int start = ta.getLineStartOffset(line) + problem.getPDELineStartOffset();
    int pLength = problem.getPDELineStopOffset() + 1
        - problem.getPDELineStartOffset();
   
    try {
      String badCode = null;
      String goodCode = null;
      try {
        badCode = ta.getDocument().getText(start, pLength);
        goodCode = ta.getDocument().getText(ta.getLineStartOffset(line),
                                            problem.getPDELineStartOffset());
        //log("paintErrorLine() LineText GC: " + goodCode);
        //log("paintErrorLine() LineText BC: " + badCode);
      } catch (BadLocationException bl) {
        // Error in the import statements or end of code.
        // System.out.print("BL caught. " + ta.getLineCount() + " ,"
        // + line + " ,");
        // log((ta.getLineStopOffset(line) - start - 1));
        return;
      }

      // Take care of offsets
      int aw = fm.stringWidth(trimRight(badCode)) + ta.getHorizontalOffset(); // apparent width. Whitespaces
      // to the left of line + text
      // width
      int rw = fm.stringWidth(badCode.trim()); // real width
      int x1 = fm.stringWidth(goodCode) + (aw - rw), y1 = y + fm.getHeight()
          - 2, x2 = x1 + rw;
      // Adding offsets for the gutter
      x1 += ta.getGutterWidth();
      x2 += ta.getGutterWidth();

      // gfx.fillRect(x1, y, rw, height);

      // Let the painting begin!
     
      // Little rect at starting of a line containing errors - disabling it for now
//      gfx.setColor(errorMarkerColor);
//      if (isWarning) {
//        gfx.setColor(warningMarkerColor);
//      }
//      gfx.fillRect(1, y + 2, 3, height - 2);

     
      gfx.setColor(errorColor);
      if (isWarning) {
        gfx.setColor(warningColor);
      }
      int xx = x1;

      // Draw the jagged lines
      while (xx < x2) {
        gfx.drawLine(xx, y1, xx + 2, y1 + 1);
        xx += 2;
        gfx.drawLine(xx, y1 + 1, xx + 2, y1);
        xx += 2;
      }
    } catch (Exception e) {
      System.out
          .println("Looks like I messed up! XQTextAreaPainter.paintLine() : "
              + e);
      //e.printStackTrace();
    }

    // Won't highlight the line. Select the text instead.
    // gfx.setColor(Color.RED);
    // gfx.fillRect(2, y, 3, height);
  }

  /**
   * Trims out trailing whitespaces (to the right)
   *
   * @param string
   * @return - String
   */
  private String trimRight(String string) {
    String newString = "";
    for (int i = 0; i < string.length(); i++) {
      if (string.charAt(i) != ' ') {
        newString = string.substring(0, i) + string.trim();
        break;
      }
    }
    return newString;
  }

  /**
   * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode)
   *
   * @param ecs
   * @param mode
   */
  public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode) {
    this.errorCheckerService = ecs;
    loadTheme(mode);
  }

  public String getToolTipText(java.awt.event.MouseEvent evt) {
    int off = ta.xyToOffset(evt.getX(), evt.getY());
    if (off < 0)
      return null;
    int line = ta.getLineOfOffset(off);
    if (line < 0)
      return null;
    String s = ta.getLineText(line);
    if (s == null)
      return evt.toString();
    else if (s.length() == 0)
      return null;
    else {
      int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1;
      int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line);
      if (x < 0 || x >= s.length())
        return null;
      String word = s.charAt(x) + "";
      if (s.charAt(x) == ' ')
        return null;
      if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s
          .charAt(x) == '$'))
        return null;
      int i = 0;
      while (true) {
        i++;
        if (x1 >= 0 && x1 < s.length()) {
          if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') {
            word = s.charAt(x1--) + word;
            xLS--;
          } else
            x1 = -1;
        } else
          x1 = -1;

        if (x2 >= 0 && x2 < s.length()) {
          if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_'
              || s.charAt(x2) == '$')
            word = word + s.charAt(x2++);
          else
            x2 = -1;
        } else
          x2 = -1;

        if (x1 < 0 && x2 < 0)
          break;
        if (i > 200) {
          // time out!
          // System.err.println("Whoopsy! :P");
          break;
        }
      }
      if (Character.isDigit(word.charAt(0)))
        return null;
      String tooltipText = errorCheckerService.getASTGenerator()
          .getLabelForASTNode(line, word, xLS);

      log(errorCheckerService.mainClassOffset + " MCO "
      + "|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n");
      if (tooltipText != null)
        return tooltipText;
      return word;
    }

  }

}
TOP

Related Classes of processing.mode.experimental.TextAreaPainter

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.