Source Code Cross Referenced for ColorInputHandler.java in  » Scripting » oscript-2.10.4 » ti » swing » console » 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 » ti.swing.console 
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 modify
005:         *  it under the terms of the GNU General Public License as published by
006:         *  the Free Software Foundation; either version 2 of the License, or
007:         *  (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
012:         *  GNU General Public License for more details.
013:         * 
014:         *  You should have received a copy of the GNU General Public License
015:         *  along with this program; if not, write to the Free Software
016:         *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
017:         */
018:
019:        package ti.swing.console;
020:
021:        import java.awt.*;
022:        import java.awt.event.*;
023:        import java.util.Vector;
024:        import java.util.Hashtable;
025:        import java.util.Iterator;
026:        import java.util.LinkedList;
027:
028:        /**
029:         * An input handler which provides support for color, by use of escaped 
030:         * sequences of characters.  The escape character, and the format of the
031:         * escaped character sequences, is not well defined, so the static methods
032:         * {@link #fgColor}, {@link #bgColor}, and {@link #hyperlink} should be
033:         * used, for example:
034:         * <pre>
035:         *   // to make text with blue background, green foreground:
036:         *   out.println(
037:         *     ColorInputHandler.fgColor( Color.green,
038:         *       ColorInputHandler.bgColor( Color.blue, "Some Text" ) ) );
039:         *   
040:         *   // to make a hyperlink:
041:         *   out.println(
042:         *     ColorInputHandler.hyperlink( new Runnable() {
043:         *       public void run() {
044:         *         // do something here!
045:         *       }
046:         *     }, "Some Text" ) );
047:         * </pre>
048:         * Attributes can be combined and nested as needed.  Attributes created by
049:         * {@link #fgColor} and {@link #bgColor} are constant, and so the resulting
050:         * string can be reused, written to disk, read from disk, etc.  Attributes
051:         * created by {@link #hyperlink} are dynamic, and can only be used once for
052:         * each time they are created by calling {@link #hyperlink}.
053:         * 
054:         * @author Rob Clark
055:         * @version 0.1
056:         */
057:        public class ColorInputHandler extends InputAdapter {
058:            static final char ESCAPE_CHAR = 0x241b; // symbol for UNICODE escape, should be safe to use
059:
060:            static final char FGCOLOR_ATTR_OPEN = 1;
061:            static final char FGCOLOR_ATTR_CLOSE = 2;
062:            static final char BGCOLOR_ATTR_OPEN = 3;
063:            static final char BGCOLOR_ATTR_CLOSE = 4;
064:            static final char HYPERLINK_ATTR_OPEN = 5;
065:            static final char HYPERLINK_ATTR_CLOSE = 6;
066:
067:            /**
068:             * Table of runnables.  This is sorta cheezy, but an entry in the table is
069:             * populated when {@link #hyperlink} is called, and unpopulated when an
070:             * instance of this class encounters the corresponding open tag in the
071:             * input stream.  This means a hyperlink can only be written to a single
072:             * console.  It also means that there can only be a finite number of
073:             * hyperlinks created but not yet scaned by an instance of this class.  It
074:             * is possible that the implementation changes in the future if needed,
075:             * which is why the format of the attributes is not publicly defined.
076:             */
077:            private static Runnable[] runnables = new Runnable[64];
078:
079:            /* Attribute formats:
080:             *    fgColor:    ESCAPE_CHAR + FGCOLOR_ATTR_OPEN + r + g + b + <STR> + ESCAPE_CHAR + FGCOLOR_ATTR_CLOSE
081:             *    bgColor:    ESCAPE_CHAR + BGCOLOR_ATTR_OPEN + r + g + b + <STR> + ESCAPE_CHAR + BGCOLOR_ATTR_CLOSE
082:             *    hyperlink:  ESCAPE_CHAR + HYPERLINK_ATTR_OPEN + runnableIdx + <STR> + ESCAPE_CHAR + HYPERLINK_ATTR_CLOSE
083:             */
084:
085:            /**
086:             * The console we are part of.
087:             */
088:            private Console console;
089:
090:            /**
091:             * The state machine:
092:             */
093:            private State state;
094:
095:            /**
096:             * Class Constructor.
097:             * 
098:             * @param console      the console we are adding this input handler to
099:             */
100:            public ColorInputHandler(Console console) {
101:                super (console.getInputHandler());
102:
103:                this .console = console;
104:                this .state = NULL_STATE.reset();
105:
106:                HyperlinkMouseHandler hmh = new HyperlinkMouseHandler();
107:                console.addMouseListener(hmh);
108:                console.addMouseMotionListener(hmh);
109:            }
110:
111:            /*=======================================================================*/
112:
113:            /**
114:             * Create a string with a foreground color attribute applied.
115:             * 
116:             * @param c            the color to apply
117:             * @param str          the string to apply it to
118:             * @return a string with embedded control characters
119:             */
120:            public static String fgColor(Color c, String str) {
121:                if ((str == null) || (str.length() == 0))
122:                    return str;
123:
124:                StringBuffer sb = new StringBuffer(str.length() + 7);
125:
126:                sb.append(ESCAPE_CHAR);
127:                sb.append(FGCOLOR_ATTR_OPEN);
128:                sb.append((char) (c.getRed()));
129:                sb.append((char) (c.getGreen()));
130:                sb.append((char) (c.getBlue()));
131:                sb.append(str);
132:                sb.append(ESCAPE_CHAR);
133:                sb.append(FGCOLOR_ATTR_CLOSE);
134:
135:                return sb.toString();
136:            }
137:
138:            /**
139:             * Create a string with a background color attribute applied.
140:             * 
141:             * @param c            the color to apply
142:             * @param str          the string to apply it to
143:             * @return a string with embedded control characters
144:             */
145:            public static String bgColor(Color c, String str) {
146:                if ((str == null) || (str.length() == 0))
147:                    return str;
148:
149:                StringBuffer sb = new StringBuffer(str.length() + 7);
150:
151:                sb.append(ESCAPE_CHAR);
152:                sb.append(BGCOLOR_ATTR_OPEN);
153:                sb.append((char) (c.getRed()));
154:                sb.append((char) (c.getGreen()));
155:                sb.append((char) (c.getBlue()));
156:                sb.append(str);
157:                sb.append(ESCAPE_CHAR);
158:                sb.append(BGCOLOR_ATTR_CLOSE);
159:
160:                return sb.toString();
161:            }
162:
163:            /**
164:             * Create a string with a hyperlink.  Each time the user clicks the 
165:             * hyperlink, the runnable is invoked.  
166:             * 
167:             * @param r            the runnable to invoke when user clicks link
168:             * @param str          the string to apply it to
169:             * @return a string with embedded control characters
170:             */
171:            public static String hyperlink(Runnable r, String str) {
172:                return hyperlink(Color.cyan, r, str);
173:            }
174:
175:            /**
176:             * Create a string with a hyperlink.  Each time the user clicks the 
177:             * hyperlink, the runnable is invoked.  
178:             * 
179:             * @param c            the color to apply
180:             * @param r            the runnable to invoke when user clicks link
181:             * @param str          the string to apply it to
182:             * @return a string with embedded control characters
183:             */
184:            public static String hyperlink(Color c, Runnable r, String str) {
185:                if ((str == null) || (str.length() == 0))
186:                    return str;
187:
188:                synchronized (runnables) {
189:                    int idx = 0;
190:
191:                    while ((idx < runnables.length) && (runnables[idx] != null))
192:                        idx++;
193:
194:                    if (idx < runnables.length)
195:                        runnables[idx] = r;
196:
197:                    StringBuffer sb = new StringBuffer(str.length() + 12);
198:
199:                    sb.append(ESCAPE_CHAR);
200:                    sb.append(HYPERLINK_ATTR_OPEN);
201:                    sb.append((char) (idx));
202:
203:                    // inline this instead, to avoid an extra copy:
204:                    //    sb.append( fgColor( c, str ) );
205:                    sb.append(ESCAPE_CHAR);
206:                    sb.append(FGCOLOR_ATTR_OPEN);
207:                    sb.append((char) (c.getRed()));
208:                    sb.append((char) (c.getGreen()));
209:                    sb.append((char) (c.getBlue()));
210:                    sb.append(str);
211:                    sb.append(ESCAPE_CHAR);
212:                    sb.append(FGCOLOR_ATTR_CLOSE);
213:
214:                    sb.append(ESCAPE_CHAR);
215:                    sb.append(HYPERLINK_ATTR_CLOSE);
216:
217:                    return sb.toString();
218:                }
219:            }
220:
221:            /*=======================================================================*/
222:
223:            /**
224:             * Append characters to the end of the character stream.  Note that this
225:             * method is the entry point to a bunch of internal processing that is
226:             * not thread safe, so it is synchronized on the buffer lock.
227:             * 
228:             * @param cbuf         the character buffer
229:             * @param off          the offset into cbuf to first character to append
230:             * @param len          the number of characters to append
231:             */
232:            public void append(char[] cbuf, int off, int len) {
233:                synchronized (getBufferLock()) {
234:                    lock();
235:                    for (int i = 0; i < len; i++)
236:                        handle(cbuf[off + i]);
237:                    unlock();
238:                }
239:            }
240:
241:            private final void handle(char c) {
242:                state = state.handle(c);
243:            }
244:
245:            /*=======================================================================*/
246:
247:            /* The stacks for each of the attribute types.  These are stacks of attr
248:             * regions that have opened, but not yet closed, ie. we are still scanning
249:             * for the close tag.
250:             */
251:            private Vector fgAttrStack = new Vector();
252:            private Vector bgAttrStack = new Vector();
253:            private Vector hyperlinkStack = new Vector();
254:
255:            private void handleFgColorOpen(int r, int g, int b) {
256:                fgAttrStack.add(new ColorStartMarker(getFgColorAttr(new Color(
257:                        r, g, b)), getOffset()));
258:            }
259:
260:            private void handleFgColorClose() {
261:                int idx = fgAttrStack.size() - 1;
262:                ColorStartMarker m = (ColorStartMarker) (fgAttrStack.get(idx));
263:                fgAttrStack.remove(idx);
264:                int startOffset = m.getOffset();
265:                addRegion(m.getAttribute().getRegion(startOffset,
266:                        getOffset() - startOffset));
267:            }
268:
269:            private void handleBgColorOpen(int r, int g, int b) {
270:                bgAttrStack.add(new ColorStartMarker(getBgColorAttr(new Color(
271:                        r, g, b)), getOffset()));
272:            }
273:
274:            private void handleBgColorClose() {
275:                int idx = bgAttrStack.size() - 1;
276:                ColorStartMarker m = (ColorStartMarker) (bgAttrStack.get(idx));
277:                bgAttrStack.remove(idx);
278:                int startOffset = m.getOffset();
279:                addRegion(m.getAttribute().getRegion(startOffset,
280:                        getOffset() - startOffset));
281:            }
282:
283:            private void handleHyperlinkOpen(int idx) {
284:                Runnable r = null;
285:
286:                synchronized (runnables) {
287:                    if ((0 <= idx) && (idx < runnables.length)) {
288:                        r = runnables[idx];
289:                        runnables[idx] = null;
290:                    }
291:                }
292:
293:                hyperlinkStack.add(new HyperlinkStartMarker(r, getOffset()));
294:            }
295:
296:            private void handleHyperlinkClose() {
297:                int idx = hyperlinkStack.size() - 1;
298:                HyperlinkStartMarker m = (HyperlinkStartMarker) (hyperlinkStack
299:                        .get(idx));
300:                hyperlinkStack.remove(idx);
301:                int startOffset = m.getOffset();
302:                addRegion(new HyperlinkRegion(startOffset, getOffset()
303:                        - startOffset, m.getRunnable()));
304:            }
305:
306:            /*=======================================================================*/
307:
308:            private static class ColorStartMarker {
309:                private Attribute attr;
310:                private int offset;
311:
312:                ColorStartMarker(Attribute attr, int offset) {
313:                    this .attr = attr;
314:                    this .offset = offset;
315:                }
316:
317:                Attribute getAttribute() {
318:                    return attr;
319:                }
320:
321:                int getOffset() {
322:                    return offset;
323:                }
324:            }
325:
326:            private static class HyperlinkStartMarker {
327:                private Runnable r;
328:                private int offset;
329:
330:                HyperlinkStartMarker(Runnable r, int offset) {
331:                    this .r = r;
332:                    this .offset = offset;
333:                }
334:
335:                Runnable getRunnable() {
336:                    return r;
337:                }
338:
339:                int getOffset() {
340:                    return offset;
341:                }
342:            }
343:
344:            /*=======================================================================*/
345:
346:            /**
347:             * Region that is created to track a hyperlink in the console.  The
348:             * {@link HyperlinkMouseHandler} detects mouse clicks that intersect
349:             * regions of this type, in order to handle mouse clicks on hyperlink.
350:             */
351:            private static class HyperlinkRegion extends Region {
352:                private Runnable r;
353:
354:                HyperlinkRegion(int offset, int length, Runnable r) {
355:                    super (offset, length);
356:                    this .r = r;
357:                }
358:
359:                void mouseClicked(MouseEvent evt) {
360:                    if (r != null)
361:                        r.run();
362:                }
363:            }
364:
365:            /**
366:             * Mouse listener that looks for mouse clicks intersecting a
367:             * {@link HyperlinkRegion}
368:             */
369:            private class HyperlinkMouseHandler implements  MouseMotionListener,
370:                    MouseListener {
371:                private boolean inLink = false; // track current cursor state
372:
373:                public void mouseDragged(MouseEvent evt) {
374:                } // no-op
375:
376:                public void mousePressed(MouseEvent evt) {
377:                } // no-op
378:
379:                public void mouseReleased(MouseEvent evt) {
380:                } // no-op
381:
382:                public void mouseClicked(final MouseEvent evt) {
383:                    final LinkedList intersectingRegionList = new LinkedList();
384:
385:                    // since we don't want to process the mouse click while holding the
386:                    // region-iterator-lock, so copy them into a list so they can be
387:                    // handled after lock is released
388:                    synchronized (getBufferLock()) {
389:                        for (Iterator itr = getRegions(console.toOffset(evt
390:                                .getPoint()), 0); itr.hasNext();) {
391:                            Region r = (Region) (itr.next());
392:
393:                            if (r instanceof  HyperlinkRegion)
394:                                intersectingRegionList.add(r);
395:                        }
396:                    }
397:
398:                    for (Iterator itr = intersectingRegionList.iterator(); itr
399:                            .hasNext();)
400:                        ((HyperlinkRegion) (itr.next())).mouseClicked(evt);
401:                }
402:
403:                public void mouseMoved(MouseEvent evt) {
404:                    boolean currentlyInLink = false;
405:
406:                    synchronized (getBufferLock()) {
407:                        for (Iterator itr = getRegions(console.toOffset(evt
408:                                .getPoint()), 0); itr.hasNext();) {
409:                            Region r = (Region) (itr.next());
410:
411:                            if (r instanceof  HyperlinkRegion) {
412:                                currentlyInLink = true;
413:                                break;
414:                            }
415:                        }
416:                    }
417:
418:                    if (currentlyInLink != inLink) {
419:                        inLink = currentlyInLink;
420:
421:                        if (inLink)
422:                            console.setCursor(Cursor
423:                                    .getPredefinedCursor(Cursor.HAND_CURSOR));
424:                        else
425:                            console
426:                                    .setCursor(Cursor
427:                                            .getPredefinedCursor(Cursor.DEFAULT_CURSOR));
428:                    }
429:                }
430:
431:                public void mouseEntered(MouseEvent evt) {
432:                } // no-op
433:
434:                public void mouseExited(MouseEvent evt) {
435:                } // no-op
436:            }
437:
438:            /*=======================================================================*/
439:
440:            // Color attributes can be cached re-used:
441:            private static Hashtable fgColorAttrTable = new Hashtable();
442:
443:            private static Attribute getFgColorAttr(Color c) {
444:                Attribute attr = (Attribute) (fgColorAttrTable.get(c));
445:                if (attr == null) {
446:                    attr = new FgColorAttribute(c);
447:                    fgColorAttrTable.put(c, attr);
448:                }
449:                return attr;
450:            }
451:
452:            private static Hashtable bgColorAttrTable = new Hashtable();
453:
454:            private static Attribute getBgColorAttr(Color c) {
455:                Attribute attr = (Attribute) (bgColorAttrTable.get(c));
456:                if (attr == null) {
457:                    attr = new BgColorAttribute(c);
458:                    bgColorAttrTable.put(c, attr);
459:                }
460:                return attr;
461:            }
462:
463:            /*=======================================================================*/
464:
465:            /**
466:             * The state interface.  The state machine is used to implement scanning
467:             * the multiple character sequences used to control the attributes.  It
468:             * isn't use to handle matching up open/close control sequences, that is
469:             * done with the attribute stacks.
470:             */
471:            private abstract class State {
472:                private char[] cbuf = new char[1];
473:
474:                protected void write(char c) {
475:                    // note: access to this in synchronized in ColorInputHandler#append()
476:                    cbuf[0] = c;
477:                    ColorInputHandler.super .append(cbuf, 0, 1);
478:                }
479:
480:                abstract State handle(char c);
481:
482:                // if internal state needs to be reset, overload this:
483:                State reset() {
484:                    return this ;
485:                }
486:            }
487:
488:            private final State NULL_STATE = new State() {
489:
490:                State handle(char c) {
491:                    if (c == ESCAPE_CHAR)
492:                        return ESCAPE_STATE.reset();
493:
494:                    write(c);
495:                    return this ;
496:                }
497:
498:            };
499:
500:            private final State ESCAPE_STATE = new State() {
501:
502:                State handle(char c) {
503:                    switch (c) {
504:                    case FGCOLOR_ATTR_OPEN:
505:                        return FG_COLOR_OPEN_STATE.reset();
506:
507:                    case FGCOLOR_ATTR_CLOSE:
508:                        handleFgColorClose();
509:                        return NULL_STATE.reset();
510:
511:                    case BGCOLOR_ATTR_OPEN:
512:                        return BG_COLOR_OPEN_STATE.reset();
513:
514:                    case BGCOLOR_ATTR_CLOSE:
515:                        handleBgColorClose();
516:                        return NULL_STATE.reset();
517:
518:                    case HYPERLINK_ATTR_OPEN:
519:                        return HYPERLINK_OPEN_STATE.reset();
520:
521:                    case HYPERLINK_ATTR_CLOSE:
522:                        handleHyperlinkClose();
523:                        return NULL_STATE.reset();
524:
525:                    default:
526:                        // go back to null state, pass thru ESCAPE_CHAR in case it
527:                        // is used by a different InputHandler:
528:                        write(ESCAPE_CHAR);
529:                        write(c);
530:                        return NULL_STATE.reset();
531:                    }
532:                }
533:
534:            };
535:
536:            // to avoid a proliferation of state classes, a single fg/bg open
537:            // state class is used, but maintains some state internally...
538:            private abstract class ColorOpenState extends State {
539:                private int r;
540:                private int g;
541:                private int b;
542:
543:                State handle(char c) {
544:                    if (r == -1) {
545:                        r = (int) c;
546:                        return this ;
547:                    } else if (g == -1) {
548:                        g = (int) c;
549:                        return this ;
550:                    } else {
551:                        b = (int) c;
552:                        handle(r, g, b);
553:                        return NULL_STATE.reset();
554:                    }
555:                }
556:
557:                State reset() {
558:                    r = -1;
559:                    g = -1;
560:                    b = -1;
561:
562:                    return super .reset();
563:                }
564:
565:                protected abstract void handle(int r, int g, int b);
566:            }
567:
568:            private final State FG_COLOR_OPEN_STATE = new ColorOpenState() {
569:
570:                protected void handle(int r, int g, int b) {
571:                    handleFgColorOpen(r, g, b);
572:                }
573:
574:            };
575:
576:            private final State BG_COLOR_OPEN_STATE = new ColorOpenState() {
577:
578:                protected void handle(int r, int g, int b) {
579:                    handleBgColorOpen(r, g, b);
580:                }
581:
582:            };
583:
584:            private final State HYPERLINK_OPEN_STATE = new State() {
585:
586:                State handle(char c) {
587:                    int idx = (int) c;
588:                    handleHyperlinkOpen(idx);
589:                    return NULL_STATE.reset();
590:                }
591:
592:            };
593:
594:            public void close() {
595:                super .close();
596:            }
597:        }
598:
599:        /*
600:         *   Local Variables:
601:         *   tab-width: 2
602:         *   indent-tabs-mode: nil
603:         *   mode: java
604:         *   c-indentation-style: java
605:         *   c-basic-offset: 2
606:         *   eval: (c-set-offset 'substatement-open '0)
607:         *   eval: (c-set-offset 'case-label '+)
608:         *   eval: (c-set-offset 'inclass '+)
609:         *   eval: (c-set-offset 'inline-open '0)
610:         *   End:
611:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.