001: /*
002: * (C) Copyright IBM Corp. 1999-2004. All Rights Reserved.
003: *
004: * The program is provided "as is" without any warranty express or
005: * implied, including the warranty of non-infringement and the implied
006: * warranties of merchantibility and fitness for a particular purpose.
007: * IBM will not be liable for any damages suffered by you as a result
008: * of using the Program. In no event will IBM be liable for any
009: * special, indirect or consequential damages or lost profits even if
010: * IBM has been advised of the possibility of their occurrence. IBM
011: * will not be liable for any third party claims against you.
012: */
013:
014: package com.ibm.richtext.demo;
015:
016: import com.ibm.richtext.awtui.TextFrame;
017: import com.ibm.richtext.textpanel.MTextPanel;
018: import com.ibm.richtext.textpanel.TextPanelEvent;
019: import com.ibm.richtext.textpanel.TextPanelListener;
020:
021: import com.ibm.richtext.styledtext.MConstText;
022: import com.ibm.richtext.styledtext.MText;
023: import com.ibm.richtext.styledtext.StyledText;
024: import com.ibm.richtext.styledtext.StyleModifier;
025:
026: import com.ibm.richtext.textlayout.attributes.AttributeMap;
027: import com.ibm.richtext.textlayout.attributes.TextAttribute;
028:
029: import java.awt.Color;
030:
031: import java.awt.event.WindowAdapter;
032: import java.awt.event.WindowEvent;
033:
034: import java.text.BreakIterator;
035: import java.text.CharacterIterator;
036: import java.text.CollationKey;
037: import java.text.Collator;
038:
039: import java.util.Enumeration;
040: import java.util.Hashtable;
041:
042: /**
043: * SyntaxColorer is a TextPanelListener that applies a style
044: * to a set of words in the TextPanel.
045: */
046: public final class SyntaxColorer implements TextPanelListener {
047:
048: static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
049:
050: private static final class Colorer {
051:
052: static final String COPYRIGHT = "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
053: private int fStart;
054: private Hashtable fStyleMap;
055: private Collator fCollator = Collator.getInstance();
056: private BreakIterator fBreakIter = BreakIterator
057: .getWordInstance();
058:
059: private String fText;
060: private int fCurrentStart;
061: private int fCurrentLimit;
062: private AttributeMap fCurrentStyle;
063:
064: Colorer(Hashtable styles) {
065:
066: fStyleMap = new Hashtable(styles.size());
067:
068: Enumeration e = styles.keys();
069: while (e.hasMoreElements()) {
070: String k = (String) e.nextElement();
071: fStyleMap.put(fCollator.getCollationKey(k), styles
072: .get(k));
073: }
074: }
075:
076: void set(CharacterIterator text, int start, int limit) {
077:
078: fStart = start;
079:
080: StringBuffer sb = new StringBuffer(limit - start);
081: for (char c = text.setIndex(start); text.getIndex() != limit; c = text
082: .next()) {
083: sb.append(c);
084: }
085: fText = sb.toString();
086: fCurrentStart = fCurrentLimit = 0;
087: fCurrentStyle = AttributeMap.EMPTY_ATTRIBUTE_MAP;
088:
089: fBreakIter.setText(fText);
090: fBreakIter.first();
091: }
092:
093: boolean next() {
094:
095: if (fCurrentLimit == fText.length()) {
096: fText = null;
097: return false;
098: }
099:
100: fCurrentStart = fCurrentLimit;
101: fCurrentLimit = fBreakIter.next();
102:
103: String word = fText.substring(fCurrentStart, fCurrentLimit);
104: CollationKey ck = fCollator.getCollationKey(word);
105: fCurrentStyle = (AttributeMap) fStyleMap.get(ck);
106: if (fCurrentStyle == null) {
107: fCurrentStyle = AttributeMap.EMPTY_ATTRIBUTE_MAP;
108: }
109:
110: return true;
111: }
112:
113: int currentStart() {
114: return fCurrentStart + fStart;
115: }
116:
117: int currentLimit() {
118: return fCurrentLimit + fStart;
119: }
120:
121: AttributeMap currentStyle() {
122: return fCurrentStyle;
123: }
124: }
125:
126: private BreakIterator fBreakIter = BreakIterator.getWordInstance();
127: private Colorer fColorer;
128: private boolean fModifying = false;
129: private AttributeMap fDefaultKeywordStyle = AttributeMap.EMPTY_ATTRIBUTE_MAP;
130: private Hashtable fModifierCache;
131:
132: public SyntaxColorer() {
133:
134: this (null);
135: }
136:
137: public SyntaxColorer(MTextPanel panel) {
138:
139: Hashtable ht = new Hashtable();
140:
141: //Uncomment this to make keywords appear right-to-left!
142: //fDefaultKeywordStyle = fDefaultKeywordStyle.addAttribute(TextAttribute.BIDI_EMBEDDING,
143: // new Integer(-1));
144:
145: fDefaultKeywordStyle = fDefaultKeywordStyle.addAttribute(
146: TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
147: fDefaultKeywordStyle = fDefaultKeywordStyle.addAttribute(
148: TextAttribute.FOREGROUND, Color.blue);
149:
150: String[] javaWords = { "abstract", "boolean", "break", "byte",
151: "byvalue", "case", "cast", "default", "do", "double",
152: "else", "extends", "false", "final", "goto", "if",
153: "implements", "import", "inner", "instanceof", "int",
154: "operator", "outer", "package", "private", "protected",
155: "public", "rest", "synchronized", "this", "throw",
156: "throws", "transient", "true", "try", "catch", "char",
157: "const", "continue", "finally", "float", "for",
158: "future", "generic", "interface", "long", "native",
159: "new", "null", "return", "short", "static", "super",
160: "switch", "var", "void", "volatile", "while", "class" };
161:
162: for (int i = 0; i < javaWords.length; i++) {
163: ht.put(javaWords[i], fDefaultKeywordStyle);
164: }
165:
166: fColorer = new Colorer(ht);
167:
168: if (panel != null) {
169: MConstText text = panel.getText();
170: colorRange(0, text.length(),
171: text.createCharacterIterator(), panel);
172: }
173:
174: fModifierCache = new Hashtable(2);
175: fModifierCache.put(fDefaultKeywordStyle, StyleModifier
176: .createReplaceModifier(fDefaultKeywordStyle));
177: fModifierCache
178: .put(
179: AttributeMap.EMPTY_ATTRIBUTE_MAP,
180: StyleModifier
181: .createReplaceModifier(AttributeMap.EMPTY_ATTRIBUTE_MAP));
182: }
183:
184: public boolean respondsToEventType(int type) {
185:
186: return type == TextPanelEvent.TEXT_CHANGED;
187: }
188:
189: public void textEventOccurred(TextPanelEvent e) {
190:
191: if (fModifying) {
192: return;
193: }
194:
195: MTextPanel panel = (MTextPanel) e.getSource();
196:
197: final MConstText text = panel.getText();
198: int start = text.damagedRangeStart();
199: int limit = text.damagedRangeLimit();
200: if (start > limit) {
201: return;
202: }
203:
204: CharacterIterator textIter = text.createCharacterIterator();
205:
206: fBreakIter.setText(textIter);
207: if (start > 0) {
208: if (start == text.length()) {
209: fBreakIter.last();
210: } else {
211: fBreakIter.following(start - 1);
212: }
213: start = fBreakIter.previous();
214: }
215: if (limit < text.length()) {
216: fBreakIter.following(limit);
217: //int l;
218: if ((fBreakIter.previous()) <= limit) {
219: limit = fBreakIter.next();
220: }
221: }
222:
223: fModifying = true;
224: colorRange(start, limit, textIter, panel);
225: fModifying = false;
226: }
227:
228: private void colorRange(final int start, final int limit,
229: CharacterIterator textIter, MTextPanel panel) {
230:
231: fColorer.set(textIter, start, limit);
232:
233: MConstText oldText = panel.getText();
234: MText newText = null;
235:
236: while (fColorer.next()) {
237:
238: int rangeStart = fColorer.currentStart();
239: int rangeLimit = fColorer.currentLimit();
240:
241: AttributeMap style = fColorer.currentStyle();
242:
243: if (oldText.characterStyleLimit(rangeStart) < rangeLimit
244: || oldText.characterStyleAt(rangeStart) != style) {
245:
246: int cstart = rangeStart - start;
247: int climit = rangeLimit - start;
248: if (newText == null) {
249: newText = new StyledText(oldText, start, limit);
250: }
251: StyleModifier mod = (StyleModifier) fModifierCache
252: .get(style);
253: newText.modifyCharacterStyles(cstart, climit, mod);
254: }
255: }
256:
257: if (newText != null) {
258:
259: int oldStart = panel.getSelectionStart();
260: int oldLimit = panel.getSelectionEnd();
261:
262: panel.replaceRange(newText, start, limit);
263:
264: panel.select(oldStart, oldLimit);
265: if (oldStart == oldLimit) {
266: StyleModifier mod = (StyleModifier) fModifierCache
267: .get(AttributeMap.EMPTY_ATTRIBUTE_MAP);
268: panel.modifyCharacterStyleOnSelection(mod);
269: }
270: }
271: }
272:
273: public static void main(String[] args) {
274:
275: TextFrame f = new TextFrame();
276: f.addWindowListener(new WindowAdapter() {
277: public void windowClosing(WindowEvent e) {
278: System.exit(0);
279: }
280: });
281: f.setSize(400, 300);
282: MTextPanel panel = f.getTextPanel();
283: panel.addListener(new SyntaxColorer(panel));
284: f.show();
285: }
286: }
|