Source Code Cross Referenced for ODEEditorKit.java in  » Scripting » oscript-2.10.4 » oscript » swing » text » 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 » Scripting » oscript 2.10.4 » oscript.swing.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*=============================================================================
002:         *     Copyright Texas Instruments 2002.  All Rights Reserved.
003:         *   
004:         * This program is free software; you can redistribute it and/or
005:         * modify it under the terms of the GNU Lesser General Public
006:         * License as published by the Free Software Foundation; either
007:         * version 2 of the License, or (at your option) any later version.
008:         * 
009:         * This program is distributed in the hope that it will be useful,
010:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
011:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012:         * Lesser General Public License for more details.
013:         * 
014:         * You should have received a copy of the GNU Lesser General Public
015:         * License along with this library; if not, write to the Free Software
016:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
017:         * 
018:         * $ProjectHeader: OSCRIPT 0.155 Fri, 20 Dec 2002 18:34:22 -0800 rclark $
019:         */
020:
021:        package oscript.swing.text;
022:
023:        import oscript.data.*;
024:        import oscript.util.SymbolMap;
025:        import oscript.syntaxtree.NodeToken;
026:
027:        import java.util.*;
028:        import java.awt.Graphics;
029:        import java.awt.Color;
030:        import java.awt.Font;
031:        import javax.swing.text.*;
032:        import javax.swing.event.*;
033:        import javax.swing.undo.CompoundEdit;
034:
035:        /**
036:         * An editor-kit for an ODE src code editor.  The document used is just
037:         * a plain-old {@link PlainDocument}.  Rather than trying to integrate the 
038:         * parser with the {@link Document}'s {@link Element} structure, the parsed
039:         * representation of the document is stored seperately as an array of tokens.
040:         * We create a {@link View} for rendering the document that takes into account
041:         * the token that overlays a section of text, and the {@link AttributeSet}
042:         * which that token maps to, as it renders the text.
043:         * <p>
044:         * For performance reasons, parsing happens asynchronously, which means that
045:         * whenever the document is mutated.  So, when there is an insert, we update
046:         * the (now out of date) tokens by increasing the end-offset of the current
047:         * token, and the begin-offset and end-offset of all subsequent tokens by the
048:         * number of characters inserted.  When there is a remove, the process is 
049:         * essentially the reverse.
050:         * <p>
051:         * The script side of things handles creating the parsing thread, and it uses
052:         * {@link DocumentListener}s to determine when reparsing is needed.
053:         * 
054:         * @author Rob Clark (rob@ti.com)
055:         * <!--$Format: " * @version $Revision$"$-->
056:         * @version 1.10
057:         * @see #createDefaultDocument
058:         */
059:        public class ODEEditorKit extends DefaultEditorKit {
060:            private SymbolMap attrSetTable;
061:            private NodeToken[] nodeTokens = new NodeToken[0];
062:
063:            /**
064:             * Class Constructor.
065:             */
066:            public ODEEditorKit() {
067:                attrSetTable = new SymbolMap();
068:            }
069:
070:            /**
071:             * Set the attribute set table.
072:             * 
073:             * @param attrSetTable the table that maps NodeToken.kind to an attribute
074:             *    set.  This table is created and maintained from script code, but
075:             *    used here while rendering the text.
076:             */
077:            public void setAttributeSetTable(SymbolMap attrSetTable) {
078:                this .attrSetTable = attrSetTable;
079:            }
080:
081:            /**
082:             * Called from script code after parsing is completed.  For performance
083:             * reasons the tokens are stored here, after they are generated by script.
084:             */
085:            public synchronized void setNodeTokens(Vector v) {
086:                NodeToken[] newNodeTokens = new NodeToken[v.size()];
087:                v.copyInto(newNodeTokens);
088:                nodeTokens = newNodeTokens;
089:            }
090:
091:            /**
092:             * Get a factory for producing {@link View}s for rendering {@link Document}s
093:             * created by this editor-kit.
094:             * 
095:             * @return the view-factory
096:             */
097:            public ViewFactory getViewFactory() {
098:                return new ViewFactory() {
099:                    public View create(Element elem) {
100:                        return new NodeTokenView(elem);
101:                    }
102:                };
103:            }
104:
105:            /**
106:             * Create a uninitialized document.  The {@link Document} used by this editor
107:             * kit is basically just a {@link PlainDocument} that has been extended to
108:             * synchronously update the offsets of the tokens in response to document
109:             * mutations (insert/remove).  This is important to ensure that the token's
110:             * offset maps to sensible positions in the document during the period between
111:             * when the document is edited, and when the parser has finished re-parsing it
112:             * 
113:             * @return an unitialized document
114:             */
115:            public Document createDefaultDocument() {
116:                return new ODEDocument();
117:            }
118:
119:            public class ODEDocument extends PlainDocument {
120:                private long lastMutateTime;
121:
122:                public long getLastMutateTime() {
123:                    return lastMutateTime;
124:                }
125:
126:                private int undoableSequenceLevel = 0;
127:                private CompoundEdit undoableSequence = null;
128:
129:                /**
130:                 * All document updates performed by the runnable result in a single
131:                 * undo event.  This call gate provides a way to coalesce multiple
132:                 * insert/remove mutates into a single undoable event.
133:                 */
134:                public void performUndoableSequence(Runnable r) {
135:                    synchronized (ODEEditorKit.this ) {
136:                        undoableSequenceLevel++;
137:                        r.run();
138:                        undoableSequenceLevel--;
139:
140:                        if ((undoableSequenceLevel == 0)
141:                                && (undoableSequence != null)) {
142:                            undoableSequence.end();
143:                            super .fireUndoableEditUpdate(new UndoableEditEvent(
144:                                    this , undoableSequence));
145:                            undoableSequence = null;
146:                        }
147:                    }
148:                }
149:
150:                private CompoundEdit getUndoableSequence() {
151:                    if (undoableSequence == null) {
152:                        undoableSequence = new CompoundEdit();
153:                        //          super.fireUndoableEditUpdate( new UndoableEditEvent( this, undoableSequence ) );
154:                    }
155:                    return undoableSequence;
156:                }
157:
158:                protected void fireUndoableEditUpdate(UndoableEditEvent evt) {
159:                    synchronized (ODEEditorKit.this ) {
160:                        if (undoableSequenceLevel > 0)
161:                            getUndoableSequence().addEdit(evt.getEdit());
162:                        else
163:                            super .fireUndoableEditUpdate(evt);
164:                    }
165:                }
166:
167:                /**
168:                 * Get a reader that returns the contents of this document
169:                 */
170:                public java.io.Reader getDocumentReader() {
171:                    return new java.io.Reader() {
172:
173:                        private int idx = 0;
174:
175:                        public int read(char[] cbuf, int off, int len)
176:                                throws java.io.IOException {
177:                            try {
178:                                len = Math.min(len, getLength() - idx);
179:                                len = Math.min(len, 128); // minimize size of actual read to lessen impact of crossing gap
180:                                System.arraycopy(getText(idx, len)
181:                                        .toCharArray(), 0, cbuf, off, len);
182:                                idx += len;
183:
184:                                if (len == 0)
185:                                    return -1;
186:
187:                                return len;
188:                            } catch (BadLocationException e) {
189:                                throw new java.io.IOException("bad location: "
190:                                        + e.getMessage());
191:                            }
192:                        }
193:
194:                        public void close() {
195:                        }
196:
197:                    };
198:                }
199:
200:                /* Possibly could do something clever here, and queue up "deltas",
201:                 * and not process them until the next time getToken() is called
202:                 * (possibly only if off > queued_offs[0])
203:                 */
204:
205:                public void remove(int off, int len)
206:                        throws BadLocationException {
207:                    synchronized (ODEEditorKit.this ) {
208:                        lastMutateTime = System.currentTimeMillis();
209:
210:                        // deal with bogus removes here... it is kind of a hack, but
211:                        // easier than dealing with it at all the places that call
212:                        // remove!
213:                        off = Math.max(off, 0);
214:                        len = Math.min(off + len, getLength()) - off;
215:
216:                        updateRemove(off, len);
217:                        super .remove(off, len);
218:                    }
219:                }
220:
221:                public void insertString(int off, String str, AttributeSet a)
222:                        throws BadLocationException {
223:                    synchronized (ODEEditorKit.this ) {
224:                        lastMutateTime = System.currentTimeMillis();
225:
226:                        updateInsert(off, str.length());
227:                        super .insertString(off, str, a);
228:                    }
229:                }
230:            }
231:
232:            private synchronized void updateInsert(int off, int len) {
233:                NodeToken nt = getToken(off);
234:                if (nt != null) {
235:                    // kinda weird how we do this, but this way we don't get gaps between
236:                    // adjacent node-tokens as we iterate which might screw up getToken()
237:                    LinkedList tokenList = new LinkedList();
238:                    tokenList.add(nt);
239:                    while ((nt = getToken(nt.endOffset + 1)) != null)
240:                        tokenList.add(nt);
241:
242:                    Iterator itr = tokenList.iterator();
243:                    ((NodeToken) (itr.next())).endOffset += len;
244:
245:                    while (itr.hasNext()) {
246:                        nt = (NodeToken) (itr.next());
247:                        nt.beginOffset += len;
248:                        nt.endOffset += len;
249:                    }
250:                }
251:            }
252:
253:            private final synchronized void updateRemove(int off, int len) {
254:                NodeToken nt = getToken(off - len);
255:                if (nt != null) {
256:                    int totalSub = 0;
257:
258:                    // kinda weird how we do this, but this way we don't get gaps between
259:                    // adjacent node-tokens as we iterate which might screw up getToken()
260:                    LinkedList tokenList = new LinkedList();
261:                    tokenList.add(nt);
262:                    while ((nt = getToken(nt.endOffset + 1)) != null)
263:                        tokenList.add(nt);
264:
265:                    for (Iterator itr = tokenList.iterator(); itr.hasNext();) {
266:                        nt = (NodeToken) (itr.next());
267:
268:                        // don't want to move endOffset past current offset, so
269:                        // figure out how much to subtract, and roll-over the
270:                        // rest:
271:                        int sub = len - Math.max(0, off + len - nt.endOffset);
272:                        len -= sub;
273:                        off += sub;
274:
275:                        nt.beginOffset -= totalSub;
276:                        totalSub += sub;
277:                        nt.endOffset -= totalSub;
278:                    }
279:                }
280:            }
281:
282:            /**
283:             * The {@link View} implementation.  Basically just a {@link PlainView} that 
284:             * changes the attribute-set for different node tokens within the view as it 
285:             * renders.
286:             */
287:            private class NodeTokenView extends PlainView {
288:                private Segment text = new Segment();
289:
290:                /**
291:                 * Class Constructor.
292:                 */
293:                NodeTokenView(Element elem) {
294:                    super (elem);
295:                }
296:
297:                /**
298:                 * Renders the given range in the model as normal unselected
299:                 * text.  Uses the foreground or disabled color to render the text.
300:                 *
301:                 * @param g the graphics context
302:                 * @param x the starting X coordinate >= 0
303:                 * @param y the starting Y coordinate >= 0
304:                 * @param p0 the beginning position in the model >= 0
305:                 * @param p1 the ending position in the model >= 0
306:                 * @returns the X location of the end of the range >= 0
307:                 * @exception BadLocationException if the range is invalid
308:                 */
309:                protected synchronized int drawUnselectedText(Graphics g,
310:                        int x, int y, int p0, int p1)
311:                        throws BadLocationException {
312:                    if ((nodeTokens == null) || (nodeTokens.length == 0))
313:                        return super .drawUnselectedText(g, x, y, p0, p1);
314:
315:                    Document doc = getDocument();
316:                    int p = p0;
317:                    int kind = -1;
318:
319:                    while (p < p1) {
320:                        NodeToken nt = getToken(p);
321:                        int mark;
322:
323:                        if (nt == null) {
324:                            setKind(g, -1);
325:                            mark = p1;
326:                        } else {
327:                            if (kind != nt.kind)
328:                                setKind(g, kind = nt.kind);
329:                            mark = Math.min(nt.endOffset + 1, p1);
330:                        }
331:
332:                        if (mark > p) {
333:                            doc.getText(p, mark - p, text);
334:                            x = Utilities.drawTabbedText(text, x, y, g, this ,
335:                                    mark);
336:                        }
337:
338:                        p = mark;
339:                    }
340:
341:                    return x;
342:                }
343:
344:                private void setKind(Graphics g, int kind) {
345:                    if (kind >= oscript.util.SymbolTable.MIN_SYMBOL_ID) {
346:                        AttributeSet attrSet = (AttributeSet) (attrSetTable
347:                                .get(kind));
348:
349:                        // other attributes?  how to handle background color?
350:                        g.setColor(getFgColor(attrSet));
351:                        g.setFont(getFont(g.getFont(), attrSet));
352:                    } else {
353:                        g.setColor(Color.black);
354:                    }
355:                }
356:            }
357:
358:            private static Color defaultFgColor = Color.black;
359:
360:            public static void setDefaultFgColor(Color c) {
361:                defaultFgColor = c;
362:            }
363:
364:            /**
365:             * Given an attribute set, get the foreground color
366:             */
367:            private static Color getFgColor(AttributeSet attrSet) {
368:                Color c = null;
369:
370:                if (attrSet != null)
371:                    c = (Color) (attrSet
372:                            .getAttribute(StyleConstants.Foreground));
373:
374:                if (c == null)
375:                    c = defaultFgColor;
376:
377:                return c;
378:            }
379:
380:            /**
381:             * All editor-kits share a common font cache, keyed by an instance of
382:             * {@link FontCacheKey}.
383:             */
384:            private static Hashtable fontCache = new Hashtable();
385:
386:            private static class FontCacheKey {
387:                private String name;
388:                private int style;
389:                private int size;
390:                private int hash;
391:
392:                FontCacheKey(String name, int style, int size) {
393:                    this .name = name;
394:                    this .style = style;
395:                    this .size = size;
396:
397:                    hash = name.hashCode() ^ ((style << 16) | size);
398:                }
399:
400:                public int hashCode() {
401:                    return hash;
402:                }
403:
404:                public boolean equals(Object obj) {
405:                    return (obj instanceof  FontCacheKey)
406:                            && (((FontCacheKey) obj).hash == hash)
407:                            && ((FontCacheKey) obj).name.equals(name)
408:                            && (((FontCacheKey) obj).style == style)
409:                            && (((FontCacheKey) obj).size == size);
410:                }
411:            }
412:
413:            /**
414:             * Given an attribute set, get the font.  For performance reasons,
415:             * this avoids re-instantiating fonts, and caches fonts keys by 
416:             * &lt; name, style size &gt;.  (Use of Font#deriveFont() would be
417:             * easier, but is buggy on early versions of java v1.4 on macosx)
418:             */
419:            private static Font getFont(Font origFont, AttributeSet attrSet) {
420:                int style = Font.PLAIN;
421:
422:                if (attrSet != null) {
423:                    Integer val = (Integer) (attrSet.getAttribute("style"));
424:                    if (val != null)
425:                        style = val.intValue();
426:                }
427:
428:                Object key = new FontCacheKey(origFont.getName(), style,
429:                        origFont.getSize());
430:                Font font = (Font) (fontCache.get(key));
431:
432:                if (font == null) {
433:                    font = new Font(origFont.getName(), style, origFont
434:                            .getSize());
435:                    fontCache.put(key, font);
436:                }
437:
438:                return font;
439:            }
440:
441:            // XXX others... getBgColor, getFont, etc
442:
443:            /* 
444:             * This can be cleaned up significantly with something that produces an
445:             * Iterator interface.
446:             */
447:
448:            /**
449:             * Given an offset into the document, find the corresponding token.
450:             * This is the API used by everything else for accessing the tokens.
451:             * The remaining methods are just used to implement this method.
452:             * 
453:             * @param off          the offset into the document
454:             */
455:            public synchronized NodeToken getToken(int off) {
456:                // check the current and next token first, otherwise revert to search:
457:                if ((0 <= idx) && (idx < nodeTokens.length)) {
458:                    if (off >= nodeTokens[idx].getActualBeginOffset()) {
459:                        if (off <= nodeTokens[idx].endOffset)
460:                            return getActualToken(nodeTokens[idx], off);
461:                        else if ((++idx < nodeTokens.length)
462:                                && (off <= nodeTokens[idx].endOffset))
463:                            return getActualToken(nodeTokens[idx], off);
464:                    }
465:                }
466:
467:                idx = findTokenIndex(off);
468:
469:                if ((0 <= idx) && (idx < nodeTokens.length))
470:                    return getActualToken(nodeTokens[idx], off);
471:                return null;
472:            }
473:
474:            private int idx = 0; // cache last access, to speed next one
475:
476:            // given a regular token, and off, determine the actual token (ie.
477:            // regular or special)
478:            private static NodeToken getActualToken(NodeToken node, int off) {
479:                for (int i = 0; i < node.numSpecials(); i++)
480:                    if (node.getSpecialAt(i).endOffset >= off)
481:                        return node.getSpecialAt(i);
482:                if (node.endOffset >= off)
483:                    return node;
484:                return null;
485:            }
486:
487:            // find index of regular token containing off
488:            private int findTokenIndex(int off) {
489:                int a = 0;
490:                int b = nodeTokens.length;
491:                int idx = 0;
492:
493:                while (a < b) {
494:                    idx = (a + b) / 2;
495:
496:                    // there can be gaps between tokens, so we need to use the
497:                    // end-offset of the prev token:
498:                    int bo = (idx > 0) ? nodeTokens[idx - 1].endOffset : 0;
499:                    int eo = nodeTokens[idx].endOffset;
500:
501:                    if (off < bo)
502:                        b = idx;
503:                    else if (off > eo)
504:                        a = idx + 1;
505:                    else
506:                        break;
507:                }
508:
509:                return idx;
510:            }
511:
512:            // for debug
513:            public String offsetToNodeToken(int off) {
514:
515:                NodeToken nt = getToken(off);
516:                return "{image=\"" + nt + "\", kind="
517:                        + oscript.parser.OscriptParser.getTokenString(nt.kind)
518:                        + "}";
519:            }
520:        }
521:
522:        /*
523:         *   Local Variables:
524:         *   tab-width: 2
525:         *   indent-tabs-mode: nil
526:         *   mode: java
527:         *   c-indentation-style: java
528:         *   c-basic-offset: 2
529:         *   eval: (c-set-offset 'substatement-open '0)
530:         *   eval: (c-set-offset 'case-label '+)
531:         *   eval: (c-set-offset 'inclass '+)
532:         *   eval: (c-set-offset 'inline-open '0)
533:         *   End:
534:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.