2 * (C) Copyright IBM Corp. 1999-2004. All Rights Reserved.
\r
4 * The program is provided "as is" without any warranty express or
\r
5 * implied, including the warranty of non-infringement and the implied
\r
6 * warranties of merchantibility and fitness for a particular purpose.
\r
7 * IBM will not be liable for any damages suffered by you as a result
\r
8 * of using the Program. In no event will IBM be liable for any
\r
9 * special, indirect or consequential damages or lost profits even if
\r
10 * IBM has been advised of the possibility of their occurrence. IBM
\r
11 * will not be liable for any third party claims against you.
\r
14 package com.ibm.richtext.demo;
\r
16 import com.ibm.richtext.awtui.TextFrame;
\r
17 import com.ibm.richtext.textpanel.MTextPanel;
\r
18 import com.ibm.richtext.textpanel.TextPanelEvent;
\r
19 import com.ibm.richtext.textpanel.TextPanelListener;
\r
21 import com.ibm.richtext.styledtext.MConstText;
\r
22 import com.ibm.richtext.styledtext.MText;
\r
23 import com.ibm.richtext.styledtext.StyledText;
\r
24 import com.ibm.richtext.styledtext.StyleModifier;
\r
26 import com.ibm.richtext.textlayout.attributes.AttributeMap;
\r
27 import com.ibm.richtext.textlayout.attributes.TextAttribute;
\r
29 import java.awt.Color;
\r
31 import java.awt.event.WindowAdapter;
\r
32 import java.awt.event.WindowEvent;
\r
34 import java.text.BreakIterator;
\r
35 import java.text.CharacterIterator;
\r
36 import java.text.CollationKey;
\r
37 import java.text.Collator;
\r
39 import java.util.Enumeration;
\r
40 import java.util.Hashtable;
\r
43 * SyntaxColorer is a TextPanelListener that applies a style
\r
44 * to a set of words in the TextPanel.
\r
46 public final class SyntaxColorer implements TextPanelListener {
\r
48 static final String COPYRIGHT =
\r
49 "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
\r
51 private static final class Colorer {
\r
53 static final String COPYRIGHT =
\r
54 "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
\r
56 private Hashtable fStyleMap;
\r
57 private Collator fCollator = Collator.getInstance();
\r
58 private BreakIterator fBreakIter = BreakIterator.getWordInstance();
\r
60 private String fText;
\r
61 private int fCurrentStart;
\r
62 private int fCurrentLimit;
\r
63 private AttributeMap fCurrentStyle;
\r
65 Colorer(Hashtable styles) {
\r
67 fStyleMap = new Hashtable(styles.size());
\r
69 Enumeration e = styles.keys();
\r
70 while (e.hasMoreElements()) {
\r
71 String k = (String) e.nextElement();
\r
72 fStyleMap.put(fCollator.getCollationKey(k), styles.get(k));
\r
76 void set(CharacterIterator text, int start, int limit) {
\r
80 StringBuffer sb = new StringBuffer(limit-start);
\r
81 for (char c=text.setIndex(start); text.getIndex() != limit; c=text.next()) {
\r
84 fText = sb.toString();
\r
85 fCurrentStart = fCurrentLimit = 0;
\r
86 fCurrentStyle = AttributeMap.EMPTY_ATTRIBUTE_MAP;
\r
88 fBreakIter.setText(fText);
\r
94 if (fCurrentLimit == fText.length()) {
\r
99 fCurrentStart = fCurrentLimit;
\r
100 fCurrentLimit = fBreakIter.next();
\r
102 String word = fText.substring(fCurrentStart, fCurrentLimit);
\r
103 CollationKey ck = fCollator.getCollationKey(word);
\r
104 fCurrentStyle = (AttributeMap) fStyleMap.get(ck);
\r
105 if (fCurrentStyle == null) {
\r
106 fCurrentStyle = AttributeMap.EMPTY_ATTRIBUTE_MAP;
\r
112 int currentStart() {
\r
113 return fCurrentStart + fStart;
\r
116 int currentLimit() {
\r
117 return fCurrentLimit + fStart;
\r
120 AttributeMap currentStyle() {
\r
121 return fCurrentStyle;
\r
125 private BreakIterator fBreakIter = BreakIterator.getWordInstance();
\r
126 private Colorer fColorer;
\r
127 private boolean fModifying = false;
\r
128 private AttributeMap fDefaultKeywordStyle = AttributeMap.EMPTY_ATTRIBUTE_MAP;
\r
129 private Hashtable fModifierCache;
\r
131 public SyntaxColorer() {
\r
136 public SyntaxColorer(MTextPanel panel) {
\r
138 Hashtable ht = new Hashtable();
\r
140 //Uncomment this to make keywords appear right-to-left!
\r
141 //fDefaultKeywordStyle = fDefaultKeywordStyle.addAttribute(TextAttribute.BIDI_EMBEDDING,
\r
142 // new Integer(-1));
\r
144 fDefaultKeywordStyle = fDefaultKeywordStyle.addAttribute(TextAttribute.UNDERLINE,
\r
145 TextAttribute.UNDERLINE_ON);
\r
146 fDefaultKeywordStyle = fDefaultKeywordStyle.addAttribute(TextAttribute.FOREGROUND,
\r
149 String[] javaWords = {"abstract" , "boolean", "break", "byte",
\r
150 "byvalue", "case", "cast", "default",
\r
151 "do", "double", "else", "extends",
\r
152 "false", "final", "goto", "if",
\r
153 "implements", "import", "inner", "instanceof",
\r
154 "int", "operator", "outer", "package",
\r
155 "private", "protected", "public", "rest",
\r
156 "synchronized", "this", "throw", "throws",
\r
157 "transient", "true", "try",
\r
158 "catch", "char", "const", "continue",
\r
159 "finally", "float", "for", "future",
\r
160 "generic", "interface", "long", "native",
\r
161 "new", "null", "return", "short",
\r
162 "static", "super", "switch", "var",
\r
163 "void", "volatile", "while", "class"};
\r
165 for (int i=0; i < javaWords.length; i++) {
\r
166 ht.put(javaWords[i], fDefaultKeywordStyle);
\r
169 fColorer = new Colorer(ht);
\r
171 if (panel != null) {
\r
172 MConstText text = panel.getText();
\r
173 colorRange(0, text.length(), text.createCharacterIterator(), panel);
\r
176 fModifierCache = new Hashtable(2);
\r
177 fModifierCache.put(fDefaultKeywordStyle,
\r
178 StyleModifier.createReplaceModifier(fDefaultKeywordStyle));
\r
179 fModifierCache.put(AttributeMap.EMPTY_ATTRIBUTE_MAP,
\r
180 StyleModifier.createReplaceModifier(AttributeMap.EMPTY_ATTRIBUTE_MAP));
\r
183 public boolean respondsToEventType(int type) {
\r
185 return type == TextPanelEvent.TEXT_CHANGED;
\r
188 public void textEventOccurred(TextPanelEvent e) {
\r
194 MTextPanel panel = (MTextPanel) e.getSource();
\r
196 final MConstText text = panel.getText();
\r
197 int start = text.damagedRangeStart();
\r
198 int limit = text.damagedRangeLimit();
\r
199 if (start > limit) {
\r
203 CharacterIterator textIter = text.createCharacterIterator();
\r
205 fBreakIter.setText(textIter);
\r
207 if (start == text.length()) {
\r
211 fBreakIter.following(start-1);
\r
213 start = fBreakIter.previous();
\r
215 if (limit < text.length()) {
\r
216 fBreakIter.following(limit);
\r
218 if ((fBreakIter.previous()) <= limit) {
\r
219 limit = fBreakIter.next();
\r
224 colorRange(start, limit, textIter, panel);
\r
225 fModifying = false;
\r
228 private void colorRange(final int start,
\r
230 CharacterIterator textIter,
\r
231 MTextPanel panel) {
\r
233 fColorer.set(textIter, start, limit);
\r
235 MConstText oldText = panel.getText();
\r
236 MText newText = null;
\r
238 while (fColorer.next()) {
\r
240 int rangeStart = fColorer.currentStart();
\r
241 int rangeLimit = fColorer.currentLimit();
\r
243 AttributeMap style = fColorer.currentStyle();
\r
245 if (oldText.characterStyleLimit(rangeStart) < rangeLimit ||
\r
246 oldText.characterStyleAt(rangeStart) != style) {
\r
248 int cstart = rangeStart-start;
\r
249 int climit = rangeLimit-start;
\r
250 if (newText == null) {
\r
251 newText = new StyledText(oldText, start, limit);
\r
253 StyleModifier mod = (StyleModifier) fModifierCache.get(style);
\r
254 newText.modifyCharacterStyles(cstart, climit, mod);
\r
258 if (newText != null) {
\r
260 int oldStart = panel.getSelectionStart();
\r
261 int oldLimit = panel.getSelectionEnd();
\r
263 panel.replaceRange(newText, start, limit);
\r
265 panel.select(oldStart, oldLimit);
\r
266 if (oldStart == oldLimit) {
\r
267 StyleModifier mod = (StyleModifier) fModifierCache.get(AttributeMap.EMPTY_ATTRIBUTE_MAP);
\r
268 panel.modifyCharacterStyleOnSelection(mod);
\r
273 public static void main(String[] args) {
\r
275 TextFrame f = new TextFrame();
\r
276 f.addWindowListener(new WindowAdapter() {
\r
277 public void windowClosing(WindowEvent e) {
\r
281 f.setSize(400, 300);
\r
282 MTextPanel panel = f.getTextPanel();
\r
283 panel.addListener(new SyntaxColorer(panel));
\r