001: package com.opensymphony.workflow.designer.swing;
002:
003: import java.awt.*;
004: import java.io.IOException;
005: import java.io.Reader;
006: import java.util.*;
007: import javax.swing.*;
008: import javax.swing.text.*;
009:
010: import com.Ostermiller.Syntax.Lexer.JavaLexer;
011: import com.Ostermiller.Syntax.Lexer.Lexer;
012: import com.Ostermiller.Syntax.Lexer.Token;
013:
014: /**
015: * User: Hani Suleiman
016: * Date: Jan 6, 2004
017: * Time: 4:19:18 PM
018: */
019: public class JavaTextPane extends JTextPane {
020: /**
021: * A hash table containing the text styles.
022: * Simple attribute sets are hashed by name (String)
023: */
024: private static StyleContext styleContext = new StyleContext();
025: static {
026: initStyles();
027: }
028: /**
029: * the styled document that is the model for
030: * the textPane
031: */
032: protected HighLightedDocument document;
033: /**
034: * A reader wrapped around the document
035: * so that the document can be fed into
036: * the lexer.
037: */
038: protected DocumentReader documentReader;
039: /**
040: * The lexer that tells us what colors different
041: * words should be.
042: */
043: protected Lexer syntaxLexer;
044: /** A thread that handles the actual coloring. */
045: protected Colorer colorer;
046: /**
047: * A lock for modifying the document, or for
048: * actions that depend on the document not being
049: * modified.
050: */
051: private Object doclock = new Object();
052:
053: public JavaTextPane() {
054: super ();
055: document = new HighLightedDocument(styleContext);
056: setDocument(document);
057: setCaretPosition(0);
058: setMargin(new Insets(5, 5, 5, 5));
059: colorer = new Colorer();
060: colorer.start();
061: // create the new document.
062: documentReader = new DocumentReader(this .document);
063:
064: syntaxLexer = new JavaLexer(documentReader);
065: }
066:
067: /**
068: * Run the Syntax Highlighting as a separate thread.
069: * Things that need to be colored are messaged to the
070: * thread and put in a list.
071: */
072: private class Colorer extends Thread {
073:
074: /**
075: * Keep a list of places in the file that it is safe to restart the
076: * highlighting. This happens whenever the lexer reports that it has
077: * returned to its initial state. Since this list needs to be sorted
078: * and we need to be able to retrieve ranges from it, it is stored in a
079: * balanced tree.
080: */
081: private TreeSet iniPositions = new TreeSet(
082: new DocPositionComparator());
083:
084: /**
085: * As we go through and remove invalid positions we will also be finding
086: * new valid positions.
087: * Since the position list cannot be deleted from and written to at the same
088: * time, we will keep a list of the new positions and simply add it to the
089: * list of positions once all the old positions have been removed.
090: */
091: private HashSet newPositions = new HashSet();
092:
093: /**
094: * A simple wrapper representing something that needs to be colored.
095: * Placed into an object so that it can be stored in a Vector.
096: */
097: private class RecolorEvent {
098: public int position;
099: public int adjustment;
100:
101: public RecolorEvent(int position, int adjustment) {
102: this .position = position;
103: this .adjustment = adjustment;
104: }
105: }
106:
107: /** Vector that stores the communication between the two threads. */
108: private volatile Vector v = new Vector();
109:
110: /**
111: * The amount of change that has occurred before the place in the
112: * document that we are currently highlighting (lastPosition).
113: */
114: private volatile int change = 0;
115:
116: /** The last position colored */
117: private volatile int lastPosition = -1;
118:
119: private volatile boolean asleep = false;
120:
121: /**
122: * When accessing the vector, we need to create a critical section.
123: * we will synchronize on this object to ensure that we don't get
124: * unsafe thread behavior.
125: */
126: private Object lock = new Object();
127:
128: /**
129: * Tell the Syntax Highlighting thread to take another look at this
130: * section of the document. It will process this as a FIFO.
131: * This method should be done inside a doclock.
132: */
133: public void color(int position, int adjustment) {
134: // figure out if this adjustment effects the current run.
135: // if it does, then adjust the place in the document
136: // that gets highlighted.
137: if (position < lastPosition) {
138: if (lastPosition < position - adjustment) {
139: change -= lastPosition - position;
140: } else {
141: change += adjustment;
142: }
143: }
144: synchronized (lock) {
145: v.add(new RecolorEvent(position, adjustment));
146: if (asleep) {
147: this .interrupt();
148: }
149: }
150: }
151:
152: /**
153: * The colorer runs forever and may sleep for long
154: * periods of time. It should be interrupted every
155: * time there is something for it to do.
156: */
157: public void run() {
158: int position = -1;
159: int adjustment = 0;
160: // if we just finish, we can't go to sleep until we
161: // ensure there is nothing else for us to do.
162: // use try again to keep track of this.
163: boolean tryAgain = false;
164: for (;;) { // forever
165: synchronized (lock) {
166: if (v.size() > 0) {
167: RecolorEvent re = (RecolorEvent) (v
168: .elementAt(0));
169: v.removeElementAt(0);
170: position = re.position;
171: adjustment = re.adjustment;
172: } else {
173: tryAgain = false;
174: position = -1;
175: adjustment = 0;
176: }
177: }
178: if (position != -1) {
179: SortedSet workingSet;
180: Iterator workingIt;
181: DocPosition startRequest = new DocPosition(position);
182: DocPosition endRequest = new DocPosition(position
183: + ((adjustment >= 0) ? adjustment
184: : -adjustment));
185: DocPosition dp;
186: DocPosition dpStart = null;
187: DocPosition dpEnd = null;
188:
189: // find the starting position. We must start at least one
190: // token before the current position
191: try {
192: // all the good positions before
193: workingSet = iniPositions.headSet(startRequest);
194: // the last of the stuff before
195: dpStart = ((DocPosition) workingSet.last());
196: } catch (NoSuchElementException x) {
197: // if there were no good positions before the requested start,
198: // we can always start at the very beginning.
199: dpStart = new DocPosition(0);
200: }
201:
202: // if stuff was removed, take any removed positions off the list.
203: if (adjustment < 0) {
204: workingSet = iniPositions.subSet(startRequest,
205: endRequest);
206: workingIt = workingSet.iterator();
207: while (workingIt.hasNext()) {
208: workingIt.next();
209: workingIt.remove();
210: }
211: }
212:
213: // adjust the positions of everything after the insertion/removal.
214: workingSet = iniPositions.tailSet(startRequest);
215: workingIt = workingSet.iterator();
216: while (workingIt.hasNext()) {
217: ((DocPosition) workingIt.next())
218: .adjustPosition(adjustment);
219: }
220:
221: // now go through and highlight as much as needed
222: workingSet = iniPositions.tailSet(dpStart);
223: workingIt = workingSet.iterator();
224: dp = null;
225: if (workingIt.hasNext()) {
226: dp = (DocPosition) workingIt.next();
227: }
228: try {
229: Token t;
230: boolean done = false;
231: dpEnd = dpStart;
232: synchronized (doclock) {
233: // we are playing some games with the lexer for efficiency.
234: // we could just create a new lexer each time here, but instead,
235: // we will just reset it so that it thinks it is starting at the
236: // beginning of the document but reporting a funny start position.
237: // Reseting the lexer causes the close() method on the reader
238: // to be called but because the close() method has no effect on the
239: // DocumentReader, we can do this.
240: syntaxLexer.reset(documentReader, 0,
241: dpStart.getPosition(), 0);
242: // After the lexer has been set up, scroll the reader so that it
243: // is in the correct spot as well.
244: documentReader.seek(dpStart.getPosition());
245: // we will highlight tokens until we reach a good stopping place.
246: // the first obvious stopping place is the end of the document.
247: // the lexer will return null at the end of the document and wee
248: // need to stop there.
249: t = syntaxLexer.getNextToken();
250: }
251: newPositions.add(dpStart);
252: while (!done && t != null) {
253: // this is the actual command that colors the stuff.
254: // Color stuff with the description of the style matched
255: // to the hash table that has been set up ahead of time.
256: synchronized (doclock) {
257: if (t.getCharEnd() <= document
258: .getLength()) {
259: Style style = getStyle(t
260: .getDescription());
261: document.setCharacterAttributes(t
262: .getCharBegin()
263: + change, t.getCharEnd()
264: - t.getCharBegin(), style,
265: true);
266: // record the position of the last bit of text that we colored
267: dpEnd = new DocPosition(t
268: .getCharEnd());
269: }
270: lastPosition = (t.getCharEnd() + change);
271: }
272: // The other more complicated reason for doing no more highlighting
273: // is that all the colors are the same from here on out anyway.
274: // We can detect this by seeing if the place that the lexer returned
275: // to the initial state last time we highlighted is the same as the
276: // place that returned to the initial state this time.
277: // As long as that place is after the last changed text, everything
278: // from there on is fine already.
279: if (t.getState() == Token.INITIAL_STATE) {
280: //System.out.println(t);
281: // look at all the positions from last time that are less than or
282: // equal to the current position
283: while (dp != null
284: && dp.getPosition() <= t
285: .getCharEnd()) {
286: if (dp.getPosition() == t
287: .getCharEnd()
288: && dp.getPosition() >= endRequest
289: .getPosition()) {
290: // we have found a state that is the same
291: done = true;
292: dp = null;
293: } else if (workingIt.hasNext()) {
294: // didn't find it, try again.
295: dp = (DocPosition) workingIt
296: .next();
297: } else {
298: // didn't find it, and there is no more info from last
299: // time. This means that we will just continue
300: // until the end of the document.
301: dp = null;
302: }
303: }
304: // so that we can do this check next time, record all the
305: // initial states from this time.
306: newPositions.add(dpEnd);
307: }
308: synchronized (doclock) {
309: t = syntaxLexer.getNextToken();
310: }
311: }
312:
313: // remove all the old initial positions from the place where
314: // we started doing the highlighting right up through the last
315: // bit of text we touched.
316: workingIt = iniPositions.subSet(dpStart, dpEnd)
317: .iterator();
318: while (workingIt.hasNext()) {
319: workingIt.next();
320: workingIt.remove();
321: }
322:
323: // Remove all the positions that are after the end of the file.:
324: workingIt = iniPositions.tailSet(
325: new DocPosition(document.getLength()))
326: .iterator();
327: while (workingIt.hasNext()) {
328: workingIt.next();
329: workingIt.remove();
330: }
331:
332: // and put the new initial positions that we have found on the list.
333: iniPositions.addAll(newPositions);
334: newPositions.clear();
335:
336: /*workingIt = iniPositions.iterator();
337: while (workingIt.hasNext()){
338: System.out.println(workingIt.next());
339: }
340:
341: System.out.println("Started: " + dpStart.getPosition() + " Ended: " + dpEnd.getPosition());*/
342: } catch (IOException x) {
343: }
344: synchronized (doclock) {
345: lastPosition = -1;
346: change = 0;
347: }
348: // since we did something, we should check that there is
349: // nothing else to do before going back to sleep.
350: tryAgain = true;
351: }
352: asleep = true;
353: if (!tryAgain) {
354: try {
355: sleep(0xffffff);
356: } catch (InterruptedException x) {
357: }
358:
359: }
360: asleep = false;
361: }
362: }
363: }
364:
365: /**
366: * Color or recolor the entire document
367: */
368: public void colorAll() {
369: color(0, document.getLength());
370: }
371:
372: /**
373: * Color a section of the document.
374: * The actual coloring will start somewhere before
375: * the requested position and continue as long
376: * as needed.
377: *
378: * @param position the starting point for the coloring.
379: * @param adjustment amount of text inserted or removed
380: * at the starting point.
381: */
382: public void color(int position, int adjustment) {
383: colorer.color(position, adjustment);
384: }
385:
386: /**
387: * Just like a DefaultStyledDocument but intercepts inserts and
388: * removes to color them.
389: */
390: private class HighLightedDocument extends DefaultStyledDocument {
391: public HighLightedDocument(StyleContext styles) {
392: super (styles);
393: }
394:
395: public void insertString(int offs, String str, AttributeSet a)
396: throws BadLocationException {
397: synchronized (doclock) {
398: super .insertString(offs, str, a);
399: color(offs, str.length());
400: documentReader.update(offs, str.length());
401: }
402: }
403:
404: public void remove(int offs, int len)
405: throws BadLocationException {
406: synchronized (doclock) {
407: super .remove(offs, len);
408: color(offs, -len);
409: documentReader.update(offs, -len);
410: }
411: }
412: }
413:
414: /**
415: * A wrapper for a position in a document appropriate for storing
416: * in a collection.
417: */
418: class DocPosition {
419:
420: /** The actual position */
421: private int position;
422:
423: /**
424: * Get the position represented by this DocPosition
425: *
426: * @return the position
427: */
428: int getPosition() {
429: return position;
430: }
431:
432: /**
433: * Construct a DocPosition from the given offset into the document.
434: *
435: * @param position The position this DocObject will represent
436: */
437: public DocPosition(int position) {
438: this .position = position;
439: }
440:
441: /**
442: * Adjust this position.
443: * This is useful in cases that an amount of text is inserted
444: * or removed before this position.
445: *
446: * @param adjustment amount (either positive or negative) to adjust this position.
447: * @return the DocPosition, adjusted properly.
448: */
449: public DocPosition adjustPosition(int adjustment) {
450: position += adjustment;
451: return this ;
452: }
453:
454: /**
455: * Two DocPositions are equal iff they have the same internal position.
456: *
457: * @return if this DocPosition represents the same position as another.
458: */
459: public boolean equals(Object obj) {
460: if (obj instanceof DocPosition) {
461: DocPosition d = (DocPosition) (obj);
462: if (this .position == d.position) {
463: return true;
464: } else {
465: return false;
466: }
467: } else {
468: return false;
469: }
470: }
471:
472: /**
473: * A string representation useful for debugging.
474: *
475: * @return A string representing the position.
476: */
477: public String toString() {
478: return "" + position;
479: }
480: }
481:
482: /**
483: * A comparator appropriate for use with Collections of
484: * DocPositions.
485: */
486: class DocPositionComparator implements Comparator {
487: /**
488: * Does this Comparator equal another?
489: * Since all DocPositionComparators are the same, they
490: * are all equal.
491: *
492: * @return true for DocPositionComparators, false otherwise.
493: */
494: public boolean equals(Object obj) {
495: if (obj instanceof DocPositionComparator) {
496: return true;
497: } else {
498: return false;
499: }
500: }
501:
502: /**
503: * Compare two DocPositions
504: *
505: * @param o1 first DocPosition
506: * @param o2 second DocPosition
507: * @return negative if first < second, 0 if equal, positive if first > second
508: */
509: public int compare(Object o1, Object o2) {
510: if (o1 instanceof DocPosition && o2 instanceof DocPosition) {
511: DocPosition d1 = (DocPosition) (o1);
512: DocPosition d2 = (DocPosition) (o2);
513: return (d1.getPosition() - d2.getPosition());
514: } else if (o1 instanceof DocPosition) {
515: return -1;
516: } else if (o2 instanceof DocPosition) {
517: return 1;
518: } else if (o1.hashCode() < o2.hashCode()) {
519: return -1;
520: } else if (o2.hashCode() > o1.hashCode()) {
521: return 1;
522: } else {
523: return 0;
524: }
525: }
526: }
527:
528: /**
529: * A reader interface for an abstract document. Since
530: * the syntax highlighting packages only accept Stings and
531: * Readers, this must be used.
532: * Since the close() method does nothing and a seek() method
533: * has been added, this allows us to get some performance
534: * improvements through reuse. It can be used even after the
535: * lexer explicitly closes it by seeking to the place that
536: * we want to read next, and reseting the lexer.
537: */
538: class DocumentReader extends Reader {
539:
540: /**
541: * Modifying the document while the reader is working is like
542: * pulling the rug out from under the reader. Alerting the
543: * reader with this method (in a nice thread safe way, this
544: * should not be called at the same time as a read) allows
545: * the reader to compensate.
546: */
547: public void update(int position, int adjustment) {
548: if (position < this .position) {
549: if (this .position < position - adjustment) {
550: this .position = position;
551: } else {
552: this .position += adjustment;
553: }
554: }
555: }
556:
557: /**
558: * Current position in the document. Incremented
559: * whenever a character is read.
560: */
561: private long position = 0;
562:
563: /** Saved position used in the mark and reset methods. */
564: private long mark = -1;
565:
566: /** The document that we are working with. */
567: private AbstractDocument document;
568:
569: /**
570: * Construct a reader on the given document.
571: *
572: * @param document the document to be read.
573: */
574: public DocumentReader(AbstractDocument document) {
575: this .document = document;
576: }
577:
578: /**
579: * Has no effect. This reader can be used even after
580: * it has been closed.
581: */
582: public void close() {
583: }
584:
585: /**
586: * Save a position for reset.
587: *
588: * @param readAheadLimit ignored.
589: */
590: public void mark(int readAheadLimit) {
591: mark = position;
592: }
593:
594: /**
595: * This reader support mark and reset.
596: *
597: * @return true
598: */
599: public boolean markSupported() {
600: return true;
601: }
602:
603: /**
604: * Read a single character.
605: *
606: * @return the character or -1 if the end of the document has been reached.
607: */
608: public int read() {
609: if (position < document.getLength()) {
610: try {
611: char c = document.getText((int) position, 1)
612: .charAt(0);
613: position++;
614: return c;
615: } catch (BadLocationException x) {
616: return -1;
617: }
618: } else {
619: return -1;
620: }
621: }
622:
623: /**
624: * Read and fill the buffer.
625: * This method will always fill the buffer unless the end of the document is reached.
626: *
627: * @param cbuf the buffer to fill.
628: * @return the number of characters read or -1 if no more characters are available in the document.
629: */
630: public int read(char[] cbuf) {
631: return read(cbuf, 0, cbuf.length);
632: }
633:
634: /**
635: * Read and fill the buffer.
636: * This method will always fill the buffer unless the end of the document is reached.
637: *
638: * @param cbuf the buffer to fill.
639: * @param off offset into the buffer to begin the fill.
640: * @param len maximum number of characters to put in the buffer.
641: * @return the number of characters read or -1 if no more characters are available in the document.
642: */
643: public int read(char[] cbuf, int off, int len) {
644: if (position < document.getLength()) {
645: int length = len;
646: if (position + length >= document.getLength()) {
647: length = document.getLength() - (int) position;
648: }
649: if (off + length >= cbuf.length) {
650: length = cbuf.length - off;
651: }
652: try {
653: String s = document.getText((int) position, length);
654: position += length;
655: for (int i = 0; i < length; i++) {
656: cbuf[off + i] = s.charAt(i);
657: }
658: return length;
659: } catch (BadLocationException x) {
660: return -1;
661: }
662: } else {
663: return -1;
664: }
665: }
666:
667: /**
668: * @return true
669: */
670: public boolean ready() {
671: return true;
672: }
673:
674: /**
675: * Reset this reader to the last mark, or the beginning of the document if a mark has not been set.
676: */
677: public void reset() {
678: if (mark == -1) {
679: position = 0;
680: } else {
681: position = mark;
682: }
683: mark = -1;
684: }
685:
686: /**
687: * Skip characters of input.
688: * This method will always skip the maximum number of characters unless
689: * the end of the file is reached.
690: *
691: * @param n number of characters to skip.
692: * @return the actual number of characters skipped.
693: */
694: public long skip(long n) {
695: if (position + n <= document.getLength()) {
696: position += n;
697: return n;
698: } else {
699: long oldPos = position;
700: position = document.getLength();
701: return (document.getLength() - oldPos);
702: }
703: }
704:
705: /**
706: * Seek to the given position in the document.
707: *
708: * @param n the offset to which to seek.
709: */
710: public void seek(long n) {
711: if (n <= document.getLength()) {
712: position = n;
713: } else {
714: position = document.getLength();
715: }
716: }
717: }
718:
719: private static void initStyles() {
720: Style style;
721: style = styleContext.addStyle("body", null);
722: StyleConstants.setFontFamily(style, "Monospaced");
723: StyleConstants.setFontSize(style, 12);
724: StyleConstants.setBackground(style, Color.white);
725: StyleConstants.setForeground(style, Color.black);
726: StyleConstants.setBold(style, false);
727: StyleConstants.setItalic(style, false);
728:
729: style = styleContext.addStyle("tag", null);
730: StyleConstants.setFontFamily(style, "Monospaced");
731: StyleConstants.setFontSize(style, 12);
732: StyleConstants.setBackground(style, Color.white);
733: StyleConstants.setForeground(style, Color.blue);
734: StyleConstants.setBold(style, true);
735: StyleConstants.setItalic(style, false);
736:
737: style = styleContext.addStyle("endtag", null);
738: StyleConstants.setFontFamily(style, "Monospaced");
739: StyleConstants.setFontSize(style, 12);
740: StyleConstants.setBackground(style, Color.white);
741: StyleConstants.setForeground(style, Color.blue);
742: StyleConstants.setBold(style, false);
743: StyleConstants.setItalic(style, false);
744:
745: style = styleContext.addStyle("reference", null);
746: StyleConstants.setFontFamily(style, "Monospaced");
747: StyleConstants.setFontSize(style, 12);
748: StyleConstants.setBackground(style, Color.white);
749: StyleConstants.setForeground(style, Color.black);
750: StyleConstants.setBold(style, false);
751: StyleConstants.setItalic(style, false);
752:
753: style = styleContext.addStyle("name", null);
754: StyleConstants.setFontFamily(style, "Monospaced");
755: StyleConstants.setFontSize(style, 12);
756: StyleConstants.setBackground(style, Color.white);
757: StyleConstants
758: .setForeground(style, new Color(0xB03060)/*Color.maroon*/);
759: StyleConstants.setBold(style, true);
760: StyleConstants.setItalic(style, false);
761:
762: style = styleContext.addStyle("value", null);
763: StyleConstants.setFontFamily(style, "Monospaced");
764: StyleConstants.setFontSize(style, 12);
765: StyleConstants.setBackground(style, Color.white);
766: StyleConstants
767: .setForeground(style, new Color(0xB03060)/*Color.maroon*/);
768: StyleConstants.setBold(style, false);
769: StyleConstants.setItalic(style, true);
770:
771: style = styleContext.addStyle("tag", null);
772: StyleConstants.setFontFamily(style, "Monospaced");
773: StyleConstants.setFontSize(style, 12);
774: StyleConstants.setBackground(style, Color.white);
775: StyleConstants.setForeground(style, Color.black);
776: StyleConstants.setBold(style, true);
777: StyleConstants.setItalic(style, false);
778:
779: style = styleContext.addStyle("reservedWord", null);
780: StyleConstants.setFontFamily(style, "Monospaced");
781: StyleConstants.setFontSize(style, 12);
782: StyleConstants.setBackground(style, Color.white);
783: StyleConstants.setForeground(style, Color.blue);
784: StyleConstants.setBold(style, false);
785: StyleConstants.setItalic(style, false);
786:
787: style = styleContext.addStyle("identifier", null);
788: StyleConstants.setFontFamily(style, "Monospaced");
789: StyleConstants.setFontSize(style, 12);
790: StyleConstants.setBackground(style, Color.white);
791: StyleConstants.setForeground(style, Color.black);
792: StyleConstants.setBold(style, false);
793: StyleConstants.setItalic(style, false);
794:
795: style = styleContext.addStyle("literal", null);
796: StyleConstants.setFontFamily(style, "Monospaced");
797: StyleConstants.setFontSize(style, 12);
798: StyleConstants.setBackground(style, Color.white);
799: StyleConstants
800: .setForeground(style, new Color(0xB03060)/*Color.maroon*/);
801: StyleConstants.setBold(style, false);
802: StyleConstants.setItalic(style, false);
803:
804: style = styleContext.addStyle("separator", null);
805: StyleConstants.setFontFamily(style, "Monospaced");
806: StyleConstants.setFontSize(style, 12);
807: StyleConstants.setBackground(style, Color.white);
808: StyleConstants
809: .setForeground(style, new Color(0x000080)/*Color.navy*/);
810: StyleConstants.setBold(style, false);
811: StyleConstants.setItalic(style, false);
812:
813: style = styleContext.addStyle("operator", null);
814: StyleConstants.setFontFamily(style, "Monospaced");
815: StyleConstants.setFontSize(style, 12);
816: StyleConstants.setBackground(style, Color.white);
817: StyleConstants.setForeground(style, Color.black);
818: StyleConstants.setBold(style, true);
819: StyleConstants.setItalic(style, false);
820:
821: style = styleContext.addStyle("comment", null);
822: StyleConstants.setFontFamily(style, "Monospaced");
823: StyleConstants.setFontSize(style, 12);
824: StyleConstants.setBackground(style, Color.white);
825: StyleConstants.setForeground(style, Color.green.darker());
826: StyleConstants.setBold(style, false);
827: StyleConstants.setItalic(style, false);
828:
829: style = styleContext.addStyle("preprocessor", null);
830: StyleConstants.setFontFamily(style, "Monospaced");
831: StyleConstants.setFontSize(style, 12);
832: StyleConstants.setBackground(style, Color.white);
833: StyleConstants.setForeground(style, new Color(0xA020F0)
834: .darker()/*Color.purple*/);
835: StyleConstants.setBold(style, false);
836: StyleConstants.setItalic(style, false);
837:
838: style = styleContext.addStyle("whitespace", null);
839: StyleConstants.setFontFamily(style, "Monospaced");
840: StyleConstants.setFontSize(style, 12);
841: StyleConstants.setBackground(style, Color.white);
842: StyleConstants.setForeground(style, Color.black);
843: StyleConstants.setBold(style, false);
844: StyleConstants.setItalic(style, false);
845:
846: style = styleContext.addStyle("error", null);
847: StyleConstants.setFontFamily(style, "Monospaced");
848: StyleConstants.setFontSize(style, 12);
849: StyleConstants.setBackground(style, Color.white);
850: StyleConstants.setForeground(style, Color.red);
851: StyleConstants.setBold(style, false);
852: StyleConstants.setItalic(style, false);
853:
854: style = styleContext.addStyle("unknown", null);
855: StyleConstants.setFontFamily(style, "Monospaced");
856: StyleConstants.setFontSize(style, 12);
857: StyleConstants.setBackground(style, Color.white);
858: StyleConstants.setForeground(style, Color.orange);
859: StyleConstants.setBold(style, false);
860: StyleConstants.setItalic(style, false);
861: }
862: }
|