Package org.syntax.jedit

Source Code of org.syntax.jedit.TextAreaPainter$Highlight

/*
* Copyright 2004-2014 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/

package org.syntax.jedit;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;

import javax.swing.JComponent;
import javax.swing.ToolTipManager;
import javax.swing.text.PlainDocument;
import javax.swing.text.Segment;
import javax.swing.text.TabExpander;
import javax.swing.text.Utilities;

import org.syntax.jedit.tokenmarker.Token;
import org.syntax.jedit.tokenmarker.TokenMarker;

import com.eviware.soapui.SoapUI;

/**
* The text area repaint manager. It performs double buffering and paints lines
* of text.
*
* @author Slava Pestov
* @version $Id$
*/
public class TextAreaPainter extends JComponent implements TabExpander {
    private int areaWidth;
    private int areaHeight;

    /**
     * Creates a new repaint manager. This should be not be called directly.
     */
    public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults) {
        this.textArea = textArea;

        setAutoscrolls(true);
        setDoubleBuffered(true);
        setOpaque(true);
        setBorder(null);

        ToolTipManager.sharedInstance().registerComponent(this);

        currentLine = new Segment();
        currentLineIndex = -1;

        setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));

        setFont(new Font("Monospaced", Font.PLAIN, 14));
        setForeground(Color.black);
        setBackground(Color.white);

        blockCaret = defaults.blockCaret;
        styles = defaults.styles;
        // cols = defaults.cols;
        // rows = defaults.rows;
        caretColor = defaults.caretColor;
        selectionColor = defaults.selectionColor;
        lineHighlightColor = defaults.lineHighlightColor;
        lineHighlight = defaults.lineHighlight;
        bracketHighlightColor = defaults.bracketHighlightColor;
        bracketHighlight = defaults.bracketHighlight;
        paintInvalid = defaults.paintInvalid;
        eolMarkerColor = defaults.eolMarkerColor;
        eolMarkers = defaults.eolMarkers;
    }

    /**
     * Returns if this component can be traversed by pressing the Tab key. This
     * returns false.
     */
    public final boolean isManagingFocus() {
        return false;
    }

    /**
     * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
     * will be used to paint tokens with id = <i>n</i>.
     *
     * @see org.syntax.jedit.Token
     */
    public final SyntaxStyle[] getStyles() {
        return styles;
    }

    /**
     * Sets the syntax styles used to paint colorized text. Entry <i>n</i> will
     * be used to paint tokens with id = <i>n</i>.
     *
     * @param styles The syntax styles
     * @see org.syntax.jedit.Token
     */
    public final void setStyles(SyntaxStyle[] styles) {
        this.styles = styles;
        repaint();
    }

    /**
     * Returns the caret color.
     */
    public final Color getCaretColor() {
        return caretColor;
    }

    /**
     * Sets the caret color.
     *
     * @param caretColor The caret color
     */
    public final void setCaretColor(Color caretColor) {
        this.caretColor = caretColor;
        invalidateSelectedLines();
    }

    /**
     * Returns the selection color.
     */
    public final Color getSelectionColor() {
        return selectionColor;
    }

    /**
     * Sets the selection color.
     *
     * @param selectionColor The selection color
     */
    public final void setSelectionColor(Color selectionColor) {
        this.selectionColor = selectionColor;
        invalidateSelectedLines();
    }

    /**
     * Returns the line highlight color.
     */
    public final Color getLineHighlightColor() {
        return lineHighlightColor;
    }

    /**
     * Sets the line highlight color.
     *
     * @param lineHighlightColor The line highlight color
     */
    public final void setLineHighlightColor(Color lineHighlightColor) {
        this.lineHighlightColor = lineHighlightColor;
        invalidateSelectedLines();
    }

    /**
     * Returns true if line highlight is enabled, false otherwise.
     */
    public final boolean isLineHighlightEnabled() {
        return lineHighlight;
    }

    /**
     * Enables or disables current line highlighting.
     *
     * @param lineHighlight True if current line highlight should be enabled, false
     *                      otherwise
     */
    public final void setLineHighlightEnabled(boolean lineHighlight) {
        this.lineHighlight = lineHighlight;
        invalidateSelectedLines();
    }

    /**
     * Returns the bracket highlight color.
     */
    public final Color getBracketHighlightColor() {
        return bracketHighlightColor;
    }

    /**
     * Sets the bracket highlight color.
     *
     * @param bracketHighlightColor The bracket highlight color
     */
    public final void setBracketHighlightColor(Color bracketHighlightColor) {
        this.bracketHighlightColor = bracketHighlightColor;
        invalidateLine(textArea.getBracketLine());
    }

    /**
     * Returns true if bracket highlighting is enabled, false otherwise. When
     * bracket highlighting is enabled, the bracket matching the one before the
     * caret (if any) is highlighted.
     */
    public final boolean isBracketHighlightEnabled() {
        return bracketHighlight;
    }

    /**
     * Enables or disables bracket highlighting. When bracket highlighting is
     * enabled, the bracket matching the one before the caret (if any) is
     * highlighted.
     *
     * @param bracketHighlight True if bracket highlighting should be enabled, false otherwise
     */
    public final void setBracketHighlightEnabled(boolean bracketHighlight) {
        this.bracketHighlight = bracketHighlight;
        invalidateLine(textArea.getBracketLine());
    }

    /**
     * Returns true if the caret should be drawn as a block, false otherwise.
     */
    public final boolean isBlockCaretEnabled() {
        return blockCaret;
    }

    /**
     * Sets if the caret should be drawn as a block, false otherwise.
     *
     * @param blockCaret True if the caret should be drawn as a block, false otherwise.
     */
    public final void setBlockCaretEnabled(boolean blockCaret) {
        this.blockCaret = blockCaret;
        invalidateSelectedLines();
    }

    /**
     * Returns the EOL marker color.
     */
    public final Color getEOLMarkerColor() {
        return eolMarkerColor;
    }

    /**
     * Sets the EOL marker color.
     *
     * @param eolMarkerColor The EOL marker color
     */
    public final void setEOLMarkerColor(Color eolMarkerColor) {
        this.eolMarkerColor = eolMarkerColor;
        repaint();
    }

    /**
     * Returns true if EOL markers are drawn, false otherwise.
     */
    public final boolean getEOLMarkersPainted() {
        return eolMarkers;
    }

    /**
     * Sets if EOL markers are to be drawn.
     *
     * @param eolMarkers True if EOL markers should be drawn, false otherwise
     */
    public final void setEOLMarkersPainted(boolean eolMarkers) {
        this.eolMarkers = eolMarkers;
        repaint();
    }

    /**
     * Returns true if invalid lines are painted as red tildes (~), false
     * otherwise.
     */
    public boolean getInvalidLinesPainted() {
        return paintInvalid;
    }

    /**
     * Sets if invalid lines are to be painted as red tildes.
     *
     * @param paintInvalid True if invalid lines should be drawn, false otherwise
     */
    public void setInvalidLinesPainted(boolean paintInvalid) {
        this.paintInvalid = paintInvalid;
    }

    /**
     * Adds a custom highlight painter.
     *
     * @param highlight The highlight
     */
    public void addCustomHighlight(Highlight highlight) {
        highlight.init(textArea, highlights);
        highlights = highlight;
    }

    /**
     * Highlight interface.
     */
    public interface Highlight {
        /**
         * Called after the highlight painter has been added.
         *
         * @param textArea The text area
         * @param next     The painter this one should delegate to
         */
        void init(JEditTextArea textArea, Highlight next);

        /**
         * This should paint the highlight and delgate to the next highlight
         * painter.
         *
         * @param gfx  The graphics context
         * @param line The line number
         * @param y    The y co-ordinate of the line
         */
        void paintHighlight(Graphics gfx, int line, int y);

        /**
         * Returns the tool tip to display at the specified location. If this
         * highlighter doesn't know what to display, it should delegate to the
         * next highlight painter.
         *
         * @param evt The mouse event
         */
        String getToolTipText(MouseEvent evt);
    }

    /**
     * Returns the tool tip to display at the specified location.
     *
     * @param evt The mouse event
     */
    public String getToolTipText(MouseEvent evt) {
        if (highlights != null) {
            return highlights.getToolTipText(evt);
        } else {
            return null;
        }
    }

    /**
     * Returns the font metrics used by this component.
     */
    public FontMetrics getFontMetrics() {
        return fm;
    }

    /**
     * Sets the font for this component. This is overridden to update the cached
     * font metrics and to recalculate which lines are visible.
     *
     * @param font The font
     */
    public void setFont(Font font) {
        super.setFont(font);
        fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
        textArea.recalculateVisibleLines();
    }

    /**
     * Repaints the text.
     *
     * @param g The graphics context
     */
    public void paint(Graphics gfx) {
        Rectangle clipRect = gfx.getClipBounds();

        gfx.setColor(getBackground());
        gfx.fillRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);

        // We don't use yToLine() here because that method doesn't
        // return lines past the end of the document
        int height = fm.getHeight();
        int firstLine = textArea.getFirstLine();
        int firstInvalid = firstLine + clipRect.y / height;
        // Because the clipRect's height is usually an even multiple
        // of the font height, we subtract 1 from it, otherwise one
        // too many lines will always be painted.
        int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;

        try {
            TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
            int x = 0; // -textArea.getHorizontalOffset();

            for (int line = firstInvalid; line <= lastInvalid; line++) {
                paintLine(gfx, tokenMarker, line, x);
            }

            if (tokenMarker != null && tokenMarker.isNextLineRequested()) {
                int h = clipRect.y + clipRect.height;
                repaint(0, h, getWidth(), getHeight() - h);
            }
        } catch (Exception e) {
            System.err.println("Error repainting line" + " range {" + firstInvalid + "," + lastInvalid + "}:");
            SoapUI.logError(e);
        }
    }

    /**
     * Marks a line as needing a repaint.
     *
     * @param line The line to invalidate
     */
    public final void invalidateLine(int line) {
        repaint(0, textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(), getWidth(), fm.getHeight());
    }

    /**
     * Marks a range of lines as needing a repaint.
     *
     * @param firstLine The first line to invalidate
     * @param lastLine  The last line to invalidate
     */
    public final void invalidateLineRange(int firstLine, int lastLine) {
        repaint(0, textArea.lineToY(firstLine) + fm.getMaxDescent() + fm.getLeading(), getWidth(), (lastLine
                - firstLine + 1)
                * fm.getHeight());
    }

    /**
     * Repaints the lines containing the selection.
     */
    public final void invalidateSelectedLines() {
        invalidateLineRange(textArea.getSelectionStartLine(), textArea.getSelectionEndLine());
    }

    /**
     * Implementation of TabExpander interface. Returns next tab stop after a
     * specified point.
     *
     * @param x         The x co-ordinate
     * @param tabOffset Ignored
     * @return The next tab stop after <i>x</i>
     */
    public float nextTabStop(float x, int tabOffset) {
        if (tabSize == 0) {
            initTabSize();
        }

        int offset = 0; // -textArea.getHorizontalOffset();
        int ntabs = ((int) x - offset) / tabSize;
        return (ntabs + 1) * tabSize + offset;
    }

    private void initTabSize() {
        tabSize = fm.charWidth(' ')
                * ((Integer) textArea.getDocument().getProperty(PlainDocument.tabSizeAttribute)).intValue();
        if (tabSize == 0) {
            tabSize = fm.charWidth(' ') * 4;
        }
    }

    /**
     * Returns the painter's preferred size.
     */
    public Dimension getPreferredSize() {
        Dimension dim = new Dimension();
        dim.width = fm.charWidth('w') * textArea.getMaxLineLength() + 5;
        dim.height = fm.getHeight() * textArea.getLineCount() + 5;
        return dim;
    }

    /**
     * Returns the painter's minimum size.
     */
    public Dimension getMinimumSize() {
        return getPreferredSize();
    }

    public Dimension getMaximumSize() {
        return getPreferredSize();
    }

    // package-private members
    int currentLineIndex;
    Token currentLineTokens;
    Segment currentLine;

    // protected members
    protected JEditTextArea textArea;

    protected SyntaxStyle[] styles;
    protected Color caretColor;
    protected Color selectionColor;
    protected Color lineHighlightColor;
    protected Color bracketHighlightColor;
    protected Color eolMarkerColor;

    protected boolean blockCaret;
    protected boolean lineHighlight;
    protected boolean bracketHighlight;
    protected boolean paintInvalid;
    protected boolean eolMarkers;
    // protected int cols;
    // protected int rows;

    protected int tabSize;
    protected FontMetrics fm;

    protected Highlight highlights;

    protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, int x) {
        Font defaultFont = getFont();
        Color defaultColor = getForeground();

        currentLineIndex = line;
        int y = textArea.lineToY(line);

        int lineWidth = 0;

        if (line < 0 || line >= textArea.getLineCount()) {
            if (paintInvalid) {
                paintHighlight(gfx, line, y);
                styles[Token.INVALID].setGraphicsFlags(gfx, defaultFont);
                gfx.drawString("~", 0, y + fm.getHeight());
            }
        } else if (tokenMarker == null) {
            lineWidth = paintPlainLine(gfx, line, defaultFont, defaultColor, x, y);
        } else {
            lineWidth = paintSyntaxLine(gfx, tokenMarker, line, defaultFont, defaultColor, x, y);
        }

        if (lineWidth > areaWidth) {
            areaWidth = lineWidth;
        }
    }

    protected int paintPlainLine(Graphics gfx, int line, Font defaultFont, Color defaultColor, int x, int y) {
        paintHighlight(gfx, line, y);
        textArea.getLineText(line, currentLine);

        gfx.setFont(defaultFont);
        gfx.setColor(defaultColor);

        y += fm.getHeight();
        x = Utilities.drawTabbedText(currentLine, x, y, gfx, this, 0);

        if (eolMarkers) {
            gfx.setColor(eolMarkerColor);
            gfx.drawString(".", x, y);
        }

        return x;
    }

    protected int paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker, int line, Font defaultFont,
                                  Color defaultColor, int x, int y) {
        textArea.getLineText(currentLineIndex, currentLine);
        currentLineTokens = tokenMarker.markTokens(currentLine, currentLineIndex);

        paintHighlight(gfx, line, y);

        gfx.setFont(defaultFont);
        gfx.setColor(defaultColor);
        y += fm.getHeight();
        x = SyntaxUtilities.paintSyntaxLine(currentLine, currentLineTokens, styles, this, gfx, x, y);

        if (eolMarkers) {
            gfx.setColor(eolMarkerColor);
            gfx.drawString(".", x, y);
        }

        return x;
    }

    protected void paintHighlight(Graphics gfx, int line, int y) {
        if (line >= textArea.getSelectionStartLine() && line <= textArea.getSelectionEndLine()) {
            paintLineHighlight(gfx, line, y);
        }

        if (highlights != null) {
            highlights.paintHighlight(gfx, line, y);
        }

        if (bracketHighlight && line == textArea.getBracketLine()) {
            paintBracketHighlight(gfx, line, y);
        }

        if (line == textArea.getCaretLine()) {
            paintCaret(gfx, line, y);
        }
    }

    protected void paintLineHighlight(Graphics gfx, int line, int y) {
        int height = fm.getHeight();
        y += fm.getLeading() + fm.getMaxDescent();

        int selectionStart = textArea.getSelectionStart();
        int selectionEnd = textArea.getSelectionEnd();

        if (selectionStart == selectionEnd) {
            if (lineHighlight) {
                gfx.setColor(lineHighlightColor);
                gfx.fillRect(0, y, getWidth(), height);
            }
        } else {
            gfx.setColor(selectionColor);

            int selectionStartLine = textArea.getSelectionStartLine();
            int selectionEndLine = textArea.getSelectionEndLine();
            int lineStart = textArea.getLineStartOffset(line);

            int x1, x2;
            if (textArea.isSelectionRectangular()) {
                int lineLen = textArea.getTabExpandedLineLength(line);
                x1 = textArea._offsetToX(line,
                        Math.min(lineLen, selectionStart - textArea.getLineStartOffset(selectionStartLine)));
                x2 = textArea._offsetToX(line,
                        Math.min(lineLen, selectionEnd - textArea.getLineStartOffset(selectionEndLine)));
                if (x1 == x2) {
                    x2++;
                }
            } else if (selectionStartLine == selectionEndLine) {
                x1 = textArea._offsetToX(line, selectionStart - lineStart);
                x2 = textArea._offsetToX(line, selectionEnd - lineStart);
            } else if (line == selectionStartLine) {
                x1 = textArea._offsetToX(line, selectionStart - lineStart);
                x2 = getWidth();
            } else if (line == selectionEndLine) {
                x1 = 0;
                x2 = textArea._offsetToX(line, selectionEnd - lineStart);
            } else {
                x1 = 0;
                x2 = getWidth();
            }

            // "inlined" min/max()
            gfx.fillRect(x1 > x2 ? x2 : x1, y, x1 > x2 ? (x1 - x2) : (x2 - x1), height);
        }

    }

    protected void paintBracketHighlight(Graphics gfx, int line, int y) {
        int position = textArea.getBracketPosition();
        if (position == -1) {
            return;
        }
        y += fm.getLeading() + fm.getMaxDescent();
        int x = textArea._offsetToX(line, position);
        gfx.setColor(bracketHighlightColor);
        // Hack!!! Since there is no fast way to get the character
        // from the bracket matching routine, we use ( since all
        // brackets probably have the same width anyway
        gfx.drawRect(x, y, fm.charWidth('(') - 1, fm.getHeight() - 1);
    }

    protected void paintCaret(Graphics gfx, int line, int y) {
        if (textArea.isCaretVisible()) {
            int offset = textArea.getCaretPosition() - textArea.getLineStartOffset(line);
            int caretX = textArea._offsetToX(line, offset);
            int caretWidth = ((blockCaret || textArea.isOverwriteEnabled()) ? fm.charWidth('w') : 1);
            y += fm.getLeading() + fm.getMaxDescent();
            int height = fm.getHeight();

            gfx.setColor(caretColor);

            if (textArea.isOverwriteEnabled()) {
                gfx.fillRect(caretX, y + height - 1, caretWidth, 1);
            } else {
                gfx.drawRect(caretX, y, caretWidth, height - 1);
            }
        }
    }
}
TOP

Related Classes of org.syntax.jedit.TextAreaPainter$Highlight

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.