654 lines · 22.5 KB · Java
RawDownload
/* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package javax.swing.text; import java.util.Vector;import java.awt.*;import javax.swing.plaf.*;import javax.swing.*; /** * Implements the Highlighter interfaces.  Implements a simple highlight * painter that renders in a solid color. * * @author  Timothy Prinzing * @see     Highlighter */public class DefaultHighlighter extends LayeredHighlighter {     /**     * Creates a new DefaultHighlighther object.     */    public DefaultHighlighter() {        drawsLayeredHighlights = true;    }     // ---- Highlighter methods ----------------------------------------------     /**     * Renders the highlights.     *     * @param g the graphics context     */    public void paint(Graphics g) {        // PENDING(prinz) - should cull ranges not visible        int len = highlights.size();        for (int i = 0; i < len; i++) {            HighlightInfo info = highlights.elementAt(i);            if (!(info instanceof LayeredHighlightInfo)) {                // Avoid allocing unless we need it.                Rectangle a = component.getBounds();                Insets insets = component.getInsets();                a.x = insets.left;                a.y = insets.top;                a.width -= insets.left + insets.right;                a.height -= insets.top + insets.bottom;                for (; i < len; i++) {                    info = highlights.elementAt(i);                    if (!(info instanceof LayeredHighlightInfo)) {                        Highlighter.HighlightPainter p = info.getPainter();                        p.paint(g, info.getStartOffset(), info.getEndOffset(),                                a, component);                    }                }            }        }    }     /**     * Called when the UI is being installed into the     * interface of a JTextComponent.  Installs the editor, and     * removes any existing highlights.     *     * @param c the editor component     * @see Highlighter#install     */    public void install(JTextComponent c) {        component = c;        removeAllHighlights();    }     /**     * Called when the UI is being removed from the interface of     * a JTextComponent.     *     * @param c the component     * @see Highlighter#deinstall     */    public void deinstall(JTextComponent c) {        component = null;    }     /**     * Adds a highlight to the view.  Returns a tag that can be used     * to refer to the highlight.     *     * @param p0   the start offset of the range to highlight >= 0     * @param p1   the end offset of the range to highlight >= p0     * @param p    the painter to use to actually render the highlight     * @return     an object that can be used as a tag     *   to refer to the highlight     * @exception BadLocationException if the specified location is invalid     */    public Object addHighlight(int p0, int p1, Highlighter.HighlightPainter p) throws BadLocationException {        if (p0 < 0) {            throw new BadLocationException("Invalid start offset", p0);        }         if (p1 < p0) {            throw new BadLocationException("Invalid end offset", p1);        }         Document doc = component.getDocument();        HighlightInfo i = (getDrawsLayeredHighlights() &&                           (p instanceof LayeredHighlighter.LayerPainter)) ?                          new LayeredHighlightInfo() : new HighlightInfo();        i.painter = p;        i.p0 = doc.createPosition(p0);        i.p1 = doc.createPosition(p1);        highlights.addElement(i);        safeDamageRange(p0, p1);        return i;    }     /**     * Removes a highlight from the view.     *     * @param tag the reference to the highlight     */    public void removeHighlight(Object tag) {        if (tag instanceof LayeredHighlightInfo) {            LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag;            if (lhi.width > 0 && lhi.height > 0) {                component.repaint(lhi.x, lhi.y, lhi.width, lhi.height);            }        }        else {            HighlightInfo info = (HighlightInfo) tag;            safeDamageRange(info.p0, info.p1);        }        highlights.removeElement(tag);    }     /**     * Removes all highlights.     */    public void removeAllHighlights() {        TextUI mapper = component.getUI();        if (getDrawsLayeredHighlights()) {            int len = highlights.size();            if (len != 0) {                int minX = 0;                int minY = 0;                int maxX = 0;                int maxY = 0;                int p0 = -1;                int p1 = -1;                for (int i = 0; i < len; i++) {                    HighlightInfo hi = highlights.elementAt(i);                    if (hi instanceof LayeredHighlightInfo) {                        LayeredHighlightInfo info = (LayeredHighlightInfo)hi;                        minX = Math.min(minX, info.x);                        minY = Math.min(minY, info.y);                        maxX = Math.max(maxX, info.x + info.width);                        maxY = Math.max(maxY, info.y + info.height);                    }                    else {                        if (p0 == -1) {                            p0 = hi.p0.getOffset();                            p1 = hi.p1.getOffset();                        }                        else {                            p0 = Math.min(p0, hi.p0.getOffset());                            p1 = Math.max(p1, hi.p1.getOffset());                        }                    }                }                if (minX != maxX && minY != maxY) {                    component.repaint(minX, minY, maxX - minX, maxY - minY);                }                if (p0 != -1) {                    try {                        safeDamageRange(p0, p1);                    } catch (BadLocationException e) {}                }                highlights.removeAllElements();            }        }        else if (mapper != null) {            int len = highlights.size();            if (len != 0) {                int p0 = Integer.MAX_VALUE;                int p1 = 0;                for (int i = 0; i < len; i++) {                    HighlightInfo info = highlights.elementAt(i);                    p0 = Math.min(p0, info.p0.getOffset());                    p1 = Math.max(p1, info.p1.getOffset());                }                try {                    safeDamageRange(p0, p1);                } catch (BadLocationException e) {}                 highlights.removeAllElements();            }        }    }     /**     * Changes a highlight.     *     * @param tag the highlight tag     * @param p0 the beginning of the range >= 0     * @param p1 the end of the range >= p0     * @exception BadLocationException if the specified location is invalid     */    public void changeHighlight(Object tag, int p0, int p1) throws BadLocationException {        if (p0 < 0) {            throw new BadLocationException("Invalid beginning of the range", p0);        }         if (p1 < p0) {            throw new BadLocationException("Invalid end of the range", p1);        }         Document doc = component.getDocument();        if (tag instanceof LayeredHighlightInfo) {            LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag;            if (lhi.width > 0 && lhi.height > 0) {                component.repaint(lhi.x, lhi.y, lhi.width, lhi.height);            }            // Mark the highlights region as invalid, it will reset itself            // next time asked to paint.            lhi.width = lhi.height = 0;            lhi.p0 = doc.createPosition(p0);            lhi.p1 = doc.createPosition(p1);            safeDamageRange(Math.min(p0, p1), Math.max(p0, p1));        }        else {            HighlightInfo info = (HighlightInfo) tag;            int oldP0 = info.p0.getOffset();            int oldP1 = info.p1.getOffset();            if (p0 == oldP0) {                safeDamageRange(Math.min(oldP1, p1),                                   Math.max(oldP1, p1));            } else if (p1 == oldP1) {                safeDamageRange(Math.min(p0, oldP0),                                   Math.max(p0, oldP0));            } else {                safeDamageRange(oldP0, oldP1);                safeDamageRange(p0, p1);            }            info.p0 = doc.createPosition(p0);            info.p1 = doc.createPosition(p1);        }    }     /**     * Makes a copy of the highlights.  Does not actually clone each highlight,     * but only makes references to them.     *     * @return the copy     * @see Highlighter#getHighlights     */    public Highlighter.Highlight[] getHighlights() {        int size = highlights.size();        if (size == 0) {            return noHighlights;        }        Highlighter.Highlight[] h = new Highlighter.Highlight[size];        highlights.copyInto(h);        return h;    }     /**     * 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 p0 starting offset of view     * @param p1 ending offset of view     * @param viewBounds Bounds of View     * @param editor JTextComponent     * @param view View instance being rendered     */    public void paintLayeredHighlights(Graphics g, int p0, int p1,                                       Shape viewBounds,                                       JTextComponent editor, View view) {        for (int counter = highlights.size() - 1; counter >= 0; counter--) {            HighlightInfo tag = highlights.elementAt(counter);            if (tag instanceof LayeredHighlightInfo) {                LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag;                int start = lhi.getStartOffset();                int end = lhi.getEndOffset();                if ((p0 < start && p1 > start) ||                    (p0 >= start && p0 < end)) {                    lhi.paintLayeredHighlights(g, p0, p1, viewBounds,                                               editor, view);                }            }        }    }     /**     * Queues damageRange() call into event dispatch thread     * to be sure that views are in consistent state.     */    private void safeDamageRange(final Position p0, final Position p1) {        safeDamager.damageRange(p0, p1);    }     /**     * Queues damageRange() call into event dispatch thread     * to be sure that views are in consistent state.     */    private void safeDamageRange(int a0, int a1) throws BadLocationException {        Document doc = component.getDocument();        safeDamageRange(doc.createPosition(a0), doc.createPosition(a1));    }     /**     * If true, highlights are drawn as the Views draw the text. That is     * the Views will call into <code>paintLayeredHighlight</code> which     * will result in a rectangle being drawn before the text is drawn     * (if the offsets are in a highlighted region that is). For this to     * work the painter supplied must be an instance of     * LayeredHighlightPainter.     */    public void setDrawsLayeredHighlights(boolean newValue) {        drawsLayeredHighlights = newValue;    }     public boolean getDrawsLayeredHighlights() {        return drawsLayeredHighlights;    }     // ---- member variables --------------------------------------------     private final static Highlighter.Highlight[] noHighlights =            new Highlighter.Highlight[0];    private Vector<HighlightInfo> highlights = new Vector<HighlightInfo>();    private JTextComponent component;    private boolean drawsLayeredHighlights;    private SafeDamager safeDamager = new SafeDamager();      /**     * Default implementation of LayeredHighlighter.LayerPainter that can     * be used for painting highlights.     * <p>     * As of 1.4 this field is final.     */    public static final LayeredHighlighter.LayerPainter DefaultPainter = new DefaultHighlightPainter(null);      /**     * Simple highlight painter that fills a highlighted area with     * a solid color.     */    public static class DefaultHighlightPainter extends LayeredHighlighter.LayerPainter {         /**         * Constructs a new highlight painter. If <code>c</code> is null,         * the JTextComponent will be queried for its selection color.         *         * @param c the color for the highlight         */        public DefaultHighlightPainter(Color c) {            color = c;        }         /**         * Returns the color of the highlight.         *         * @return the color         */        public Color getColor() {            return color;        }         // --- HighlightPainter methods ---------------------------------------         /**         * Paints a highlight.         *         * @param g the graphics context         * @param offs0 the starting model offset >= 0         * @param offs1 the ending model offset >= offs1         * @param bounds the bounding box for the highlight         * @param c the editor         */        public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) {            Rectangle alloc = bounds.getBounds();            try {                // --- determine locations ---                TextUI mapper = c.getUI();                Rectangle p0 = mapper.modelToView(c, offs0);                Rectangle p1 = mapper.modelToView(c, offs1);                 // --- render ---                Color color = getColor();                 if (color == null) {                    g.setColor(c.getSelectionColor());                }                else {                    g.setColor(color);                }                if (p0.y == p1.y) {                    // same line, render a rectangle                    Rectangle r = p0.union(p1);                    g.fillRect(r.x, r.y, r.width, r.height);                } else {                    // different lines                    int p0ToMarginWidth = alloc.x + alloc.width - p0.x;                    g.fillRect(p0.x, p0.y, p0ToMarginWidth, p0.height);                    if ((p0.y + p0.height) != p1.y) {                        g.fillRect(alloc.x, p0.y + p0.height, alloc.width,                                   p1.y - (p0.y + p0.height));                    }                    g.fillRect(alloc.x, p1.y, (p1.x - alloc.x), p1.height);                }            } catch (BadLocationException e) {                // can't render            }        }         // --- LayerPainter methods ----------------------------        /**         * Paints a portion of a highlight.         *         * @param g the graphics context         * @param offs0 the starting model offset >= 0         * @param offs1 the ending model offset >= offs1         * @param bounds the bounding box of the view, which is not         *        necessarily the region to paint.         * @param c the editor         * @param view View painting for         * @return region drawing occured in         */        public Shape paintLayer(Graphics g, int offs0, int offs1,                                Shape bounds, JTextComponent c, View view) {            Color color = getColor();             if (color == null) {                g.setColor(c.getSelectionColor());            }            else {                g.setColor(color);            }             Rectangle r;             if (offs0 == view.getStartOffset() &&                offs1 == view.getEndOffset()) {                // Contained in view, can just use bounds.                if (bounds instanceof Rectangle) {                    r = (Rectangle) bounds;                }                else {                    r = bounds.getBounds();                }            }            else {                // Should only render part of View.                try {                    // --- determine locations ---                    Shape shape = view.modelToView(offs0, Position.Bias.Forward,                                                   offs1,Position.Bias.Backward,                                                   bounds);                    r = (shape instanceof Rectangle) ?                                  (Rectangle)shape : shape.getBounds();                } catch (BadLocationException e) {                    // can't render                    r = null;                }            }             if (r != null) {                // If we are asked to highlight, we should draw something even                // if the model-to-view projection is of zero width (6340106).                r.width = Math.max(r.width, 1);                 g.fillRect(r.x, r.y, r.width, r.height);            }             return r;        } 

Lines 1–500 of 654.