Source Code Cross Referenced for DrawEngine.java in  » Swing-Library » abeille-forms-designer » org » netbeans » editor » 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 » Swing Library » abeille forms designer » org.netbeans.editor 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *                 Sun Public License Notice
0003:         * 
0004:         * The contents of this file are subject to the Sun Public License
0005:         * Version 1.0 (the "License"). You may not use this file except in
0006:         * compliance with the License. A copy of the License is available at
0007:         * http://www.sun.com/
0008:         * 
0009:         * The Original Code is NetBeans. The Initial Developer of the Original
0010:         * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
0011:         * Microsystems, Inc. All Rights Reserved.
0012:         */
0013:
0014:        package org.netbeans.editor;
0015:
0016:        import java.awt.Color;
0017:        import java.awt.Font;
0018:        import java.awt.FontMetrics;
0019:        import java.awt.Graphics;
0020:        import java.awt.Graphics2D;
0021:        import java.awt.Insets;
0022:        import java.awt.Rectangle;
0023:
0024:        import javax.swing.text.BadLocationException;
0025:        import javax.swing.text.JTextComponent;
0026:
0027:        /**
0028:         * Class responsible for drawing the editor component.
0029:         * 
0030:         * @author Miloslav Metelka
0031:         * @version 1.00
0032:         */
0033:        class DrawEngine {
0034:
0035:            /** Whether debug messages should be displayed */
0036:            private static final boolean debug = Boolean
0037:                    .getBoolean("netbeans.debug.editor.draw"); // NOI18N
0038:            /** Whether debug messages for each token fragment should be displayed */
0039:            private static final boolean debugFragment = Boolean
0040:                    .getBoolean("netbeans.debug.editor.draw.fragment"); // NOI18N
0041:
0042:            /** Initial size of mark array in <CODE>DrawMarkRenderer</CODE>. */
0043:            private static final int DEFAULT_DRAW_MARK_RENDERER_SIZE = 20;
0044:
0045:            /** Only one instance of draw-engine */
0046:            private static DrawEngine drawEngine;
0047:
0048:            private static final char[] SPACE = new char[] { ' ' };
0049:
0050:            /** Prevent creation */
0051:            private DrawEngine() {
0052:            }
0053:
0054:            /** Get the static instance of draw-engine */
0055:            public static DrawEngine getDrawEngine() {
0056:                if (drawEngine == null) {
0057:                    drawEngine = new DrawEngine();
0058:                }
0059:                return drawEngine;
0060:            }
0061:
0062:            private void initLineNumbering(DrawInfo ctx) {
0063:                // Resolve whether line numbers will be painted
0064:                ctx.lineNumbering = ctx.editorUI.lineNumberVisible
0065:                        && ctx.drawGraphics.supportsLineNumbers();
0066:
0067:                // create buffer for showing line numbers
0068:                if (ctx.lineNumbering) {
0069:                    try {
0070:                        ctx.startLineNumber = Utilities.getLineOffset(ctx.doc,
0071:                                ctx.startOffset) + 1;
0072:                    } catch (BadLocationException e) {
0073:                        if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
0074:                            e.printStackTrace();
0075:                        }
0076:                    }
0077:
0078:                    ctx.lineNumberColoring = ctx.editorUI
0079:                            .getColoring(SettingsNames.LINE_NUMBER_COLORING);
0080:                    if (ctx.lineNumberColoring == null) {
0081:                        ctx.lineNumberColoring = ctx.defaultColoring; // no number
0082:                        // coloring
0083:                        // found
0084:
0085:                    } else { // lineNumberColoring not null
0086:                        ctx.lineNumberColoring = ctx.lineNumberColoring
0087:                                .apply(ctx.defaultColoring);
0088:                    }
0089:
0090:                    Font lnFont = ctx.lineNumberColoring.getFont();
0091:                    if (lnFont == null) {
0092:                        lnFont = ctx.defaultColoring.getFont();
0093:                    }
0094:
0095:                    Color lnBackColor = ctx.lineNumberColoring.getBackColor();
0096:                    if (lnBackColor == null) {
0097:                        lnBackColor = ctx.defaultColoring.getBackColor();
0098:                    }
0099:
0100:                    Color lnForeColor = ctx.lineNumberColoring.getForeColor();
0101:                    if (lnForeColor == null) {
0102:                        lnForeColor = ctx.defaultColoring.getForeColor();
0103:                    }
0104:
0105:                    ctx.lineNumberChars = new char[Math.max(
0106:                            ctx.editorUI.lineNumberMaxDigitCount, 1)];
0107:                    if (ctx.graphics == null) {
0108:                        ctx.syncedLineNumbering = true;
0109:
0110:                    } else { // non-synced line numbering - need to remember line start
0111:                        // offsets
0112:                        try {
0113:                            int endLineNumber = Utilities.getLineOffset(
0114:                                    ctx.doc, ctx.endOffset) + 1;
0115:                            ctx.lineStartOffsets = new int[endLineNumber
0116:                                    - ctx.startLineNumber + 2]; // reserve
0117:                            // more
0118:                        } catch (BadLocationException e) {
0119:                            if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
0120:                                e.printStackTrace();
0121:                            }
0122:                        }
0123:                    }
0124:                }
0125:            }
0126:
0127:            private void initInfo(DrawInfo ctx) throws BadLocationException {
0128:                ctx.x = ctx.startX;
0129:                ctx.y = ctx.startY;
0130:                ctx.lineHeight = ctx.editorUI.getLineHeight();
0131:                ctx.defaultColoring = ctx.editorUI.getDefaultColoring();
0132:                ctx.tabSize = ctx.doc.getTabSize();
0133:                ctx.fragmentOffset = ctx.startOffset; // actual painting position
0134:                ctx.graphics = ctx.drawGraphics.getGraphics();
0135:
0136:                if (ctx.graphics != null) {
0137:                    if (ctx.editorUI.renderingHints != null) {
0138:                        ((Graphics2D) ctx.graphics)
0139:                                .setRenderingHints(ctx.editorUI.renderingHints);
0140:                    }
0141:
0142:                    if (ctx.editorUI.textLimitLineVisible) { // draw limit line
0143:                        int lineX = ctx.startX + ctx.editorUI.textLimitWidth
0144:                                * ctx.editorUI.defaultSpaceWidth;
0145:                        ctx.graphics.setColor(ctx.editorUI.textLimitLineColor);
0146:                        Rectangle clip = ctx.graphics.getClipBounds();
0147:                        // ctx.graphics.drawRect(lineX, clip.y, 1, clip.height);
0148:                        ctx.graphics.drawLine(lineX, clip.y, lineX, clip.y
0149:                                + clip.height);
0150:                    }
0151:                }
0152:
0153:                initLineNumbering(ctx);
0154:
0155:                // Initialize draw context
0156:                ctx.foreColor = ctx.defaultColoring.getForeColor();
0157:                ctx.backColor = ctx.defaultColoring.getBackColor();
0158:                ctx.font = ctx.defaultColoring.getFont();
0159:                ctx.bol = true; // draw must always start at line begin
0160:
0161:                // Init draw graphics
0162:                ctx.drawGraphics.init(ctx);
0163:                ctx.drawGraphics.setDefaultBackColor(ctx.defaultColoring
0164:                        .getBackColor());
0165:                ctx.drawGraphics.setLineHeight(ctx.lineHeight);
0166:                ctx.drawGraphics.setLineAscent(ctx.editorUI.getLineAscent());
0167:                ctx.drawGraphics.setX(ctx.x);
0168:                ctx.drawGraphics.setY(ctx.y);
0169:
0170:                // Init all draw-layers
0171:                ctx.layers = ctx.editorUI.getDrawLayerList().currentLayers();
0172:                int layersLength = ctx.layers.length;
0173:                ctx.layerActives = new boolean[layersLength];
0174:                ctx.layerActivityChangeOffsets = new int[layersLength];
0175:
0176:                for (int i = 0; i < layersLength; i++) {
0177:                    ctx.layers[i].init(ctx); // init all layers
0178:                }
0179:
0180:                // Get all the draw marks in draw area through renderer
0181:                ctx.doc.op.renderMarks(ctx); // no synch needed
0182:
0183:                // Get current draw mark
0184:                ctx.drawMarkOffset = Integer.MAX_VALUE;
0185:                if (ctx.rangeMarkCount > 0) {
0186:                    ctx.drawMark = ctx.rangeDrawMarkArray[ctx.drawMarkIndex];
0187:                    ctx.drawMarkOffset = ctx.rangeOffsetArray[ctx.drawMarkIndex++];
0188:                    if (ctx.drawMarkOffset < ctx.updateOffset) {
0189:                        ctx.updateOffset = ctx.drawMarkOffset;
0190:                        ctx.drawMarkUpdate = true;
0191:                    }
0192:                }
0193:
0194:                // Prepare syntax scanner and then cycle through all the syntax segments
0195:                ctx.doc.op.prepareSyntax(ctx.slot, ctx.syntax, ctx.doc.op
0196:                        .getLeftSyntaxMark(ctx.startOffset), ctx.startOffset,
0197:                        ctx.endTokenMarkOffset - ctx.startOffset, false);
0198:
0199:                ctx.slotArray = ctx.slot.array;
0200:                ctx.buffer = ctx.slotArray;
0201:                ctx.bufferStartOffset = ctx.startOffset
0202:                        - ctx.syntax.getOffset();
0203:                ctx.drawGraphics.setBuffer(ctx.slotArray);
0204:
0205:                ctx.continueDraw = true;
0206:            }
0207:
0208:            private void handleBOL(DrawInfo ctx) {
0209:                if (ctx.lineNumbering) {
0210:                    if (ctx.syncedLineNumbering) {
0211:                        // Draw line numbers synchronously at begining of each line
0212:
0213:                        // Init context
0214:                        ctx.foreColor = ctx.lineNumberColoring.getForeColor();
0215:                        ctx.backColor = ctx.lineNumberColoring.getBackColor();
0216:                        ctx.font = ctx.lineNumberColoring.getFont();
0217:                        ctx.strikeThroughColor = null;
0218:                        ctx.underlineColor = null;
0219:
0220:                        int lineNumber = ctx.startLineNumber + ctx.lineIndex;
0221:                        // Update line-number by layers
0222:                        int layersLength = ctx.layers.length;
0223:                        for (int i = 0; i < layersLength; i++) {
0224:                            lineNumber = ctx.layers[i].updateLineNumberContext(
0225:                                    lineNumber, ctx);
0226:                        }
0227:
0228:                        // Fill the buffer with digit chars
0229:                        int i = Math.max(ctx.lineNumberChars.length - 1, 0);
0230:                        do {
0231:                            ctx.lineNumberChars[i--] = (char) ('0' + (lineNumber % 10));
0232:                            lineNumber /= 10;
0233:                        } while (lineNumber != 0 && i >= 0);
0234:
0235:                        // Fill the rest with spaces
0236:                        while (i >= 0) {
0237:                            ctx.lineNumberChars[i--] = ' ';
0238:                        }
0239:
0240:                        // Fill the DG's attributes and draw
0241:                        int numX = ctx.x - ctx.editorUI.lineNumberWidth;
0242:                        if (ctx.editorUI.lineNumberMargin != null) {
0243:                            numX += ctx.editorUI.lineNumberMargin.left;
0244:                        }
0245:                        ctx.drawGraphics.setX(numX);
0246:
0247:                        ctx.drawGraphics.setBuffer(ctx.lineNumberChars);
0248:                        ctx.drawGraphics.setForeColor(ctx.foreColor);
0249:                        ctx.drawGraphics.setBackColor(ctx.backColor);
0250:                        ctx.drawGraphics.setFont(ctx.font);
0251:                        ctx.drawGraphics.drawChars(0,
0252:                                ctx.lineNumberChars.length,
0253:                                ctx.editorUI.lineNumberWidth,
0254:                                ctx.strikeThroughColor, ctx.underlineColor);
0255:
0256:                        // When printing there should be an additional space between
0257:                        // line number and the text
0258:                        if (ctx.drawGraphics.getGraphics() == null) {
0259:                            ctx.drawGraphics.setBuffer(SPACE);
0260:                            ctx.drawGraphics.drawChars(0, 1,
0261:                                    ctx.editorUI.lineNumberDigitWidth, null,
0262:                                    null);
0263:                        }
0264:
0265:                        ctx.drawGraphics.setX(ctx.x);
0266:                        ctx.drawGraphics.setBuffer(ctx.slotArray);
0267:
0268:                    } else { // non-synced line numbering
0269:                        ctx.lineStartOffsets[ctx.lineIndex] = ctx.fragmentOffset; // store
0270:                        // the
0271:                        // line
0272:                        // number
0273:                    }
0274:                }
0275:
0276:                ctx.lineIndex++;
0277:            }
0278:
0279:            /** Handle the end-of-line */
0280:            private void handleEOL(DrawInfo ctx) {
0281:                ctx.drawGraphics.eol(); // sign EOL to DG
0282:                ctx.widestWidth = Math.max(ctx.widestWidth, ctx.x); // update widest
0283:                // width
0284:                ctx.visualColumn = 0;
0285:                ctx.x = ctx.startX;
0286:                ctx.y += ctx.lineHeight;
0287:
0288:                ctx.drawGraphics.setX(ctx.x);
0289:                ctx.drawGraphics.setY(ctx.y);
0290:
0291:            }
0292:
0293:            /**
0294:             * Called when the current fragment starts at the offset that corresponds to
0295:             * the update-offset.
0296:             */
0297:            private void updateOffsetReached(DrawInfo ctx) {
0298:                if (ctx.drawMarkUpdate) { // update because of draw mark
0299:                    // means no-mark update yet performed
0300:                    int layersLength = ctx.layers.length;
0301:                    for (int i = 0; i < layersLength; i++) {
0302:                        DrawLayer l = ctx.layers[i];
0303:                        if (l.getName().equals(ctx.drawMark.layerName)
0304:                                && (ctx.drawMark.isDocumentMark() || ctx.editorUI == ctx.drawMark
0305:                                        .getEditorUI())) {
0306:                            ctx.layerActives[i] = l.isActive(ctx, ctx.drawMark);
0307:                            int naco = l.getNextActivityChangeOffset(ctx);
0308:                            ctx.layerActivityChangeOffsets[i] = naco;
0309:                            if (naco > ctx.fragmentOffset
0310:                                    && naco < ctx.layerUpdateOffset) {
0311:                                ctx.layerUpdateOffset = naco;
0312:                            }
0313:                        }
0314:                    }
0315:
0316:                    // Get next mark
0317:                    if (ctx.drawMarkIndex < ctx.rangeMarkCount) {
0318:                        ctx.drawMark = ctx.rangeDrawMarkArray[ctx.drawMarkIndex];
0319:                        ctx.drawMarkOffset = ctx.rangeOffsetArray[ctx.drawMarkIndex++];
0320:
0321:                    } else { // no more draw marks
0322:                        ctx.drawMark = null;
0323:                        ctx.drawMarkOffset = Integer.MAX_VALUE;
0324:                    }
0325:
0326:                } else { // update because activity-change-offset set in some layer
0327:                    ctx.layerUpdateOffset = Integer.MAX_VALUE;
0328:                    int layersLength = ctx.layers.length;
0329:                    for (int i = 0; i < layersLength; i++) {
0330:                        // Update only layers with the same offset as fragmentOffset
0331:                        int naco = ctx.layerActivityChangeOffsets[i];
0332:                        if (naco == ctx.fragmentOffset) {
0333:                            DrawLayer l = ctx.layers[i];
0334:                            ctx.layerActives[i] = l.isActive(ctx, null);
0335:                            naco = l.getNextActivityChangeOffset(ctx);
0336:                            ctx.layerActivityChangeOffsets[i] = naco;
0337:                        }
0338:
0339:                        if (naco > ctx.fragmentOffset
0340:                                && naco < ctx.layerUpdateOffset) {
0341:                            ctx.layerUpdateOffset = naco;
0342:                        }
0343:                    }
0344:                }
0345:
0346:                // Check next update position
0347:                if (ctx.drawMarkOffset < ctx.layerUpdateOffset) {
0348:                    ctx.drawMarkUpdate = true;
0349:                    ctx.updateOffset = ctx.drawMarkOffset;
0350:
0351:                } else {
0352:                    ctx.drawMarkUpdate = false;
0353:                    ctx.updateOffset = ctx.layerUpdateOffset;
0354:                }
0355:
0356:            }
0357:
0358:            /** Compute the length of the fragment. */
0359:            private void computeFragmentLength(DrawInfo ctx) {
0360:                // Compute initial fragment (of token) length
0361:                ctx.fragmentStartIndex = ctx.fragmentOffset
0362:                        - ctx.bufferStartOffset;
0363:                ctx.fragmentLength = Math
0364:                        .min(ctx.updateOffset - ctx.fragmentOffset,
0365:                                ctx.tokenLength - ctx.drawnLength);
0366:
0367:                // Find first TAB or LF
0368:                int stopIndex = Analyzer.findFirstTabOrLF(ctx.slotArray,
0369:                        ctx.fragmentStartIndex, ctx.fragmentLength);
0370:
0371:                // There must be extra EOL at the end of the document
0372:                ctx.eol = (ctx.fragmentOffset == ctx.docLen);
0373:                ctx.tabsFragment = false;
0374:
0375:                // Check whether there are no tabs in the fragment and possibly shrink
0376:                // Get the first offset of the tab character or -1 if no tabs in
0377:                // fragment
0378:                if (stopIndex >= 0) { // either '\t' or '\n' found
0379:                    if (stopIndex == ctx.fragmentStartIndex) { // since fragment start
0380:                        if (ctx.slotArray[stopIndex] == '\t') { //
0381:                            ctx.tabsFragment = true;
0382:                            // Find first non-tab char
0383:                            int ntInd = Analyzer.findFirstNonTab(ctx.slotArray,
0384:                                    ctx.fragmentStartIndex, ctx.fragmentLength);
0385:
0386:                            if (ntInd != -1) { // not whole fragment are tabs
0387:                                ctx.fragmentLength = ntInd
0388:                                        - ctx.fragmentStartIndex;
0389:                            }
0390:
0391:                        } else { // '\n' found
0392:                            ctx.eol = true;
0393:                            ctx.fragmentLength = 1; // only one EOL in fragment
0394:                        }
0395:
0396:                    } else { // inside fragment start
0397:                        ctx.fragmentLength = stopIndex - ctx.fragmentStartIndex; // shrink
0398:                        // fragment
0399:                        // size
0400:                    }
0401:                }
0402:            }
0403:
0404:            /** Compute the display width of the fragment */
0405:            private void computeFragmentDisplayWidth(DrawInfo ctx) {
0406:                // First go through all layers to update draw context
0407:                // to get up-to-date fonts and colors
0408:                if (!ctx.eol) { // handled later
0409:                    int layersLength = ctx.layers.length;
0410:                    for (int i = 0; i < layersLength; i++) {
0411:                        DrawLayer l = ctx.layers[i];
0412:                        if (ctx.layerActives[i]) {
0413:                            ctx.layers[i].updateContext(ctx); // Let the layer to
0414:                            // update the context
0415:                        }
0416:                    }
0417:                }
0418:
0419:                // Handle possible white space expansion and compute display width
0420:                FontMetricsCache.Info fmcInfo = FontMetricsCache
0421:                        .getInfo(ctx.font);
0422:                ctx.spaceWidth = (ctx.component != null) ? fmcInfo
0423:                        .getSpaceWidth(ctx.component)
0424:                        : ctx.editorUI.defaultSpaceWidth;
0425:
0426:                // Compute real count of chars in fragment - can differ if tabs
0427:                ctx.fragmentCharCount = ctx.fragmentLength;
0428:                if (ctx.tabsFragment) { // tabs in fragment
0429:                    ctx.fragmentCharCount = Analyzer.getColumn(ctx.slotArray,
0430:                            ctx.fragmentStartIndex, ctx.fragmentLength,
0431:                            ctx.tabSize, ctx.visualColumn)
0432:                            - ctx.visualColumn;
0433:                    ctx.fragmentWidth = ctx.fragmentCharCount * ctx.spaceWidth;
0434:
0435:                } else if (ctx.eol) { // EOL will have the spaceWidth
0436:                    ctx.fragmentWidth = ctx.spaceWidth;
0437:
0438:                } else { // regular fragment
0439:                    if (ctx.fragmentLength > 0) {
0440:                        if (ctx.component != null) {
0441:                            ctx.fragmentWidth = FontMetricsCache
0442:                                    .getFontMetrics(ctx.font, ctx.component)
0443:                                    .charsWidth(ctx.slotArray,
0444:                                            ctx.fragmentStartIndex,
0445:                                            ctx.fragmentLength);
0446:
0447:                        } else { // non-valid component
0448:                            ctx.fragmentWidth = ctx.fragmentLength
0449:                                    * ctx.spaceWidth;
0450:                        }
0451:
0452:                    } else {
0453:                        ctx.fragmentWidth = 0; // empty fragment
0454:                    }
0455:                }
0456:
0457:            }
0458:
0459:            /**
0460:             * Draw the fragment. Handle the EOL in special way as it needs to care
0461:             * about the empty-lines.
0462:             */
0463:            private void drawFragment(DrawInfo ctx) {
0464:                if (ctx.eol) { // special handling for EOL
0465:                    int layersLength = ctx.layers.length;
0466:                    boolean emptyLine = false;
0467:                    int blankWidth = ctx.fragmentWidth;
0468:
0469:                    /**
0470:                     * Need to do one or two cycles. In the first pass the check is
0471:                     * performed whether the line is empty. If so all the layers that
0472:                     * extend the empty line are called to update the context and the
0473:                     * resulting half-space is drawn. In the second pass all the layers
0474:                     * that extend EOL are called to update the context and the
0475:                     * resulting whitespace is drawn.
0476:                     */
0477:                    do {
0478:                        blankWidth = 0;
0479:                        if (ctx.bol) { // empty line found
0480:                            if (!emptyLine) { // not yet processed
0481:                                for (int i = 0; i < layersLength; i++) {
0482:                                    if (ctx.layerActives[i]) {
0483:                                        DrawLayer l = ctx.layers[i];
0484:                                        if (l.extendsEmptyLine()) {
0485:                                            emptyLine = true; // for at least one
0486:                                            // layer
0487:                                            l.updateContext(ctx);
0488:                                        }
0489:                                    }
0490:                                }
0491:
0492:                                if (emptyLine) { // count only if necessary
0493:                                    blankWidth = ctx.spaceWidth / 2; // display half
0494:                                    // of char
0495:                                }
0496:                            } else { // already went through the cycle once for empty
0497:                                // line
0498:                                emptyLine = false;
0499:                            }
0500:                        }
0501:
0502:                        if (!emptyLine) { // EOL and currently not servicing empty
0503:                            // line
0504:                            boolean extendEOL = false;
0505:                            for (int i = 0; i < layersLength; i++) {
0506:                                if (ctx.layerActives[i]) {
0507:                                    DrawLayer l = ctx.layers[i];
0508:                                    if (l.extendsEOL()) {
0509:                                        extendEOL = true; // for at least one layer
0510:                                        l.updateContext(ctx);
0511:                                    }
0512:                                }
0513:                            }
0514:                            if (extendEOL && ctx.component != null) {
0515:                                blankWidth = ctx.component.getWidth();
0516:                            }
0517:                        }
0518:
0519:                        if (blankWidth > 0) {
0520:                            ctx.drawGraphics.setBackColor(ctx.backColor);
0521:                            ctx.drawGraphics.fillRect(blankWidth);
0522:                            if (emptyLine) {
0523:                                ctx.x += blankWidth;
0524:                            }
0525:                        }
0526:                    } while (emptyLine);
0527:
0528:                } else { // Draw regular fragment
0529:
0530:                    ctx.drawGraphics.setBackColor(ctx.backColor);
0531:                    ctx.drawGraphics.setForeColor(ctx.foreColor);
0532:                    ctx.drawGraphics.setFont(ctx.font);
0533:
0534:                    if (ctx.tabsFragment) {
0535:                        ctx.drawGraphics.drawTabs(ctx.fragmentStartIndex,
0536:                                ctx.fragmentLength, ctx.fragmentCharCount,
0537:                                ctx.fragmentWidth, ctx.strikeThroughColor,
0538:                                ctx.underlineColor);
0539:
0540:                    } else { // non-tabs
0541:                        ctx.drawGraphics.drawChars(ctx.fragmentStartIndex,
0542:                                ctx.fragmentLength, ctx.fragmentWidth,
0543:                                ctx.strikeThroughColor, ctx.underlineColor);
0544:                    }
0545:                }
0546:            }
0547:
0548:            /** Check whether the target offset was reached. */
0549:            private void checkTargetOffsetReached(DrawInfo ctx) {
0550:                ctx.continueDraw = true;
0551:
0552:                // Check whether at the end of the line
0553:                if (ctx.eol
0554:                        && (ctx.targetOffset == ctx.fragmentOffset || (ctx.targetOffset == -1))) {
0555:                    /**
0556:                     * Special case for the emulating the EOL at the end of the document
0557:                     * The EOL is emulated to process the layers that extend empty-line
0558:                     * or EOL
0559:                     */
0560:                    char ch = '\n';
0561:                    ctx.continueDraw = ctx.drawGraphics.targetOffsetReached(
0562:                            ctx.fragmentOffset, ch, ctx.x, ctx.spaceWidth, ctx);
0563:
0564:                    // Check whether targeting all characters
0565:                } else if (ctx.targetOffset == -1 && ctx.fragmentLength > 0 // Not sure
0566:                // whether
0567:                // it's
0568:                // necessary
0569:                ) { // When targeting all chars
0570:                    FontMetrics fm = FontMetricsCache.getFontMetrics(ctx.font,
0571:                            ctx.component);
0572:
0573:                    // Use binary search to find the right offset
0574:                    int low = -1;
0575:                    int high = ctx.fragmentLength - 1;
0576:
0577:                    // Cache the widths and first check whether past the end of fragment
0578:                    int lastMid = high;
0579:                    int lastWidth; // cache
0580:                    if (ctx.tabsFragment) { // fragment contains tabs
0581:                        int spaceCount = Analyzer.getColumn(ctx.slotArray,
0582:                                ctx.fragmentStartIndex, high, ctx.tabSize,
0583:                                ctx.visualColumn)
0584:                                - ctx.visualColumn;
0585:                        lastWidth = spaceCount * ctx.spaceWidth;
0586:
0587:                    } else { // no tabs inside fragment
0588:                        lastWidth = fm.charsWidth(ctx.slotArray,
0589:                                ctx.fragmentStartIndex, high);
0590:                    }
0591:
0592:                    int lastWidthP1; // plus one char
0593:                    if (ctx.tabsFragment) { // fragment contains tabs
0594:                        int spaceCount = Analyzer.getColumn(ctx.slotArray,
0595:                                ctx.fragmentStartIndex, ctx.fragmentLength,
0596:                                ctx.tabSize, ctx.visualColumn)
0597:                                - ctx.visualColumn;
0598:                        lastWidthP1 = spaceCount * ctx.spaceWidth;
0599:
0600:                    } else { // no tabs inside fragment
0601:                        lastWidthP1 = fm.charsWidth(ctx.slotArray,
0602:                                ctx.fragmentStartIndex, ctx.fragmentLength);
0603:                    }
0604:
0605:                    // Test whether the end of the fragment is accepted
0606:                    ctx.continueDraw = ctx.drawGraphics.targetOffsetReached(
0607:                            ctx.fragmentOffset + high,
0608:                            ctx.slotArray[ctx.fragmentStartIndex + high], ctx.x
0609:                                    + lastWidth, lastWidthP1 - lastWidth, ctx);
0610:
0611:                    if (!ctx.continueDraw) {
0612:                        // Binary search of the first offset that returns false follows
0613:                        while (low <= high) {
0614:                            int mid = (low + high) / 2;
0615:
0616:                            // Compute width that will be passed as x coordinate
0617:                            int width = 0;
0618:                            if (mid == lastMid + 1) { // try to use cached value
0619:                                width = lastWidthP1;
0620:
0621:                            } else {
0622:                                if (ctx.tabsFragment) { // fragment contains tabs
0623:                                    int spaceCount = Analyzer.getColumn(
0624:                                            ctx.slotArray,
0625:                                            ctx.fragmentStartIndex, mid,
0626:                                            ctx.tabSize, ctx.visualColumn)
0627:                                            - ctx.visualColumn;
0628:                                    width = spaceCount * ctx.spaceWidth;
0629:
0630:                                } else { // no tabs inside fragment
0631:                                    width = fm.charsWidth(ctx.slotArray,
0632:                                            ctx.fragmentStartIndex, mid);
0633:                                }
0634:                            }
0635:
0636:                            // Compute width plus one char and substract the previous
0637:                            // width
0638:                            // to get the width of the char
0639:                            int widthP1 = 0;
0640:                            if (mid == lastMid - 1) { // try to use cached value
0641:                                widthP1 = lastWidth;
0642:
0643:                            } else {
0644:                                if (ctx.tabsFragment) { // fragment contains tabs
0645:                                    int spaceCount = Analyzer.getColumn(
0646:                                            ctx.slotArray,
0647:                                            ctx.fragmentStartIndex, mid + 1,
0648:                                            ctx.tabSize, ctx.visualColumn)
0649:                                            - ctx.visualColumn;
0650:                                    widthP1 = spaceCount * ctx.spaceWidth;
0651:
0652:                                } else { // no tabs inside fragment
0653:                                    widthP1 = fm.charsWidth(ctx.slotArray,
0654:                                            ctx.fragmentStartIndex, mid + 1);
0655:                                }
0656:                            }
0657:
0658:                            lastWidth = width;
0659:                            lastWidthP1 = widthP1;
0660:                            lastMid = mid;
0661:
0662:                            ctx.continueDraw = ctx.drawGraphics
0663:                                    .targetOffsetReached(
0664:                                            ctx.fragmentOffset + mid,
0665:                                            ctx.slotArray[ctx.fragmentStartIndex
0666:                                                    + mid], ctx.x + width,
0667:                                            widthP1 - width, ctx);
0668:
0669:                            if (ctx.continueDraw) {
0670:                                low = mid + 1;
0671:                            } else {
0672:                                if (mid > low + 1) {
0673:                                    high = mid; // last that rejected
0674:
0675:                                } else { // mid = low + 1 -> mid is first rejected
0676:                                    break;
0677:                                }
0678:                            }
0679:                        }
0680:                    }
0681:
0682:                    // Check whether target offset is inside current fragment
0683:                } else if (ctx.targetOffset < ctx.fragmentOffset
0684:                        + ctx.fragmentLength
0685:                        && ctx.fragmentOffset <= ctx.targetOffset) {
0686:                    int curWidth;
0687:                    int prevWidth = 0;
0688:                    int i = (ctx.targetOffset - ctx.fragmentOffset);
0689:
0690:                    if (i > 0) {
0691:                        if (ctx.tabsFragment) { // fragment contains tabs
0692:                            int spaceCount = Analyzer.getColumn(ctx.slotArray,
0693:                                    ctx.fragmentStartIndex, i, ctx.tabSize,
0694:                                    ctx.visualColumn)
0695:                                    - ctx.visualColumn;
0696:                            prevWidth = spaceCount * ctx.spaceWidth;
0697:
0698:                        } else { // no tabs inside fragment
0699:                            prevWidth = FontMetricsCache.getFontMetrics(
0700:                                    ctx.font, ctx.component).charsWidth(
0701:                                    ctx.slotArray, ctx.fragmentStartIndex, i);
0702:                        }
0703:                    }
0704:
0705:                    if (ctx.tabsFragment) { // fragment contains tabs
0706:                        int spaceCount = Analyzer.getColumn(ctx.slotArray,
0707:                                ctx.fragmentStartIndex, i + 1, ctx.tabSize,
0708:                                ctx.visualColumn)
0709:                                - ctx.visualColumn;
0710:                        curWidth = spaceCount * ctx.spaceWidth;
0711:
0712:                    } else { // no tabs inside fragment
0713:                        curWidth = FontMetricsCache.getFontMetrics(ctx.font,
0714:                                ctx.component).charsWidth(ctx.slotArray,
0715:                                ctx.fragmentStartIndex, i + 1);
0716:                    }
0717:
0718:                    ctx.continueDraw = ctx.drawGraphics.targetOffsetReached(
0719:                            ctx.fragmentOffset + i,
0720:                            ctx.slotArray[ctx.fragmentStartIndex + i], ctx.x
0721:                                    + prevWidth, curWidth - prevWidth, ctx);
0722:                }
0723:            }
0724:
0725:            /** Draw current fragment of the token. */
0726:            private void drawCurrentTokenFragment(DrawInfo ctx) {
0727:                // Fill in the draw context
0728:                ctx.foreColor = ctx.defaultColoring.getForeColor();
0729:                ctx.backColor = ctx.defaultColoring.getBackColor();
0730:                ctx.font = ctx.defaultColoring.getFont();
0731:                ctx.strikeThroughColor = null;
0732:                ctx.underlineColor = null;
0733:
0734:                if (ctx.bol) { // if we are on the line begining
0735:                    handleBOL(ctx);
0736:                }
0737:
0738:                // Check for status updates in planes at the begining of this fragment
0739:                while (ctx.fragmentOffset == ctx.updateOffset) {
0740:                    updateOffsetReached(ctx); // while() because can be more marks at
0741:                    // same pos
0742:                }
0743:
0744:                // Compute the length of the fragment
0745:                computeFragmentLength(ctx);
0746:
0747:                // Compute the display width of the fragment
0748:                computeFragmentDisplayWidth(ctx);
0749:
0750:                // Draw the fragment
0751:                drawFragment(ctx);
0752:
0753:                if (debugFragment) {
0754:                    System.err.println("DrawEngine:   FRAGMENT='" // NOI18N
0755:                            + EditorDebug.debugChars(ctx.buffer,
0756:                                    ctx.fragmentStartIndex, ctx.fragmentLength)
0757:                            + "', at pos=" + ctx.fragmentOffset // NOI18N
0758:                            + ", bol=" + ctx.bol + ", eol=" + ctx.eol // NOI18N
0759:                    );
0760:                }
0761:
0762:                // Check whether target-offset was reached
0763:                if (ctx.component != null) {
0764:                    checkTargetOffsetReached(ctx);
0765:                }
0766:
0767:                // Move the variables to the next fragment in token
0768:                ctx.fragmentOffset += ctx.fragmentLength;
0769:                ctx.drawnLength += ctx.fragmentLength;
0770:                ctx.visualColumn += ctx.fragmentCharCount;
0771:                ctx.x += ctx.fragmentWidth;
0772:                ctx.bol = false;
0773:
0774:                // Update coordinates at the end of each line
0775:                if (ctx.eol) {
0776:                    handleEOL(ctx);
0777:                    ctx.bol = true; // now at BOL
0778:                }
0779:
0780:                if (ctx.fragmentOffset >= ctx.endOffset
0781:                        && ctx.endOffset < ctx.docLen) {
0782:                    ctx.continueDraw = false;
0783:                }
0784:            }
0785:
0786:            /**
0787:             * Draw one token. This is repeatedly called until all the tokens were
0788:             * drawn.
0789:             * 
0790:             * @return true when the drawing of the next token should be done or false
0791:             *         when the drawing should stop.
0792:             */
0793:            private void drawCurrentToken(DrawInfo ctx) {
0794:                // Get the token
0795:                if (ctx.tokenID != null) {
0796:                    ctx.tokenContextPath = ctx.syntax.getTokenContextPath();
0797:                    ctx.tokenOffset = ctx.syntax.getTokenOffset()
0798:                            + ctx.bufferStartOffset;
0799:                    ctx.tokenLength = ctx.syntax.getTokenLength();
0800:
0801:                    /*
0802:                     * Check whether the token isn't totally before the area to be
0803:                     * drawn. It must cover it at least by one character. For the more
0804:                     * complicated lexical analyzers it's possible that they return
0805:                     * several tokens that will cover only the prescan area.
0806:                     */
0807:                    if (ctx.tokenOffset + ctx.tokenLength <= ctx.startOffset) {
0808:                        return;
0809:                    }
0810:
0811:                } else { // end of drawing area
0812:                    ctx.tokenContextPath = null;
0813:                    ctx.tokenOffset = ctx.fragmentOffset;
0814:                    ctx.tokenLength = 0;
0815:                }
0816:
0817:                // Ask all the contexts first to possibly find out
0818:                // the first fragment length
0819:                if (ctx.tokenOffset <= ctx.startOffset) {
0820:                    ctx.layerUpdateOffset = Integer.MAX_VALUE;
0821:                    int layersLength = ctx.layers.length;
0822:                    for (int i = 0; i < layersLength; i++) { // update status of all
0823:                        // layers
0824:                        DrawLayer l = ctx.layers[i];
0825:                        ctx.layerActives[i] = l.isActive(ctx, null);
0826:
0827:                        int naco = l.getNextActivityChangeOffset(ctx);
0828:                        ctx.layerActivityChangeOffsets[i] = naco;
0829:                        if (naco > ctx.fragmentOffset
0830:                                && naco < ctx.layerUpdateOffset) {
0831:                            ctx.layerUpdateOffset = naco;
0832:                        }
0833:                    }
0834:                    ctx.updateOffset = Math.min(ctx.layerUpdateOffset,
0835:                            ctx.drawMarkOffset);
0836:                }
0837:
0838:                ctx.drawnLength = ctx.fragmentOffset - ctx.tokenOffset;
0839:                ctx.fragmentLength = 0; // length of current token fragment
0840:
0841:                if (debug) {
0842:                    System.err.println("DrawEngine: TOKEN='" // NOI18N
0843:                            + EditorDebug.debugChars(ctx.getBuffer(), ctx
0844:                                    .getTokenOffset()
0845:                                    - ctx.getBufferStartOffset(), ctx
0846:                                    .getTokenLength())
0847:                            + "', tokenID=<"
0848:                            + (ctx.getTokenID() == null ? "null" : ctx.tokenID
0849:                                    .getName()) // NOI18N
0850:                            + ">, tcp=" + ctx.getTokenContextPath() // NOI18N
0851:                            + ", pos=" + ctx.getTokenOffset() // NOI18N
0852:                    );
0853:                }
0854:
0855:                // Process all the fragments of one token
0856:                do {
0857:                    drawCurrentTokenFragment(ctx);
0858:                } while (ctx.continueDraw && ctx.drawnLength < ctx.tokenLength);
0859:
0860:            }
0861:
0862:            private void graphicsSpecificUpdates(DrawInfo ctx) {
0863:                Rectangle bounds = ctx.editorUI.getExtentBounds();
0864:                Rectangle clip = ctx.graphics.getClipBounds();
0865:                Insets textMargin = ctx.editorUI.getTextMargin();
0866:                int leftMarginWidth = textMargin.left
0867:                        - ctx.editorUI.lineNumberWidth
0868:                        - ctx.editorUI.textLeftMarginWidth;
0869:
0870:                // Draw line numbers bar and all the line nummbers
0871:                if (ctx.lineNumbering && !ctx.syncedLineNumbering) {
0872:                    Color lnBackColor = ctx.lineNumberColoring.getBackColor();
0873:                    int numY = ctx.startY;
0874:                    int lnBarX = bounds.x + leftMarginWidth;
0875:                    if (!lnBackColor.equals(ctx.defaultColoring.getBackColor())
0876:                            || bounds.x > 0) {
0877:                        ctx.graphics.setColor(lnBackColor);
0878:                        ctx.graphics.fillRect(lnBarX, numY,
0879:                                ctx.editorUI.lineNumberWidth, ctx.lineIndex
0880:                                        * ctx.lineHeight); // can't
0881:                        // use
0882:                        // dg
0883:                        // because
0884:                        // of
0885:                        // height
0886:                    }
0887:
0888:                    ctx.drawGraphics.setDefaultBackColor(lnBackColor); // will paint
0889:                    // into bar
0890:
0891:                    int lastDigitInd = Math.max(ctx.lineNumberChars.length - 1,
0892:                            0);
0893:                    int numX = lnBarX;
0894:                    if (ctx.editorUI.lineNumberMargin != null) {
0895:                        numX += ctx.editorUI.lineNumberMargin.left;
0896:                    }
0897:
0898:                    ctx.bol = true; //
0899:                    for (int j = 0; j < ctx.lineIndex; j++) { // draw all line numbers
0900:
0901:                        // Init the context
0902:                        ctx.fragmentOffset = ctx.lineStartOffsets[j];
0903:                        ctx.foreColor = ctx.lineNumberColoring.getForeColor();
0904:                        ctx.backColor = lnBackColor;
0905:                        ctx.font = ctx.lineNumberColoring.getFont();
0906:                        ctx.strikeThroughColor = null;
0907:                        ctx.underlineColor = null;
0908:
0909:                        int lineNumber = ctx.startLineNumber + j;
0910:                        // Update line-number by layers
0911:                        int layersLength = ctx.layers.length;
0912:                        for (int i = 0; i < layersLength; i++) {
0913:                            lineNumber = ctx.layers[i].updateLineNumberContext(
0914:                                    lineNumber, ctx);
0915:                        }
0916:
0917:                        int i = lastDigitInd;
0918:                        // Fill in the digit chars
0919:                        do {
0920:                            ctx.lineNumberChars[i--] = (char) ('0' + (lineNumber % 10));
0921:                            lineNumber /= 10;
0922:                        } while (lineNumber != 0 && i >= 0);
0923:                        // Fill in the spaces
0924:                        while (i >= 0) {
0925:                            ctx.lineNumberChars[i--] = ' ';
0926:                        }
0927:
0928:                        ctx.drawGraphics.setY(numY);
0929:                        ctx.drawGraphics.setBuffer(ctx.lineNumberChars);
0930:                        ctx.drawGraphics.setForeColor(ctx.foreColor);
0931:                        ctx.drawGraphics.setBackColor(ctx.backColor);
0932:                        ctx.drawGraphics.setFont(ctx.font);
0933:
0934:                        ctx.drawGraphics.setX(lnBarX);
0935:                        ctx.drawGraphics.fillRect(ctx.editorUI.lineNumberWidth);
0936:                        ctx.drawGraphics.setX(numX);
0937:
0938:                        ctx.drawGraphics.drawChars(0,
0939:                                ctx.lineNumberChars.length,
0940:                                ctx.lineNumberChars.length
0941:                                        * ctx.editorUI.lineNumberDigitWidth,
0942:                                ctx.strikeThroughColor, ctx.underlineColor);
0943:
0944:                        ctx.drawGraphics.setBuffer(null); // will do changes in buffer
0945:
0946:                        numY += ctx.lineHeight;
0947:                    }
0948:                }
0949:
0950:                // Clear margins
0951:                ctx.graphics.setColor(ctx.defaultColoring.getBackColor());
0952:
0953:                /**
0954:                 * The margin is cleared only in case the line is scrolled horizontally
0955:                 * and therefore the margin is dirty because of the previous text on the
0956:                 * line. Otherwise the margin is not cleared. The condition (bounds.x gt
0957:                 * 0) gives the answer.
0958:                 */
0959:                // Left margin
0960:                if (leftMarginWidth > 0 && bounds.x > 0) {
0961:                    ctx.graphics.fillRect(bounds.x, ctx.startY,
0962:                            leftMarginWidth, ctx.lineIndex * ctx.lineHeight);
0963:                }
0964:
0965:                // Text left margin
0966:                if (ctx.editorUI.textLeftMarginWidth > 0 && bounds.x > 0) {
0967:                    ctx.graphics.fillRect(bounds.x + textMargin.left
0968:                            - ctx.editorUI.textLeftMarginWidth, ctx.startY,
0969:                            ctx.editorUI.textLeftMarginWidth, ctx.lineIndex
0970:                                    * ctx.lineHeight);
0971:                }
0972:
0973:                // Right margin
0974:                if (textMargin.right > 0) {
0975:                    ctx.graphics.fillRect(bounds.x + bounds.width
0976:                            - textMargin.right, ctx.startY, textMargin.right,
0977:                            ctx.lineIndex * ctx.lineHeight);
0978:                }
0979:
0980:                // Top margin
0981:                /**
0982:                 * The margin is cleared only in case the extent bounds are high enough
0983:                 * so that the margin could be dirty because of drawing too much to the
0984:                 * right.
0985:                 */
0986:                if (textMargin.top > 0 && clip.y < bounds.y + textMargin.top) {
0987:                    ctx.graphics.fillRect(bounds.x, bounds.y, bounds.width,
0988:                            textMargin.top);
0989:                }
0990:
0991:                // Bottom margin
0992:                int bY = bounds.y + bounds.height - textMargin.bottom;
0993:                if (textMargin.bottom > 0 && clip.y + clip.height > bY) {
0994:                    ctx.graphics.fillRect(bounds.x, bY, bounds.width,
0995:                            textMargin.bottom);
0996:                }
0997:            }
0998:
0999:            /**
1000:             * Draw on the specified area.
1001:             * 
1002:             * @param drawGraphics
1003:             *            draw graphics through which the drawing is done
1004:             * @param editorUI
1005:             *            extended UI to use
1006:             * @param startOffset
1007:             *            position from which the drawing starts. It must BOL of the
1008:             *            first line to be drawn.
1009:             * @param endOffset
1010:             *            position where the drawing stops. It must be EOL of the last
1011:             *            line to be drawn.
1012:             * @param startX
1013:             *            x-coordinate at which the drawing starts
1014:             * @param startY
1015:             *            x-coordinate at which the drawing starts
1016:             * @param targetOffset
1017:             *            position where the targetOffsetReached() method of
1018:             *            drawGraphics is called. This is useful for caret update or
1019:             *            modelToView. The Integer.MAX_VALUE can be passed to ignore
1020:             *            that behavior. The -1 value has special meaning there so that
1021:             *            it calls targetOffsetReached() after each character processed.
1022:             *            This is used by viewToModel to find the position for some
1023:             *            point.
1024:             */
1025:            void draw(DrawGraphics drawGraphics, EditorUI editorUI,
1026:                    int startOffset, int endOffset, int startX, int startY,
1027:                    int targetOffset) throws BadLocationException {
1028:                // Some correctness tests at the begining
1029:                if (startOffset < 0 || endOffset < 0 || startOffset > endOffset
1030:                        || startX < 0 || startY < 0) {
1031:                    return;
1032:                }
1033:
1034:                if (debug) {
1035:                    System.err
1036:                            .println("DrawEngine:------------------ DRAWING ------------------------"); // NOI18N
1037:                }
1038:
1039:                // Draw-context and other info
1040:                DrawInfo ctx = new DrawInfo();
1041:                ctx.drawGraphics = drawGraphics;
1042:                ctx.editorUI = editorUI;
1043:                ctx.startOffset = startOffset;
1044:                ctx.endOffset = endOffset;
1045:                ctx.startX = startX;
1046:                ctx.startY = startY;
1047:                ctx.targetOffset = targetOffset;
1048:
1049:                synchronized (editorUI) { // lock operations manipulating draw layer
1050:                    // chain
1051:                    ctx.doc = editorUI.getDocument();
1052:                    if (ctx.doc == null) { // no base-document available
1053:                        return;
1054:                    }
1055:
1056:                    ctx.slot = SyntaxSeg.getFreeSlot();
1057:                    ctx.syntax = ctx.doc.getFreeSyntax();
1058:                    ctx.doc.readLock();
1059:
1060:                    try {
1061:                        ctx.component = editorUI.getComponent();
1062:                        ctx.docLen = ctx.doc.getLength();
1063:
1064:                        if (ctx.startOffset > ctx.docLen
1065:                                || ctx.endOffset > ctx.docLen) {
1066:                            return;
1067:                        }
1068:
1069:                        /*
1070:                         * Correct the ending position to be at the begining of the next
1071:                         * line. The only exception is when the endOffset is equal to
1072:                         * docLen.
1073:                         */
1074:                        if (ctx.endOffset < ctx.docLen) {
1075:                            ctx.endOffset++;
1076:                        }
1077:
1078:                        // Initialize the draw-info
1079:                        initInfo(ctx);
1080:
1081:                        // Cycle through all the tokens found in the buffer
1082:                        do {
1083:                            ctx.tokenID = ctx.syntax.nextToken();
1084:
1085:                            // Draw the current token
1086:                            drawCurrentToken(ctx);
1087:
1088:                        } while (ctx.continueDraw && ctx.tokenID != null);
1089:
1090:                        ctx.editorUI.updateVirtualWidth(ctx.widestWidth
1091:                                + ctx.editorUI.lineNumberWidth + 2
1092:                                * ctx.editorUI.defaultSpaceWidth);
1093:
1094:                        // When drawing to graphics, the line numbers and insets will be
1095:                        // drawn now
1096:                        if (ctx.graphics != null) {
1097:                            graphicsSpecificUpdates(ctx);
1098:                        }
1099:
1100:                    } finally {
1101:                        ctx.drawGraphics.setBuffer(null);
1102:                        ctx.drawGraphics.finish();
1103:
1104:                        ctx.doc.releaseSyntax(ctx.syntax);
1105:                        SyntaxSeg.releaseSlot(ctx.slot);
1106:                        ctx.doc.readUnlock();
1107:
1108:                    }
1109:                } // synchronized on editorUI
1110:            }
1111:
1112:            class DrawInfo extends DocMarks.Renderer implements  DrawContext {
1113:
1114:                // DrawContext -----------------------------------------------
1115:                /** Current foreground color. */
1116:                Color foreColor;
1117:
1118:                /** Current background color. */
1119:                Color backColor;
1120:
1121:                /** Current background color. */
1122:                Color underlineColor;
1123:
1124:                /** Color of the strike-through line or null. */
1125:                Color strikeThroughColor;
1126:
1127:                /** Current font. */
1128:                Font font;
1129:
1130:                /** Starting position of the drawing. */
1131:                int startOffset;
1132:
1133:                /** Ending position of the drawing. */
1134:                int endOffset;
1135:
1136:                /** Whether we are currently at the line begining. */
1137:                boolean bol;
1138:
1139:                /** Whether we are currently at the line end. */
1140:                boolean eol;
1141:
1142:                /** Editor-UI of the component for which we are drawing. */
1143:                EditorUI editorUI;
1144:
1145:                /** Buffer from which the chars are being drawn. */
1146:                char[] buffer;
1147:
1148:                /** Starting poisition of the buffer inside the document. */
1149:                int bufferStartOffset;
1150:
1151:                /** Token-id of the token being drawn. */
1152:                TokenID tokenID;
1153:
1154:                /** Token-context-path of the token being drawn. */
1155:                TokenContextPath tokenContextPath;
1156:
1157:                /** Position of the token in the document */
1158:                int tokenOffset;
1159:
1160:                /** Length of the token's text. */
1161:                int tokenLength;
1162:
1163:                /** Position of the fragment of the token being drawn in the document. */
1164:                int fragmentOffset;
1165:
1166:                /** Length of the fragment of the token in the document. */
1167:                int fragmentLength;
1168:
1169:                // Other variables ---------------------------------------------
1170:
1171:                /** Draw graphics */
1172:                DrawGraphics drawGraphics;
1173:
1174:                /**
1175:                 * Target document position for the drawing or -1 if all the positions
1176:                 * are the potential targets.
1177:                 */
1178:                int targetOffset;
1179:
1180:                /** Syntax-segment slot being used by drawing. */
1181:                SyntaxSeg.Slot slot;
1182:
1183:                /** Char array in the slot. */
1184:                char[] slotArray;
1185:
1186:                /** Syntax scanning the input. */
1187:                Syntax syntax;
1188:
1189:                /** Component being painted */
1190:                JTextComponent component;
1191:
1192:                /** Document of the component. */
1193:                BaseDocument doc;
1194:
1195:                /** Current length of the document */
1196:                int docLen;
1197:
1198:                /** Current visual column. */
1199:                int visualColumn;
1200:
1201:                /** Current x-coordinate. */
1202:                int x;
1203:
1204:                /** Current y-coordinate. */
1205:                int y;
1206:
1207:                /** Starting x-coordinate. */
1208:                int startX;
1209:
1210:                /** Starting y-coordinate. */
1211:                int startY;
1212:
1213:                /** Height of the line being drawn. */
1214:                int lineHeight;
1215:
1216:                /** Default coloring of the component. */
1217:                Coloring defaultColoring;
1218:
1219:                /** Size of the TAB character being drawn. */
1220:                int tabSize;
1221:
1222:                /** Widest width of the line that was painted. */
1223:                int widestWidth;
1224:
1225:                /** Whether the draw should continue or not. */
1226:                boolean continueDraw;
1227:
1228:                /** Line number of the first painted line. */
1229:                int startLineNumber;
1230:
1231:                /**
1232:                 * Index of the line being drawn. It is added to the startLineNumber to
1233:                 * form the resulting line number.
1234:                 */
1235:                int lineIndex;
1236:
1237:                /** Array of the start positions of all the lines drawn. */
1238:                int[] lineStartOffsets;
1239:
1240:                /**
1241:                 * Characters forming the line-number. It is reused for drawing all the
1242:                 * lines.
1243:                 */
1244:                char[] lineNumberChars;
1245:
1246:                /** Coloring for the line-number. */
1247:                Coloring lineNumberColoring;
1248:
1249:                /** Graphics object. It can be null when not drawing to the component. */
1250:                Graphics graphics;
1251:
1252:                /** Whether line-numbers are visible and allowed by the draw-graphics. */
1253:                boolean lineNumbering;
1254:
1255:                /**
1256:                 * Whether the line-numbers should be painted after each is painted. By
1257:                 * default the line-numbers are drawn as one block at the end of the
1258:                 * drawing.
1259:                 */
1260:                boolean syncedLineNumbering;
1261:
1262:                /** Array of the draw-layers to be used in the painting */
1263:                DrawLayer[] layers;
1264:
1265:                /** Whether the particular layer is currently active or not. */
1266:                boolean[] layerActives;
1267:
1268:                /**
1269:                 * Next position where the layer will be asked whether it's active or
1270:                 * not.
1271:                 */
1272:                int[] layerActivityChangeOffsets;
1273:
1274:                /**
1275:                 * Position where either the next draw-mark is or which matches the
1276:                 * activity-change-offset of one or more layers.
1277:                 */
1278:                int updateOffset;
1279:
1280:                /** Next activity-change-offset of one or more layers. */
1281:                int layerUpdateOffset;
1282:
1283:                /**
1284:                 * Update of the layers because of the draw-mark is at the given
1285:                 * position. False means the update is because the
1286:                 * activity-change-offset was reached.
1287:                 */
1288:                boolean drawMarkUpdate;
1289:
1290:                /** Current mark index in the rangeDrawMarkArray. */
1291:                int drawMarkIndex;
1292:
1293:                /** Current draw-mark */
1294:                MarkFactory.DrawMark drawMark;
1295:
1296:                /** Position of the current draw-mark */
1297:                int drawMarkOffset;
1298:
1299:                /** Length of the current token that was already drawn. */
1300:                int drawnLength;
1301:
1302:                /** Offset of the fragment starting character in the buffer */
1303:                int fragmentStartIndex;
1304:
1305:                /** Whether the fragment contains TABs only. */
1306:                boolean tabsFragment;
1307:
1308:                /** Width of one space character for the current context font. */
1309:                int spaceWidth;
1310:
1311:                /** Display width of the fragment */
1312:                int fragmentWidth;
1313:
1314:                /**
1315:                 * Number of characters that the fragment stands for. It can differ from
1316:                 * fragmentLength for tabsFragment.
1317:                 */
1318:                int fragmentCharCount;
1319:
1320:                /**
1321:                 * This is the offset of the first mark that follows the ending offset
1322:                 * of the drawing and in which the prescan is low enough so that it's
1323:                 * clear that the last token will not reach this offset. It's computed
1324:                 * by mark renderer.
1325:                 */
1326:                int endTokenMarkOffset;
1327:
1328:                // Doc-marks renderer ------------------------------------------
1329:
1330:                /** Array of draw-marks that were found in draw area. */
1331:                MarkFactory.DrawMark rangeDrawMarkArray[] = new MarkFactory.DrawMark[DEFAULT_DRAW_MARK_RENDERER_SIZE];
1332:
1333:                /**
1334:                 * Array of positions of the draw-marks that were found in the draw
1335:                 * area.
1336:                 */
1337:                int rangeOffsetArray[] = new int[DEFAULT_DRAW_MARK_RENDERER_SIZE];
1338:
1339:                /** Total count of found marks (and also positions) */
1340:                int rangeMarkCount;
1341:
1342:                public Color getForeColor() {
1343:                    return foreColor;
1344:                }
1345:
1346:                public void setForeColor(Color foreColor) {
1347:                    this .foreColor = foreColor;
1348:                }
1349:
1350:                public Color getBackColor() {
1351:                    return backColor;
1352:                }
1353:
1354:                public void setBackColor(Color backColor) {
1355:                    this .backColor = backColor;
1356:                }
1357:
1358:                public Color getUnderlineColor() {
1359:                    return underlineColor;
1360:                }
1361:
1362:                public void setUnderlineColor(Color underlineColor) {
1363:                    this .underlineColor = underlineColor;
1364:                }
1365:
1366:                public Color getStrikeThroughColor() {
1367:                    return strikeThroughColor;
1368:                }
1369:
1370:                public void setStrikeThroughColor(Color strikeThroughColor) {
1371:                    this .strikeThroughColor = strikeThroughColor;
1372:                }
1373:
1374:                public Font getFont() {
1375:                    return font;
1376:                }
1377:
1378:                public void setFont(Font font) {
1379:                    this .font = font;
1380:                }
1381:
1382:                public int getStartOffset() {
1383:                    return startOffset;
1384:                }
1385:
1386:                public int getEndOffset() {
1387:                    return endOffset;
1388:                }
1389:
1390:                public boolean isBOL() {
1391:                    return bol;
1392:                }
1393:
1394:                public boolean isEOL() {
1395:                    return eol;
1396:                }
1397:
1398:                public EditorUI getEditorUI() {
1399:                    return editorUI;
1400:                }
1401:
1402:                public char[] getBuffer() {
1403:                    return buffer;
1404:                }
1405:
1406:                public int getBufferStartOffset() {
1407:                    return bufferStartOffset;
1408:                }
1409:
1410:                public TokenID getTokenID() {
1411:                    return tokenID;
1412:                }
1413:
1414:                public TokenContextPath getTokenContextPath() {
1415:                    return tokenContextPath;
1416:                }
1417:
1418:                public int getTokenOffset() {
1419:                    return tokenOffset;
1420:                }
1421:
1422:                public int getTokenLength() {
1423:                    return tokenLength;
1424:                }
1425:
1426:                public int getFragmentOffset() {
1427:                    return fragmentOffset;
1428:                }
1429:
1430:                public int getFragmentLength() {
1431:                    return fragmentLength;
1432:                }
1433:
1434:                /** Render the marks to get all the draw-marks in a given range. */
1435:                public void render() {
1436:                    Mark mark = getMarks().getLeftMark(startOffset, null);
1437:                    rangeMarkCount = 0;
1438:                    Mark markArray[] = getMarkArray();
1439:                    int srcIndex = getMarkIndex(mark);
1440:                    int pos = getMarkOffset(mark);
1441:
1442:                    while (pos < startOffset) { // go to next mark
1443:                        srcIndex = getNextIndex(srcIndex);
1444:                        if (srcIndex >= getMarkArrayLength()) {
1445:                            break;
1446:                        }
1447:                        mark = markArray[srcIndex];
1448:                        pos = getMarkOffset(mark);
1449:                    }
1450:
1451:                    while (pos <= endOffset) { // will include even end-of-doc marks
1452:                        if (mark instanceof  MarkFactory.DrawMark) {
1453:                            MarkFactory.DrawMark dm = (MarkFactory.DrawMark) mark;
1454:                            if (!dm.removeInvalid()) { // remove if not valid
1455:                                // Check array ranges
1456:                                if (rangeOffsetArray.length < rangeMarkCount + 1) {
1457:                                    MarkFactory.DrawMark rma[] = new MarkFactory.DrawMark[2 * rangeDrawMarkArray.length];
1458:                                    System.arraycopy(rangeDrawMarkArray, 0,
1459:                                            rma, 0, rangeMarkCount);
1460:                                    rangeDrawMarkArray = rma;
1461:
1462:                                    int rpa[] = new int[rma.length];
1463:                                    System.arraycopy(rangeOffsetArray, 0, rpa,
1464:                                            0, rangeMarkCount);
1465:                                    rangeOffsetArray = rpa;
1466:                                }
1467:
1468:                                rangeDrawMarkArray[rangeMarkCount] = (MarkFactory.DrawMark) mark;
1469:                                rangeOffsetArray[rangeMarkCount++] = pos;
1470:                            }
1471:                        }
1472:                        srcIndex = getNextIndex(srcIndex);
1473:                        if (srcIndex < getMarkArrayLength()) {
1474:                            mark = markArray[srcIndex];
1475:                            pos = getMarkOffset(mark);
1476:                        } else {
1477:                            break;
1478:                        }
1479:                    }
1480:
1481:                    // Compute end token mark offset by searching for syntax-mark
1482:                    endTokenMarkOffset = docLen;
1483:                    while (true) {
1484:                        if (mark instanceof  MarkFactory.SyntaxMark) {
1485:                            MarkFactory.SyntaxMark sm = (MarkFactory.SyntaxMark) mark;
1486:                            Syntax.StateInfo si = sm.getStateInfo();
1487:                            if (si == null) {
1488:                                /*
1489:                                 * This is a situation where there's a long token at the
1490:                                 * end of the area to be drawn. Normally the
1491:                                 * prepareSyntax() should update some area around but if
1492:                                 * the token is long the stateinfo can be empty which is
1493:                                 * this situation. It has no sense to go on because all
1494:                                 * the following state infos are null. So in this case
1495:                                 * the the prepareSyntax() is made for the end of the
1496:                                 * document to be sure all the marks are updated. The
1497:                                 * slot must be (and it should be) empty at this time.
1498:                                 */
1499:                                try {
1500:                                    doc.op.prepareSyntax(slot, syntax, doc.op
1501:                                            .getLeftSyntaxMark(startOffset),
1502:                                            startOffset, pos - startOffset,
1503:                                            true);
1504:                                } catch (BadLocationException e) {
1505:                                    if (System
1506:                                            .getProperty("netbeans.debug.exceptions") != null) { // NOI18N
1507:                                        e.printStackTrace();
1508:                                    }
1509:                                }
1510:
1511:                                // Info in syntax mark should be non-null now
1512:                                si = sm.getStateInfo();
1513:                            }
1514:
1515:                            if (pos - si.getPreScan() > endOffset) {
1516:                                endTokenMarkOffset = pos; // Found lower end position
1517:                                break;
1518:                            }
1519:                        }
1520:
1521:                        // Get next mark or break
1522:                        srcIndex = getNextIndex(srcIndex);
1523:                        if (srcIndex < getMarkArrayLength()) {
1524:                            mark = markArray[srcIndex];
1525:                            pos = getMarkOffset(mark);
1526:
1527:                        } else {
1528:                            break;
1529:                        }
1530:                    }
1531:
1532:                }
1533:
1534:            }
1535:
1536:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.