Source Code Cross Referenced for ReverseHighlighter.java in  » IDE » DrJava » edu » rice » cs » drjava » ui » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE » DrJava » edu.rice.cs.drjava.ui 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*BEGIN_COPYRIGHT_BLOCK
002:         *
003:         * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004:         * All rights reserved.
005:         * 
006:         * Redistribution and use in source and binary forms, with or without
007:         * modification, are permitted provided that the following conditions are met:
008:         *    * Redistributions of source code must retain the above copyright
009:         *      notice, this list of conditions and the following disclaimer.
010:         *    * Redistributions in binary form must reproduce the above copyright
011:         *      notice, this list of conditions and the following disclaimer in the
012:         *      documentation and/or other materials provided with the distribution.
013:         *    * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014:         *      names of its contributors may be used to endorse or promote products
015:         *      derived from this software without specific prior written permission.
016:         * 
017:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018:         * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019:         * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020:         * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024:         * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025:         * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026:         * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028:         *
029:         * This software is Open Source Initiative approved Open Source Software.
030:         * Open Source Initative Approved is a trademark of the Open Source Initiative.
031:         * 
032:         * This file is part of DrJava.  Download the current version of this project
033:         * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034:         * 
035:         * END_COPYRIGHT_BLOCK*/
036:
037:        package edu.rice.cs.drjava.ui;
038:
039:        import javax.swing.text.*;
040:        import java.util.Vector;
041:        import java.awt.*;
042:        import javax.swing.plaf.*;
043:        import javax.swing.*;
044:
045:        /**
046:         * Implements the Highlighter interfaces.  Implements a simple highlight painter, but stores
047:         * the highlights in reverse order. That means that the selection (for copying) is always
048:         * the foremost hightlight, and after that, the highlights are drawn from most recent
049:         * to oldest.
050:         * Based on DefaultHighlighter by Timothy Prinzing, version 1.39 12/19/03
051:         * Unfortunately, as the vector of highlights in DefaultHighlighter was private, there was
052:         * no efficient way to make use of inheritance.
053:         */
054:        public class ReverseHighlighter extends DefaultHighlighter {
055:            /**
056:             * Creates a new ReverseHighlighter object.
057:             */
058:            public ReverseHighlighter() {
059:                drawsLayeredHighlights = true;
060:            }
061:
062:            // ---- Highlighter methods ----------------------------------------------
063:
064:            /**
065:             * Renders the highlights.
066:             *
067:             * @param g the graphics context
068:             */
069:            public void paint(Graphics g) {
070:                // PENDING(prinz) - should cull ranges not visible
071:                int len = highlights.size();
072:                for (int i = 0; i < len; i++) {
073:                    HighlightInfo info = highlights.elementAt(i);
074:                    if (!(info instanceof  LayeredHighlightInfo)) {
075:                        // Avoid allocing unless we need it.
076:                        Rectangle a = component.getBounds();
077:                        Insets insets = component.getInsets();
078:                        a.x = insets.left;
079:                        a.y = insets.top;
080:                        a.width -= insets.left + insets.right;
081:                        a.height -= insets.top + insets.bottom;
082:                        for (; i < len; i++) {
083:                            info = highlights.elementAt(i);
084:                            if (!(info instanceof  LayeredHighlightInfo)) {
085:                                Highlighter.HighlightPainter p = info
086:                                        .getPainter();
087:                                p.paint(g, info.getStartOffset(), info
088:                                        .getEndOffset(), a, component);
089:                            }
090:                        }
091:                    }
092:                }
093:            }
094:
095:            /** Called when the UI is being installed into the interface of a JTextComponent.  Installs the editor, and
096:             * removes any existing highlights.
097:             * @param c the editor component
098:             * @see Highlighter#install
099:             */
100:            public void install(JTextComponent c) {
101:                component = c;
102:                removeAllHighlights();
103:            }
104:
105:            /** Called when the UI is being removed from the interface of a JTextComponent.
106:             * @param c the component
107:             * @see Highlighter#deinstall
108:             */
109:            public void deinstall(JTextComponent c) {
110:                component = null;
111:            }
112:
113:            //static edu.rice.cs.util.Log _log = new edu.rice.cs.util.Log("highlighter.txt",true);
114:
115:            /** Adds a highlight to the view.  Returns a tag that can be used to refer to the highlight.
116:             * @param p0   the start offset of the range to highlight >= 0
117:             * @param p1   the end offset of the range to highlight >= p0
118:             * @param p    the painter to use to actually render the highlight
119:             * @return     an object that can be used as a tag to refer to the highlight
120:             * @exception BadLocationException if the specified location is invalid
121:             */
122:            public Object addHighlight(int p0, int p1,
123:                    Highlighter.HighlightPainter p) throws BadLocationException {
124:                Document doc = component.getDocument();
125:                HighlightInfo i = (getDrawsLayeredHighlights() && (p instanceof  LayeredHighlighter.LayerPainter)) ? new LayeredHighlightInfo()
126:                        : new HighlightInfo();
127:                i.painter = p;
128:
129:                i.p0 = doc.createPosition(p0);
130:                i.p1 = doc.createPosition(p1);
131:
132:                int insertPos = highlights.size();
133:                /*if ((!(p instanceof DefaultFrameHighlightPainter)) && (!(p instanceof DefaultUnderlineHighlightPainter))) {
134:                  // insert solid painters after the frame and underline painters
135:                  while (insertPos>0) {
136:                    HighlightInfo hli = highlights.elementAt( insertPos-1 );
137:                    if ((! (hli.getPainter() instanceof DefaultFrameHighlightPainter)) && 
138:                        (! (hli.getPainter() instanceof DefaultUnderlineHighlightPainter))) {
139:                      break;
140:                    }
141:                    --insertPos;
142:                  }
143:                }*/
144:                if (p instanceof  DrJavaHighlightPainter) {
145:                    while (insertPos > 0) {
146:                        HighlightInfo hli = highlights.elementAt(insertPos - 1);
147:                        if (hli.getPainter() instanceof  DrJavaHighlightPainter)
148:                            --insertPos;
149:                        else
150:                            break;
151:                    }
152:                } else if (p instanceof  DefaultHighlightPainter) {
153:                    while (insertPos > 0) {
154:                        HighlightInfo hli = highlights.elementAt(insertPos - 1);
155:                        if (hli.getPainter() instanceof  DefaultHighlightPainter)
156:                            --insertPos;
157:                        else
158:                            break;
159:                    }
160:                } else if (p instanceof  DefaultFrameHighlightPainter) {
161:                    while (insertPos > 0) {
162:                        HighlightInfo hli = highlights.elementAt(insertPos - 1);
163:                        if (hli.getPainter() instanceof  DefaultHighlightPainter
164:                                || hli.getPainter() instanceof  DefaultFrameHighlightPainter)
165:                            --insertPos;
166:                        else
167:                            break;
168:                    }
169:                } else {
170:                    insertPos = 0;
171:                }
172:                highlights.add(insertPos, i);
173:                //_log.log(p.toString() + ", pos: " + insertPos);
174:                safeDamageRange(p0, p1);
175:                return i;
176:            }
177:
178:            /**
179:             * Removes a highlight from the view.
180:             *
181:             * @param tag the reference to the highlight
182:             */
183:            public void removeHighlight(Object tag) {
184:                if (tag instanceof  LayeredHighlightInfo) {
185:                    LayeredHighlightInfo lhi = (LayeredHighlightInfo) tag;
186:                    if (lhi.width > 0 && lhi.height > 0) {
187:                        component.repaint(lhi.x, lhi.y, lhi.width, lhi.height);
188:                    }
189:                } else {
190:                    HighlightInfo info = (HighlightInfo) tag;
191:                    safeDamageRange(info.p0, info.p1);
192:                }
193:                highlights.removeElement(tag);
194:            }
195:
196:            /**
197:             * Removes all highlights.
198:             */
199:            public void removeAllHighlights() {
200:                TextUI mapper = component.getUI();
201:                if (getDrawsLayeredHighlights()) {
202:                    int len = highlights.size();
203:                    if (len != 0) {
204:                        int minX = 0;
205:                        int minY = 0;
206:                        int maxX = 0;
207:                        int maxY = 0;
208:                        int p0 = -1;
209:                        int p1 = -1;
210:                        for (int i = 0; i < len; i++) {
211:                            HighlightInfo hi = highlights.elementAt(i);
212:                            if (hi instanceof  LayeredHighlightInfo) {
213:                                LayeredHighlightInfo info = (LayeredHighlightInfo) hi;
214:                                minX = Math.min(minX, info.x);
215:                                minY = Math.min(minY, info.y);
216:                                maxX = Math.max(maxX, info.x + info.width);
217:                                maxY = Math.max(maxY, info.y + info.height);
218:                            } else {
219:                                if (p0 == -1) {
220:                                    p0 = hi.p0.getOffset();
221:                                    p1 = hi.p1.getOffset();
222:                                } else {
223:                                    p0 = Math.min(p0, hi.p0.getOffset());
224:                                    p1 = Math.max(p1, hi.p1.getOffset());
225:                                }
226:                            }
227:                        }
228:                        if (minX != maxX && minY != maxY) {
229:                            component.repaint(minX, minY, maxX - minX, maxY
230:                                    - minY);
231:                        }
232:                        if (p0 != -1) {
233:                            try {
234:                                safeDamageRange(p0, p1);
235:                            } catch (BadLocationException e) {
236:                            }
237:                        }
238:                        highlights.removeAllElements();
239:                    }
240:                } else if (mapper != null) {
241:                    int len = highlights.size();
242:                    if (len != 0) {
243:                        int p0 = Integer.MAX_VALUE;
244:                        int p1 = 0;
245:                        for (int i = 0; i < len; i++) {
246:                            HighlightInfo info = highlights.elementAt(i);
247:                            p0 = Math.min(p0, info.p0.getOffset());
248:                            p1 = Math.max(p1, info.p1.getOffset());
249:                        }
250:                        try {
251:                            safeDamageRange(p0, p1);
252:                        } catch (BadLocationException e) {
253:                        }
254:
255:                        highlights.removeAllElements();
256:                    }
257:                }
258:            }
259:
260:            /**
261:             * Changes a highlight.
262:             *
263:             * @param tag the highlight tag
264:             * @param p0 the beginning of the range >= 0
265:             * @param p1 the end of the range >= p0
266:             * @exception BadLocationException if the specified location is invalid
267:             */
268:            public void changeHighlight(Object tag, int p0, int p1)
269:                    throws BadLocationException {
270:                Document doc = component.getDocument();
271:                if (tag instanceof  LayeredHighlightInfo) {
272:                    LayeredHighlightInfo lhi = (LayeredHighlightInfo) tag;
273:                    if (lhi.width > 0 && lhi.height > 0) {
274:                        component.repaint(lhi.x, lhi.y, lhi.width, lhi.height);
275:                    }
276:                    // Mark the highlights region as invalid, it will reset itself
277:                    // next time asked to paint.
278:                    lhi.width = lhi.height = 0;
279:
280:                    lhi.p0 = doc.createPosition(p0);
281:                    lhi.p1 = doc.createPosition(p1);
282:                    safeDamageRange(Math.min(p0, p1), Math.max(p0, p1));
283:                } else {
284:                    HighlightInfo info = (HighlightInfo) tag;
285:                    int oldP0 = info.p0.getOffset();
286:                    int oldP1 = info.p1.getOffset();
287:                    if (p0 == oldP0)
288:                        safeDamageRange(Math.min(oldP1, p1), Math
289:                                .max(oldP1, p1));
290:                    else if (p1 == oldP1)
291:                        safeDamageRange(Math.min(p0, oldP0), Math
292:                                .max(p0, oldP0));
293:                    else {
294:                        safeDamageRange(oldP0, oldP1);
295:                        safeDamageRange(p0, p1);
296:                    }
297:
298:                    info.p0 = doc.createPosition(p0);
299:                    info.p1 = doc.createPosition(p1);
300:
301:                    // TODO: figure out what is wrong here.  The preceding lines are dead code.
302:                }
303:            }
304:
305:            /**
306:             * Makes a copy of the highlights.  Does not actually clone each highlight,
307:             * but only makes references to them.
308:             *
309:             * @return the copy
310:             * @see Highlighter#getHighlights
311:             */
312:            public Highlighter.Highlight[] getHighlights() {
313:                int size = highlights.size();
314:                if (size == 0) {
315:                    return noHighlights;
316:                }
317:                Highlighter.Highlight[] h = new Highlighter.Highlight[size];
318:                highlights.copyInto(h);
319:                return h;
320:            }
321:
322:            /**
323:             * When leaf Views (such as LabelView) are rendering they should
324:             * call into this method. If a highlight is in the given region it will
325:             * be drawn immediately.
326:             *
327:             * @param g Graphics used to draw
328:             * @param p0 starting offset of view
329:             * @param p1 ending offset of view
330:             * @param viewBounds Bounds of View
331:             * @param editor JTextComponent
332:             * @param view View instance being rendered
333:             */
334:            public void paintLayeredHighlights(Graphics g, int p0, int p1,
335:                    Shape viewBounds, JTextComponent editor, View view) {
336:                for (int counter = highlights.size() - 1; counter >= 0; counter--) {
337:                    Object tag = highlights.elementAt(counter);
338:                    if (tag instanceof  LayeredHighlightInfo) {
339:                        LayeredHighlightInfo lhi = (LayeredHighlightInfo) tag;
340:                        int start = lhi.getStartOffset();
341:                        int end = lhi.getEndOffset();
342:                        if ((p0 < start && p1 > start)
343:                                || (p0 >= start && p0 < end)) {
344:                            lhi.paintLayeredHighlights(g, p0, p1, viewBounds,
345:                                    editor, view);
346:                        }
347:                    }
348:                }
349:            }
350:
351:            /** Queues damageRange() call into event dispatch thread to be sure that views are in consistent state. */
352:            private void safeDamageRange(final Position p0, final Position p1) {
353:                safeDamager.damageRange(p0, p1);
354:            }
355:
356:            /** Queues damageRange() call into event dispatch thread to be sure that views are in consistent state. */
357:            private void safeDamageRange(int a0, int a1)
358:                    throws BadLocationException {
359:                Document doc = component.getDocument();
360:
361:                safeDamageRange(doc.createPosition(a0), doc.createPosition(a1));
362:            }
363:
364:            /**
365:             * If true, highlights are drawn as the Views draw the text. That is
366:             * the Views will call into <code>paintLayeredHighlight</code> which
367:             * will result in a rectangle being drawn before the text is drawn
368:             * (if the offsets are in a highlighted region that is). For this to
369:             * work the painter supplied must be an instance of
370:             * LayeredHighlightPainter.
371:             */
372:            public void setDrawsLayeredHighlights(boolean newValue) {
373:                drawsLayeredHighlights = newValue;
374:            }
375:
376:            public boolean getDrawsLayeredHighlights() {
377:                return drawsLayeredHighlights;
378:            }
379:
380:            // ---- member variables --------------------------------------------
381:
382:            private final static Highlighter.Highlight[] noHighlights = new Highlighter.Highlight[0];
383:            private Vector<HighlightInfo> highlights = new Vector<HighlightInfo>(); // Vector<HighlightInfo>
384:            private JTextComponent component;
385:            private boolean drawsLayeredHighlights;
386:            private SafeDamager safeDamager = new SafeDamager();
387:
388:            /** Simple highlight painter that draws a rectangular box around text. */
389:            public static class DefaultFrameHighlightPainter extends
390:                    LayeredHighlighter.LayerPainter {
391:
392:                /**
393:                 * Constructs a new highlight painter. If <code>c</code> is null,
394:                 * the JTextComponent will be queried for its selection color.
395:                 *
396:                 * @param c the color for the highlight
397:                 * @param t the thickness in pixels
398:                 */
399:                public DefaultFrameHighlightPainter(Color c, int t) {
400:                    color = c;
401:                    thickness = t;
402:                }
403:
404:                /**
405:                 * Returns the color of the highlight.
406:                 *
407:                 * @return the color
408:                 */
409:                public Color getColor() {
410:                    return color;
411:                }
412:
413:                /** @return thickness in pixels */
414:                public int getThickness() {
415:                    return thickness;
416:                }
417:
418:                // --- HighlightPainter methods ---------------------------------------
419:
420:                private void drawRectThick(Graphics g, int x, int y, int width,
421:                        int height, int thick) {
422:                    if (thick < 2) {
423:                        g.drawRect(x, y, width, height);
424:                    } else {
425:                        g.fillRect(x, y, width, thick);
426:                        g.fillRect(x, y + height - thick, width, thick);
427:                        g.fillRect(x, y, thick, height);
428:                        g.fillRect(x + width - thick, y, thick, height);
429:                    }
430:                }
431:
432:                /**
433:                 * Paints a highlight.
434:                 *
435:                 * @param g the graphics context
436:                 * @param offs0 the starting model offset >= 0
437:                 * @param offs1 the ending model offset >= offs1
438:                 * @param bounds the bounding box for the highlight
439:                 * @param c the editor
440:                 */
441:                public void paint(Graphics g, int offs0, int offs1,
442:                        Shape bounds, JTextComponent c) {
443:                    Rectangle alloc = bounds.getBounds();
444:                    try {
445:                        // --- determine locations ---
446:                        TextUI mapper = c.getUI();
447:                        Rectangle p0 = mapper.modelToView(c, offs0);
448:                        Rectangle p1 = mapper.modelToView(c, offs1);
449:
450:                        // --- render ---
451:                        Color color = getColor();
452:
453:                        if (color == null) {
454:                            g.setColor(c.getSelectionColor());
455:                        } else {
456:                            g.setColor(color);
457:                        }
458:                        if (p0.y == p1.y) {
459:                            // same line, render a rectangle
460:                            Rectangle r = p0.union(p1);
461:                            drawRectThick(g, r.x, r.y, r.width, r.height,
462:                                    thickness);
463:                        } else {
464:                            // different lines
465:                            int p0ToMarginWidth = alloc.x + alloc.width - p0.x;
466:                            drawRectThick(g, p0.x, p0.y, p0ToMarginWidth,
467:                                    p0.height, thickness);
468:                            if ((p0.y + p0.height) != p1.y) {
469:                                drawRectThick(g, alloc.x, p0.y + p0.height,
470:                                        alloc.width, p1.y - (p0.y + p0.height),
471:                                        thickness);
472:                            }
473:                            drawRectThick(g, alloc.x, p1.y, (p1.x - alloc.x),
474:                                    p1.height, thickness);
475:                        }
476:                    } catch (BadLocationException e) {
477:                        // can't render
478:                    }
479:                }
480:
481:                // --- LayerPainter methods ----------------------------
482:                /**
483:                 * Paints a portion of a highlight.
484:                 *
485:                 * @param g the graphics context
486:                 * @param offs0 the starting model offset >= 0
487:                 * @param offs1 the ending model offset >= offs1
488:                 * @param bounds the bounding box of the view, which is not
489:                 *        necessarily the region to paint.
490:                 * @param c the editor
491:                 * @param view View painting for
492:                 * @return region drawing occured in
493:                 */
494:                public Shape paintLayer(Graphics g, int offs0, int offs1,
495:                        Shape bounds, JTextComponent c, View view) {
496:                    Color color = getColor();
497:
498:                    if (color == null) {
499:                        g.setColor(c.getSelectionColor());
500:                    } else {
501:                        g.setColor(color);
502:                    }
503:                    if (offs0 == view.getStartOffset()
504:                            && offs1 == view.getEndOffset()) {
505:                        // Contained in view, can just use bounds.
506:                        Rectangle alloc;
507:                        if (bounds instanceof  Rectangle) {
508:                            alloc = (Rectangle) bounds;
509:                        } else {
510:                            alloc = bounds.getBounds();
511:                        }
512:                        drawRectThick(g, alloc.x, alloc.y, alloc.width,
513:                                alloc.height, thickness);
514:                        return alloc;
515:                    } else {
516:                        // Should only render part of View.
517:                        try {
518:                            // --- determine locations ---
519:                            Shape shape = view.modelToView(offs0,
520:                                    Position.Bias.Forward, offs1,
521:                                    Position.Bias.Backward, bounds);
522:                            Rectangle r = (shape instanceof  Rectangle) ? (Rectangle) shape
523:                                    : shape.getBounds();
524:                            drawRectThick(g, r.x, r.y, r.width, r.height,
525:                                    thickness);
526:                            return r;
527:                        } catch (BadLocationException e) {
528:                            // can't render
529:                        }
530:                    }
531:                    // Only if exception
532:                    return null;
533:                }
534:
535:                private Color color;
536:                private int thickness;
537:            }
538:
539:            /**
540:             * Simple highlight painter that underlines text.
541:             */
542:            public static class DefaultUnderlineHighlightPainter extends
543:                    LayeredHighlighter.LayerPainter {
544:
545:                /**
546:                 * Constructs a new highlight painter. If <code>c</code> is null,
547:                 * the JTextComponent will be queried for its selection color.
548:                 *
549:                 * @param c the color for the highlight
550:                 * @param t the thickness in pixels
551:                 */
552:                public DefaultUnderlineHighlightPainter(Color c, int t) {
553:                    color = c;
554:                    thickness = t;
555:                }
556:
557:                /**
558:                 * Returns the color of the highlight.
559:                 *
560:                 * @return the color
561:                 */
562:                public Color getColor() {
563:                    return color;
564:                }
565:
566:                /** @return thickness in pixels */
567:                public int getThickness() {
568:                    return thickness;
569:                }
570:
571:                // --- HighlightPainter methods ---------------------------------------
572:
573:                private void drawUnderline(Graphics g, int x, int y, int width,
574:                        int height, int thick) {
575:                    g.fillRect(x, y + height - thick, width, thick);
576:                }
577:
578:                /**
579:                 * Paints a highlight.
580:                 *
581:                 * @param g the graphics context
582:                 * @param offs0 the starting model offset >= 0
583:                 * @param offs1 the ending model offset >= offs1
584:                 * @param bounds the bounding box for the highlight
585:                 * @param c the editor
586:                 */
587:                public void paint(Graphics g, int offs0, int offs1,
588:                        Shape bounds, JTextComponent c) {
589:                    Rectangle alloc = bounds.getBounds();
590:                    try {
591:                        // --- determine locations ---
592:                        TextUI mapper = c.getUI();
593:                        Rectangle p0 = mapper.modelToView(c, offs0);
594:                        Rectangle p1 = mapper.modelToView(c, offs1);
595:
596:                        // --- render ---
597:                        Color color = getColor();
598:
599:                        if (color == null) {
600:                            g.setColor(c.getSelectionColor());
601:                        } else {
602:                            g.setColor(color);
603:                        }
604:                        if (p0.y == p1.y) {
605:                            // same line, render a rectangle
606:                            Rectangle r = p0.union(p1);
607:                            drawUnderline(g, r.x, r.y, r.width, r.height,
608:                                    thickness);
609:                        } else {
610:                            // different lines
611:                            int p0ToMarginWidth = alloc.x + alloc.width - p0.x;
612:                            drawUnderline(g, p0.x, p0.y, p0ToMarginWidth,
613:                                    p0.height, thickness);
614:                            if ((p0.y + p0.height) != p1.y) {
615:                                drawUnderline(g, alloc.x, p0.y + p0.height,
616:                                        alloc.width, p1.y - (p0.y + p0.height),
617:                                        thickness);
618:                            }
619:                            drawUnderline(g, alloc.x, p1.y, (p1.x - alloc.x),
620:                                    p1.height, thickness);
621:                        }
622:                    } catch (BadLocationException e) {
623:                        // can't render
624:                    }
625:                }
626:
627:                // --- LayerPainter methods ----------------------------
628:                /**
629:                 * Paints a portion of a highlight.
630:                 *
631:                 * @param g the graphics context
632:                 * @param offs0 the starting model offset >= 0
633:                 * @param offs1 the ending model offset >= offs1
634:                 * @param bounds the bounding box of the view, which is not
635:                 *        necessarily the region to paint.
636:                 * @param c the editor
637:                 * @param view View painting for
638:                 * @return region drawing occured in
639:                 */
640:                public Shape paintLayer(Graphics g, int offs0, int offs1,
641:                        Shape bounds, JTextComponent c, View view) {
642:                    Color color = getColor();
643:
644:                    if (color == null) {
645:                        g.setColor(c.getSelectionColor());
646:                    } else {
647:                        g.setColor(color);
648:                    }
649:                    if (offs0 == view.getStartOffset()
650:                            && offs1 == view.getEndOffset()) {
651:                        // Contained in view, can just use bounds.
652:                        Rectangle alloc;
653:                        if (bounds instanceof  Rectangle) {
654:                            alloc = (Rectangle) bounds;
655:                        } else {
656:                            alloc = bounds.getBounds();
657:                        }
658:                        drawUnderline(g, alloc.x, alloc.y, alloc.width,
659:                                alloc.height, thickness);
660:                        return alloc;
661:                    } else {
662:                        // Should only render part of View.
663:                        try {
664:                            // --- determine locations ---
665:                            Shape shape = view.modelToView(offs0,
666:                                    Position.Bias.Forward, offs1,
667:                                    Position.Bias.Backward, bounds);
668:                            Rectangle r = (shape instanceof  Rectangle) ? (Rectangle) shape
669:                                    : shape.getBounds();
670:                            drawUnderline(g, r.x, r.y, r.width, r.height,
671:                                    thickness);
672:                            return r;
673:                        } catch (BadLocationException e) {
674:                            // can't render
675:                        }
676:                    }
677:                    // Only if exception
678:                    return null;
679:                }
680:
681:                private Color color;
682:                private int thickness;
683:            }
684:
685:            class HighlightInfo implements  Highlighter.Highlight {
686:
687:                public int getStartOffset() {
688:                    return p0.getOffset();
689:                }
690:
691:                public int getEndOffset() {
692:                    return p1.getOffset();
693:                }
694:
695:                public Highlighter.HighlightPainter getPainter() {
696:                    return painter;
697:                }
698:
699:                Position p0;
700:                Position p1;
701:                Highlighter.HighlightPainter painter;
702:            }
703:
704:            /**
705:             * This class is a wrapper for the DefaultHighlightPainter that allows us to tell whether a highlight was
706:             * requested by DrJava or by Swing (as in selected text).
707:             */
708:            public static class DrJavaHighlightPainter extends
709:                    DefaultHighlightPainter {
710:
711:                public DrJavaHighlightPainter(Color c) {
712:                    super (c);
713:                }
714:
715:            }
716:
717:            /**
718:             * LayeredHighlightPainter is used when a drawsLayeredHighlights is
719:             * true. It maintains a rectangle of the region to paint.
720:             */
721:            class LayeredHighlightInfo extends HighlightInfo {
722:
723:                void union(Shape bounds) {
724:                    if (bounds == null)
725:                        return;
726:
727:                    Rectangle alloc;
728:                    if (bounds instanceof  Rectangle) {
729:                        alloc = (Rectangle) bounds;
730:                    } else {
731:                        alloc = bounds.getBounds();
732:                    }
733:                    if (width == 0 || height == 0) {
734:                        x = alloc.x;
735:                        y = alloc.y;
736:                        width = alloc.width;
737:                        height = alloc.height;
738:                    } else {
739:                        width = Math.max(x + width, alloc.x + alloc.width);
740:                        height = Math.max(y + height, alloc.y + alloc.height);
741:                        x = Math.min(x, alloc.x);
742:                        width -= x;
743:                        y = Math.min(y, alloc.y);
744:                        height -= y;
745:                    }
746:                }
747:
748:                /** Restricts the region based on the receivers offsets and messages the painter to paint the region.*/
749:                void paintLayeredHighlights(Graphics g, int p0, int p1,
750:                        Shape viewBounds, JTextComponent editor, View view) {
751:                    int start = getStartOffset();
752:                    int end = getEndOffset();
753:                    // Restrict the region to what we represent
754:                    p0 = Math.max(start, p0);
755:                    p1 = Math.min(end, p1);
756:                    // Paint the appropriate region using the painter and union
757:                    // the effected region with our bounds.
758:                    union(((LayeredHighlighter.LayerPainter) painter)
759:                            .paintLayer(g, p0, p1, viewBounds, editor, view));
760:                }
761:
762:                int x;
763:                int y;
764:                int width;
765:                int height;
766:            }
767:
768:            /** This class invokes <code>mapper.damageRange</code> in EventDispatchThread. The only one instance per Highlighter
769:             *  is cretaed. When a number of ranges should be damaged it collects them into queue and damages them in consecutive
770:             *  order in <code>run</code> call.
771:             */
772:            class SafeDamager implements  Runnable {
773:                private Vector<Position> p0 = new Vector<Position>(10);
774:                private Vector<Position> p1 = new Vector<Position>(10);
775:                private Document lastDoc = null;
776:
777:                /** Executes range(s) damage and cleans range queue. */
778:                public synchronized void run() {
779:                    if (component != null) {
780:                        TextUI mapper = component.getUI();
781:                        if (mapper != null
782:                                && lastDoc == component.getDocument()) {
783:                            // the Document should be the same to properly display highlights
784:                            int len = p0.size();
785:                            for (int i = 0; i < len; i++) {
786:                                mapper.damageRange(component, p0.get(i)
787:                                        .getOffset(), p1.get(i).getOffset());
788:                            }
789:                        }
790:                    }
791:                    p0.clear();
792:                    p1.clear();
793:
794:                    // release reference
795:                    lastDoc = null;
796:                }
797:
798:                /**
799:                 * Adds the range to be damaged into the range queue. If the
800:                 * range queue is empty (the first call or run() was already
801:                 * invoked) then adds this class instance into EventDispatch
802:                 * queue.
803:                 *
804:                 * The method also tracks if the current document changed or
805:                 * component is null. In this case it removes all ranges added
806:                 * before from range queue.
807:                 */
808:                public synchronized void damageRange(Position pos0,
809:                        Position pos1) {
810:                    if (component == null) {
811:                        p0.clear();
812:                        lastDoc = null;
813:                        return;
814:                    }
815:
816:                    boolean addToQueue = p0.isEmpty();
817:                    Document curDoc = component.getDocument();
818:                    if (curDoc != lastDoc) {
819:                        if (!p0.isEmpty()) {
820:                            p0.clear();
821:                            p1.clear();
822:                        }
823:                        lastDoc = curDoc;
824:                    }
825:                    p0.add(pos0);
826:                    p1.add(pos1);
827:
828:                    if (addToQueue) {
829:                        SwingUtilities.invokeLater(this);
830:                    }
831:                }
832:            }
833:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.