KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > java > swing > plaf > gtk > GTKParser


1 /*
2  * @(#)GTKParser.java 1.88 04/08/10
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package com.sun.java.swing.plaf.gtk;
9
10 import java.util.*;
11 import java.io.*;
12 import java.awt.*;
13 import java.util.regex.PatternSyntaxException JavaDoc;
14 import javax.swing.plaf.ColorUIResource JavaDoc;
15 import java.security.AccessController JavaDoc;
16 import sun.security.action.GetPropertyAction;
17 import javax.swing.plaf.synth.SynthConstants JavaDoc;
18
19 /**
20  * @author Shannon Hickey
21  * @version 1.88 08/10/04
22  */

23 class GTKParser {
24     
25     private ArrayList freeScanners = new ArrayList();
26     
27     private HashMap namedStyles = new HashMap();
28     
29     private ArrayList assignments = new ArrayList();
30
31     private HashMap settings = new HashMap();
32
33     private File[] pixmapPaths = null;
34     
35     private ArrayList dirStack = new ArrayList();
36     
37     private HashMap engineParsers = new HashMap();
38
39     // Register parsers here for now. Later we can add methods to register
40
// new parser classes.
41
{
42         engineParsers.put("pixmap", "com.sun.java.swing.plaf.gtk.PixmapEngineParser");
43         engineParsers.put("bluecurve", "com.sun.java.swing.plaf.gtk.BluecurveEngineParser");
44         engineParsers.put("wonderland", "com.sun.java.swing.plaf.gtk.BluecurveEngineParser");
45         engineParsers.put("blueprint", "com.sun.java.swing.plaf.gtk.BlueprintEngineParser");
46     }
47     
48     private GTKScanner scanner;
49
50     private final String JavaDoc CWD = (String JavaDoc)AccessController.doPrivileged(
51                                            new GetPropertyAction("user.dir"));
52
53     static class Symbol {
54         
55         public String JavaDoc name;
56         public int val;
57         
58         public Symbol(String JavaDoc name, int val) {
59             this.name = name;
60             this.val = val;
61         }
62     }
63
64     private static final Symbol SYMBOL_INVALID = new Symbol("invalid", GTKScanner.TOKEN_LAST);
65     private static final Symbol SYMBOL_INCLUDE = new Symbol("include", SYMBOL_INVALID.val + 1);
66     private static final Symbol SYMBOL_NORMAL = new Symbol("NORMAL", SYMBOL_INCLUDE.val + 1);
67     private static final Symbol SYMBOL_ACTIVE = new Symbol("ACTIVE", SYMBOL_NORMAL.val + 1);
68     private static final Symbol SYMBOL_PRELIGHT = new Symbol("PRELIGHT", SYMBOL_ACTIVE.val + 1);
69     private static final Symbol SYMBOL_SELECTED = new Symbol("SELECTED", SYMBOL_PRELIGHT.val + 1);
70     private static final Symbol SYMBOL_INSENSITIVE = new Symbol("INSENSITIVE", SYMBOL_SELECTED.val + 1);
71     private static final Symbol SYMBOL_FG = new Symbol("fg", SYMBOL_INSENSITIVE.val + 1);
72     private static final Symbol SYMBOL_BG = new Symbol("bg", SYMBOL_FG.val + 1);
73     private static final Symbol SYMBOL_TEXT = new Symbol("text", SYMBOL_BG.val + 1);
74     private static final Symbol SYMBOL_BASE = new Symbol("base", SYMBOL_TEXT.val + 1);
75     private static final Symbol SYMBOL_XTHICKNESS = new Symbol("xthickness", SYMBOL_BASE.val + 1);
76     private static final Symbol SYMBOL_YTHICKNESS = new Symbol("ythickness", SYMBOL_XTHICKNESS.val + 1);
77     private static final Symbol SYMBOL_FONT = new Symbol("font", SYMBOL_YTHICKNESS.val + 1);
78     private static final Symbol SYMBOL_FONTSET = new Symbol("fontset", SYMBOL_FONT.val + 1);
79     private static final Symbol SYMBOL_FONT_NAME = new Symbol("font_name", SYMBOL_FONTSET.val + 1);
80     private static final Symbol SYMBOL_BG_PIXMAP = new Symbol("bg_pixmap", SYMBOL_FONT_NAME.val + 1);
81     private static final Symbol SYMBOL_PIXMAP_PATH = new Symbol("pixmap_path", SYMBOL_BG_PIXMAP.val + 1);
82     private static final Symbol SYMBOL_STYLE = new Symbol("style", SYMBOL_PIXMAP_PATH.val + 1);
83     private static final Symbol SYMBOL_BINDING = new Symbol("binding", SYMBOL_STYLE.val + 1);
84     private static final Symbol SYMBOL_BIND = new Symbol("bind", SYMBOL_BINDING.val + 1);
85     private static final Symbol SYMBOL_WIDGET = new Symbol("widget", SYMBOL_BIND.val + 1);
86     private static final Symbol SYMBOL_WIDGET_CLASS = new Symbol("widget_class", SYMBOL_WIDGET.val + 1);
87     private static final Symbol SYMBOL_CLASS = new Symbol("class", SYMBOL_WIDGET_CLASS.val + 1);
88     private static final Symbol SYMBOL_LOWEST = new Symbol("lowest", SYMBOL_CLASS.val + 1);
89     private static final Symbol SYMBOL_GTK = new Symbol("gtk", SYMBOL_LOWEST.val + 1);
90     private static final Symbol SYMBOL_APPLICATION = new Symbol("application", SYMBOL_GTK.val + 1);
91     private static final Symbol SYMBOL_THEME = new Symbol("theme", SYMBOL_APPLICATION.val + 1);
92     private static final Symbol SYMBOL_RC = new Symbol("rc", SYMBOL_THEME.val + 1);
93     private static final Symbol SYMBOL_HIGHEST = new Symbol("highest", SYMBOL_RC.val + 1);
94     private static final Symbol SYMBOL_ENGINE = new Symbol("engine", SYMBOL_HIGHEST.val + 1);
95     private static final Symbol SYMBOL_MODULE_PATH = new Symbol("module_path", SYMBOL_ENGINE.val + 1);
96     private static final Symbol SYMBOL_IM_MODULE_PATH = new Symbol("im_module_path", SYMBOL_MODULE_PATH.val + 1);
97     private static final Symbol SYMBOL_IM_MODULE_FILE = new Symbol("im_module_file", SYMBOL_IM_MODULE_PATH.val + 1);
98     private static final Symbol SYMBOL_STOCK = new Symbol("stock", SYMBOL_IM_MODULE_FILE.val + 1);
99     private static final Symbol SYMBOL_LTR = new Symbol("LTR", SYMBOL_STOCK.val + 1);
100     private static final Symbol SYMBOL_RTL = new Symbol("RTL", SYMBOL_LTR.val + 1);
101     private static final Symbol SYMBOL_LAST = new Symbol("last", SYMBOL_RTL.val + 1);
102     
103     private static final Symbol[] symbols = {
104         SYMBOL_INCLUDE, SYMBOL_NORMAL, SYMBOL_ACTIVE, SYMBOL_PRELIGHT,
105         SYMBOL_SELECTED, SYMBOL_INSENSITIVE, SYMBOL_FG, SYMBOL_BG,
106         SYMBOL_TEXT, SYMBOL_BASE, SYMBOL_XTHICKNESS, SYMBOL_YTHICKNESS,
107         SYMBOL_FONT, SYMBOL_FONTSET, SYMBOL_FONT_NAME, SYMBOL_BG_PIXMAP,
108         SYMBOL_PIXMAP_PATH, SYMBOL_STYLE, SYMBOL_BINDING, SYMBOL_BIND,
109         SYMBOL_WIDGET, SYMBOL_WIDGET_CLASS, SYMBOL_CLASS, SYMBOL_LOWEST,
110         SYMBOL_GTK, SYMBOL_APPLICATION, SYMBOL_THEME, SYMBOL_RC,
111         SYMBOL_HIGHEST, SYMBOL_ENGINE, SYMBOL_MODULE_PATH,
112         SYMBOL_IM_MODULE_FILE, SYMBOL_STOCK, SYMBOL_LTR, SYMBOL_RTL
113     };
114     
115     private static class StyleInfo {
116         String JavaDoc name;
117         
118         static final int NUM_STATES = 5;
119         
120         static final int NORMAL = 0;
121         static final int PRELIGHT = 1;
122         static final int ACTIVE = 2;
123         static final int INSENSITIVE = 3;
124         static final int SELECTED = 4;
125         
126         Color[] fg = new Color[NUM_STATES];
127         Color[] bg = new Color[NUM_STATES];
128         Color[] text = new Color[NUM_STATES];
129         Color[] base = new Color[NUM_STATES];
130         String JavaDoc[] bgPixmapName = new String JavaDoc[NUM_STATES];
131         
132         Font font = null;
133         
134         int xThickness = GTKStyle.UNDEFINED_THICKNESS;
135         int yThickness = GTKStyle.UNDEFINED_THICKNESS;
136
137         // An array of HashMaps. The first HashMap is for stock
138
// icons defined in this style. The other elements are
139
// those inherited from parent.
140
ArrayList stocks = null;
141         
142         CircularIdentityList props = null;
143         
144         EngineInfo engineInfo = null;
145
146         private GTKStyle cachedStyle = null;
147         private static GTKStyle EMPTY_STYLE = new GTKStyle();
148         
149         StyleInfo(String JavaDoc name) {
150             this.name = name;
151         }
152         
153         private void initStocksIfNecessary() {
154             if (stocks == null) {
155                 stocks = new ArrayList();
156                 // for stock icons defined in this style
157
stocks.add(new HashMap());
158             }
159         }
160
161         void addStockItem(String JavaDoc id, GTKStyle.GTKIconSource[] sources) {
162             initStocksIfNecessary();
163             
164             GTKStyle.GTKStockIconInfo iconInfo = new GTKStyle.GTKStockIconInfo(id, sources);
165             
166             HashMap map = (HashMap)stocks.get(0);
167             map.put(id, iconInfo);
168         }
169         
170         void addProperty(String JavaDoc klass, String JavaDoc prop, Object JavaDoc value) {
171             if (props == null) {
172                 props = new CircularIdentityList();
173             }
174             
175             CircularIdentityList subList = (CircularIdentityList)props.get(klass);
176             
177             if (subList == null) {
178                 subList = new CircularIdentityList();
179                 props.set(klass, subList);
180             }
181             
182             subList.set(prop, value);
183         }
184         
185         void copyDataFrom(StyleInfo other) {
186             for (int i = 0; i < NUM_STATES; i++) {
187                 fg[i] = other.fg[i];
188                 bg[i] = other.bg[i];
189                 text[i] = other.text[i];
190                 base[i] = other.base[i];
191                 bgPixmapName[i] = other.bgPixmapName[i];
192             }
193
194             xThickness = other.xThickness;
195             yThickness = other.yThickness;
196             font = other.font;
197             
198             if (other.stocks != null) {
199                 initStocksIfNecessary();
200                 stocks.addAll(other.stocks);
201             }
202             
203             if (props == null) {
204                 props = GTKStyle.cloneClassSpecificValues(other.props);
205             } else {
206                 GTKStyle.addClassSpecificValues(other.props, props);
207             }
208         }
209         
210         GTKStyle toGTKStyle() {
211             if (cachedStyle != null) {
212                 return cachedStyle;
213             }
214             
215             ArrayList stateInfos = new ArrayList();
216             
217             for (int i = 0; i < NUM_STATES; i++) {
218                 Color[] colors = null;
219
220                 if (fg[i] != null
221                         || bg[i] != null
222                         || text[i] != null
223                         || base[i] != null) {
224                     colors = new Color[GTKColorType.MAX_COUNT];
225                     colors[GTKColorType.FOREGROUND.getID()] = fg[i];
226                     colors[GTKColorType.BACKGROUND.getID()] = bg[i];
227                     colors[GTKColorType.TEXT_FOREGROUND.getID()] = text[i];
228                     colors[GTKColorType.TEXT_BACKGROUND.getID()] = base[i];
229                 }
230                 
231                 if (colors != null || bgPixmapName[i] != null) {
232                     GTKStyle.GTKStateInfo stateInfo =
233                         new GTKStyle.GTKStateInfo(toSynthState(i),
234                                                   null, colors, bgPixmapName[i]);
235                     stateInfos.add(stateInfo);
236                 }
237             }
238             
239             GTKStyle.GTKStateInfo[] infoArray = null;
240             if (stateInfos.size() != 0) {
241                 infoArray = new GTKStyle.GTKStateInfo[stateInfos.size()];
242                 infoArray = (GTKStyle.GTKStateInfo[])stateInfos.toArray(infoArray);
243             }
244
245             GTKStyle.GTKStockIconInfo[] stockArray = stocksToArray();
246
247             // if this style has engine information, delegate the creation
248
if (engineInfo != null) {
249                 cachedStyle = engineInfo.constructGTKStyle(infoArray,
250                                                            props,
251                                                            font,
252                                                            xThickness,
253                                                            yThickness,
254                                                            stockArray);
255             // otherwise, create a regular GTKStyle
256
} else if (infoArray != null
257                            || stockArray != null
258                            || props != null
259                            || font != null
260                            || xThickness != GTKStyle.UNDEFINED_THICKNESS
261                            || yThickness != GTKStyle.UNDEFINED_THICKNESS) {
262                 cachedStyle = new GTKStyle(infoArray,
263                                            props,
264                                            font,
265                                            xThickness,
266                                            yThickness,
267                                            stockArray);
268             } else {
269                 cachedStyle = EMPTY_STYLE;
270             }
271
272             return cachedStyle;
273         }
274
275         private GTKStyle.GTKStockIconInfo[] stocksToArray() {
276             if (stocks == null) {
277                 return null;
278             }
279             
280             ArrayList tmpList = new ArrayList();
281             
282             HashMap[] maps = new HashMap[stocks.size()];
283             maps = (HashMap[])stocks.toArray(maps);
284             
285             for (int i = 0; i < maps.length; i++) {
286                 tmpList.addAll(maps[i].values());
287             }
288             
289             GTKStyle.GTKStockIconInfo[] retVal = new GTKStyle.GTKStockIconInfo[tmpList.size()];
290             retVal = (GTKStyle.GTKStockIconInfo[])tmpList.toArray(retVal);
291             
292             return retVal;
293         }
294
295         private static int toSynthState(int ourState) {
296             switch(ourState) {
297                 case NORMAL: return SynthConstants.ENABLED;
298                 case PRELIGHT: return SynthConstants.MOUSE_OVER;
299                 case ACTIVE: return SynthConstants.PRESSED;
300                 case INSENSITIVE: return SynthConstants.DISABLED;
301                 case SELECTED: return SynthConstants.SELECTED;
302             }
303             
304             // should not happen
305
return SynthConstants.ENABLED;
306         }
307     }
308
309     static abstract class EngineInfo {
310         private String JavaDoc engineName;
311         
312         abstract GTKStyle constructGTKStyle(GTKStyle.GTKStateInfo[] infoArray,
313                                             CircularIdentityList props,
314                                             Font font,
315                                             int xThickness,
316                                             int yThickness,
317                                             GTKStyle.GTKStockIconInfo[] stockArray);
318     }
319
320     private static class Assignment {
321         int type;
322         String JavaDoc pattern;
323         StyleInfo info;
324         
325         Assignment(int type, String JavaDoc pattern, StyleInfo info) {
326             this.type = type;
327             this.pattern = pattern;
328             this.info = info;
329         }
330         
331         public String JavaDoc toString() {
332             String JavaDoc sVal = "";
333             
334             switch(type) {
335                 case GTKStyleFactory.WIDGET: sVal = "widget, "; break;
336                 case GTKStyleFactory.WIDGET_CLASS: sVal = "widget_class, "; break;
337                 case GTKStyleFactory.CLASS: sVal = "class, "; break;
338             }
339             
340             sVal += pattern + ", ";
341             sVal += info.name;
342             
343             return sVal;
344         }
345     }
346
347     private static Symbol getSymbol(int symbol) {
348         if (symbol > SYMBOL_INVALID.val && symbol < SYMBOL_LAST.val) {
349             for (int i = 0; i < symbols.length; i++) {
350                 if (symbols[i].val == symbol) {
351                     return symbols[i];
352                 }
353             }
354         }
355         
356         return null;
357     }
358
359     public GTKParser() {
360         freeScanners.add(createScanner());
361     }
362     
363     public void parseString(String JavaDoc str) throws IOException {
364         StringReader reader = new StringReader(str);
365         parseReader(reader, "-");
366     }
367     
368     public void parseFile(File file, String JavaDoc name) throws IOException {
369         if (!file.canRead() || !file.isFile()) {
370             return;
371         }
372         
373         File parent = file.getParentFile();
374         if (parent == null) {
375             parent = new File(CWD);
376         }
377         
378         dirStack.add(parent);
379
380         try {
381             BufferedReader reader = new BufferedReader(new FileReader(file));
382             parseReader(reader, name);
383         } finally {
384             dirStack.remove(dirStack.size() - 1);
385         }
386
387         // PENDING(shannonh) - This is where we should look up and parse
388
// the locale-specific version of the file.
389
}
390
391     private void parseReader(Reader reader, String JavaDoc name) throws IOException {
392         int len = freeScanners.size();
393         
394         if (len == 0) {
395             scanner = createScanner();
396         } else {
397             scanner = (GTKScanner)freeScanners.remove(len - 1);
398         }
399         
400         scanner.scanReader(reader, name);
401         
402         try {
403             parseCurrent();
404         } finally {
405             scanner.clearScanner();
406             freeScanners.add(scanner);
407         }
408     }
409     
410     private static GTKScanner createScanner() {
411         GTKScanner scanner = new GTKScanner();
412
413         // configure scanner for GTK rc files
414
scanner.caseSensitive = true;
415         scanner.scanBinary = true;
416         scanner.scanHexDollar = true;
417         scanner.symbol2Token = true;
418         
419         for (int i = 0; i < symbols.length; i++) {
420             scanner.addSymbol(symbols[i].name, symbols[i].val);
421         }
422         
423         return scanner;
424     }
425     
426     public void loadStylesInto(GTKStyleFactory factory) {
427         Assignment[] assigns = new Assignment[assignments.size()];
428         assigns = (Assignment[])assignments.toArray(assigns);
429         
430         for (int i = 0; i < assigns.length; i++) {
431             Assignment assign = assigns[i];
432             GTKStyle style = assign.info.toGTKStyle();
433             
434             if (style != StyleInfo.EMPTY_STYLE) {
435                 try {
436                     factory.addStyle(style, assign.pattern, assign.type);
437                 } catch (PatternSyntaxException JavaDoc pse) {
438                     // should not happen
439
}
440             }
441         }
442     }
443
444     public HashMap getGTKSettings() {
445         return settings;
446     }
447
448     public void clearParser() {
449         namedStyles.clear();
450         settings.clear();
451         assignments.clear();
452         dirStack.clear();
453         pixmapPaths = null;
454     }
455
456
457
458 //------------------------- Parsing Methods ------------------------------//
459

460     private void parseCurrent() throws IOException {
461         while (true) {
462             if (scanner.peekNextToken() == GTKScanner.TOKEN_EOF) {
463                 break;
464             }
465
466             int expected = parseStatement();
467
468             if (expected != GTKScanner.TOKEN_NONE) {
469                 String JavaDoc symbolName = null;
470                 String JavaDoc msg = null;
471
472                 if (scanner.currScope == 0) {
473                     Symbol lookup;
474
475                     lookup = getSymbol(expected);
476                     if (lookup != null) {
477                         msg = "e.g. `" + lookup.name + "'";
478                     }
479
480                     lookup = getSymbol(scanner.currToken);
481                     if (lookup != null) {
482                         symbolName = lookup.name;
483                     }
484                 }
485
486                 scanner.unexpectedToken(expected, symbolName, msg, true);
487                 break;
488             }
489         }
490     }
491     
492     private int parseStatement() throws IOException {
493         int token;
494         
495         token = scanner.peekNextToken();
496         if (token == SYMBOL_INCLUDE.val) {
497             return parseInclude();
498         } else if (token == SYMBOL_STYLE.val) {
499             return parseStyle();
500         } else if (token == SYMBOL_BINDING.val) {
501             return parseBinding();
502         } else if (token == SYMBOL_PIXMAP_PATH.val) {
503             return parsePixmapPath();
504         } else if (token == SYMBOL_WIDGET.val
505                        || token == SYMBOL_WIDGET_CLASS.val
506                        || token == SYMBOL_CLASS.val) {
507             return parseAssignment(token);
508         } else if (token == SYMBOL_MODULE_PATH.val) {
509             return parseModulePath();
510         } else if (token == SYMBOL_IM_MODULE_FILE.val) {
511             return parseIMModuleFile();
512         } else if (token == GTKScanner.TOKEN_IDENTIFIER) {
513             return parseIdentifier();
514         }
515
516         scanner.getToken();
517         return SYMBOL_STYLE.val;
518     }
519     
520     private int parseInclude() throws IOException {
521         int token;
522         
523         token = scanner.getToken();
524         if (token != SYMBOL_INCLUDE.val) {
525             return SYMBOL_INCLUDE.val;
526         }
527         
528         token = scanner.getToken();
529         if (token != GTKScanner.TOKEN_STRING) {
530             return GTKScanner.TOKEN_STRING;
531         }
532         
533         File parseFile = null;
534         
535         String JavaDoc name = scanner.currValue.stringVal;
536         File file = new File(name);
537
538         if (file.isAbsolute()) {
539             parseFile = file;
540         } else {
541             File[] dirs = new File[dirStack.size()];
542             dirs = (File[])dirStack.toArray(dirs);
543             
544             for (int i = dirs.length - 1; i >= 0; i--) {
545                 file = new File(dirs[i], name);
546                 if (file.exists()) {
547                     parseFile = file;
548                     break;
549                 }
550             }
551         }
552         
553         if (parseFile == null) {
554             scanner.printMessage("Unable to find include file: \"" + name + "\"", false);
555         } else {
556             // save the current scanner and recurse
557
GTKScanner savedScanner = scanner;
558
559             try {
560                 parseFile(file, name);
561             } catch (IOException ioe) {
562                 savedScanner.printMessage("(" + ioe.toString()
563                                               + ") while parsing include file: \""
564                                               + name
565                                               + "\"", false);
566             }
567
568             // restore the scanner
569
scanner = savedScanner;
570         }
571         
572         return GTKScanner.TOKEN_NONE;
573     }
574     
575     private int parseStyle() throws IOException {
576         int token;
577         
578         token = scanner.getToken();
579         if (token != SYMBOL_STYLE.val) {
580             return SYMBOL_STYLE.val;
581         }
582         
583         token = scanner.getToken();
584         if (token != GTKScanner.TOKEN_STRING) {
585             return GTKScanner.TOKEN_STRING;
586         }
587         
588         StyleInfo info = (StyleInfo)namedStyles.get(scanner.currValue.stringVal);
589         
590         if (info == null) {
591             info = new StyleInfo(scanner.currValue.stringVal);
592         }
593         
594         token = scanner.peekNextToken();
595         if (token == GTKScanner.TOKEN_EQUAL_SIGN) {
596             token = scanner.getToken();
597             token = scanner.getToken();
598             
599             if (token != GTKScanner.TOKEN_STRING) {
600                 return GTKScanner.TOKEN_STRING;
601             }
602             
603             StyleInfo parent = (StyleInfo)namedStyles.get(scanner.currValue.stringVal);
604             if (parent != null) {
605                 info.copyDataFrom(parent);
606             }
607         }
608         
609         token = scanner.getToken();
610         if (token != GTKScanner.TOKEN_LEFT_CURLY) {
611             return GTKScanner.TOKEN_LEFT_CURLY;
612         }
613
614         token = scanner.peekNextToken();
615         while (token != GTKScanner.TOKEN_RIGHT_CURLY) {
616             if (token == SYMBOL_FG.val
617                     || token == SYMBOL_BG.val
618                     || token == SYMBOL_TEXT.val
619                     || token == SYMBOL_BASE.val) {
620                 token = parseColorSetting(token, info);
621             } else if (token == SYMBOL_XTHICKNESS.val
622                            || token == SYMBOL_YTHICKNESS.val) {
623                 token = parseThickness(token, info);
624             } else if (token == SYMBOL_BG_PIXMAP.val) {
625                 token = parseBGPixmap(info);
626             } else if (token == SYMBOL_FONT.val
627                            || token == SYMBOL_FONTSET.val
628                            || token == SYMBOL_FONT_NAME.val) {
629                 token = parseFont(token, info);
630             } else if (token == SYMBOL_ENGINE.val) {
631                 token = parseEngine(info);
632             } else if (token == SYMBOL_STOCK.val) {
633                 token = parseStock(info);
634             } else if (token == GTKScanner.TOKEN_IDENTIFIER) {
635                 token = parseIdentifierInStyle(info);
636             } else {
637                 scanner.getToken();
638                 token = GTKScanner.TOKEN_RIGHT_CURLY;
639             }
640             
641             if (token != GTKScanner.TOKEN_NONE) {
642                 return token;
643             }
644             
645             token = scanner.peekNextToken();
646         }
647         
648         token = scanner.getToken();
649         if (token != GTKScanner.TOKEN_RIGHT_CURLY) {
650             return GTKScanner.TOKEN_RIGHT_CURLY;
651         }
652         
653         namedStyles.put(info.name, info);
654         
655         return GTKScanner.TOKEN_NONE;
656     }
657     
658     private int parseBinding() throws IOException {
659         int token;
660         
661         token = scanner.getToken();
662         if (token != SYMBOL_BINDING.val) {
663             return SYMBOL_BINDING.val;
664         }
665         
666         token = scanner.getToken();
667         if (token != GTKScanner.TOKEN_STRING) {
668             return GTKScanner.TOKEN_STRING;
669         }
670         
671         token = ignoreBlock();
672         if (token != GTKScanner.TOKEN_NONE) {
673             return token;
674         }
675         
676         scanner.printMessage("Binding specification is unsupported, ignoring", false);
677         
678         return GTKScanner.TOKEN_NONE;
679     }
680     
681     private int parsePixmapPath() throws IOException {
682         int token;
683         
684         token = scanner.getToken();
685         if (token != SYMBOL_PIXMAP_PATH.val) {
686             return SYMBOL_PIXMAP_PATH.val;
687         }
688         
689         token = scanner.getToken();
690         if (token != GTKScanner.TOKEN_STRING) {
691             return GTKScanner.TOKEN_STRING;
692         }
693         
694         pixmapPaths = null;
695         
696         ArrayList tempPaths = new ArrayList();
697         
698         StringTokenizer tok = new StringTokenizer(scanner.currValue.stringVal, File.pathSeparator);
699         while (tok.hasMoreTokens()) {
700             String JavaDoc path = tok.nextToken();
701             File file = new File(path);
702             if (file.isAbsolute()) {
703                 tempPaths.add(file);
704             } else {
705                 scanner.printMessage("Pixmap path element: \"" + path + "\" must be absolute", false);
706             }
707         }
708         
709         if (tempPaths.size() > 0) {
710             pixmapPaths = new File[tempPaths.size()];
711             pixmapPaths = (File[])tempPaths.toArray(pixmapPaths);
712         }
713         
714         return GTKScanner.TOKEN_NONE;
715     }
716     
717     private int parseAssignment(int expVal) throws IOException {
718         int token;
719         
720         token = scanner.getToken();
721         if (token != expVal) {
722             return expVal;
723         }
724         
725         int type;
726         String JavaDoc pattern;
727         StyleInfo info;
728         
729         boolean isBinding;
730         
731         if (token == SYMBOL_WIDGET.val) {
732             type = GTKStyleFactory.WIDGET;
733         } else if (token == SYMBOL_WIDGET_CLASS.val) {
734             type = GTKStyleFactory.WIDGET_CLASS;
735         } else if (token == SYMBOL_CLASS.val) {
736             type = GTKStyleFactory.CLASS;
737         } else {
738             return SYMBOL_WIDGET_CLASS.val;
739         }
740         
741         token = scanner.getToken();
742         if (token != GTKScanner.TOKEN_STRING) {
743             return GTKScanner.TOKEN_STRING;
744         }
745         
746         pattern = scanner.currValue.stringVal;
747         
748         token = scanner.getToken();
749         if (token == SYMBOL_STYLE.val) {
750             isBinding = false;
751         } else if (token == SYMBOL_BINDING.val) {
752             isBinding = true;
753         } else {
754             return SYMBOL_STYLE.val;
755         }
756         
757         token = scanner.peekNextToken();
758         if (token == ':') {
759             token = scanner.getToken();
760
761             token = scanner.getToken();
762             if (token != SYMBOL_LOWEST.val
763                     && token != SYMBOL_GTK.val
764                     && token != SYMBOL_APPLICATION.val
765                     && token != SYMBOL_THEME.val
766                     && token != SYMBOL_RC.val
767                     && token != SYMBOL_HIGHEST.val) {
768                 return SYMBOL_APPLICATION.val;
769             }
770             
771             scanner.printMessage("Priority specification is unsupported, ignoring", false);
772         }
773         
774         token = scanner.getToken();
775         if (token != GTKScanner.TOKEN_STRING) {
776             return GTKScanner.TOKEN_STRING;
777         }
778
779         // PENDING(shannonh) - When we start handling priority, the information will
780
// probably be stored as part of an Assignment here
781
if (isBinding) {
782             // PENDING(shannonh) - Key binding support
783
scanner.printMessage("Binding assignment is unsupported, ignoring", false);
784         } else {
785             info = (StyleInfo)namedStyles.get(scanner.currValue.stringVal);
786             if (info == null) {
787                 return GTKScanner.TOKEN_STRING;
788             }
789             
790             Assignment assignment = new Assignment(type, pattern, info);
791             assignments.add(assignment);
792         }
793         
794         return GTKScanner.TOKEN_NONE;
795     }
796     
797     private int parseModulePath() throws IOException {
798         int token;
799         
800         token = scanner.getToken();
801         if (token != SYMBOL_MODULE_PATH.val) {
802             return SYMBOL_MODULE_PATH.val;
803         }
804         
805         token = scanner.getToken();
806         if (token != GTKScanner.TOKEN_STRING) {
807             return GTKScanner.TOKEN_STRING;
808         }
809         
810         scanner.printMessage("module_path directive is now ignored", false);
811         
812         return GTKScanner.TOKEN_NONE;
813     }
814     
815     private int parseIMModuleFile() throws IOException {
816         int token;
817         
818         token = scanner.getToken();
819         if (token != SYMBOL_IM_MODULE_FILE.val) {
820             return SYMBOL_IM_MODULE_FILE.val;
821         }
822         
823         token = scanner.getToken();
824         if (token != GTKScanner.TOKEN_STRING) {
825             return GTKScanner.TOKEN_STRING;
826         }
827
828         scanner.printMessage("im_module_file directive is unsupported, ignoring", false);
829         
830         return GTKScanner.TOKEN_NONE;
831     }
832     
833     private int parseIdentifier() throws IOException {
834         int token;
835         
836         token = scanner.getToken();
837         if (token != GTKScanner.TOKEN_IDENTIFIER) {
838             return GTKScanner.TOKEN_IDENTIFIER;
839         }
840         
841         String JavaDoc prop;
842         Object JavaDoc[] value = new Object JavaDoc[1];
843
844         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(scanner.currValue.stringVal);
845
846         String JavaDoc validChars = GTKScanner.CHARS_A_2_Z
847                                 + GTKScanner.CHARS_a_2_z
848                                 + GTKScanner.CHARS_DIGITS
849                                 + "-";
850
851         // some weird logic that GTK does
852
int len = buf.length();
853         for (int i = 0; i < len; i++) {
854             if (validChars.indexOf(buf.charAt(i)) == -1) {
855                 buf.setCharAt(i, '-');
856             }
857         }
858         
859         prop = buf.toString().intern();
860         
861         token = parsePropertyAssignment(value);
862         if (token != GTKScanner.TOKEN_NONE) {
863             return token;
864         }
865
866         settings.put(prop, value[0]);
867
868         return GTKScanner.TOKEN_NONE;
869     }
870     
871     private int parseColorSetting(int expVal, StyleInfo info) throws IOException {
872         int token;
873         
874         token = scanner.getToken();
875         if (token != expVal) {
876             return expVal;
877         }
878         
879         Color[] cols = null;
880         
881         if (token == SYMBOL_FG.val) {
882             cols = info.fg;
883         } else if (token == SYMBOL_BG.val) {
884             cols = info.bg;
885         } else if (token == SYMBOL_TEXT.val) {
886             cols = info.text;
887         } else if (token == SYMBOL_BASE.val) {
888             cols = info.base;
889         } else {
890             return SYMBOL_FG.val;
891         }
892         
893         int[] state = new int[1];
894         token = parseState(state);
895         
896         if (token != GTKScanner.TOKEN_NONE) {
897             return token;
898         }
899         
900         token = scanner.getToken();
901         if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
902             return GTKScanner.TOKEN_EQUAL_SIGN;
903         }
904         
905         return parseColor(scanner, cols, state[0]);
906     }
907     
908     private int parseState(int[] retVal) throws IOException {
909         int token;
910         
911         token = scanner.getToken();
912         if (token != GTKScanner.TOKEN_LEFT_BRACE) {
913             return GTKScanner.TOKEN_LEFT_BRACE;
914         }
915         
916         token = scanner.getToken();
917         if (token == SYMBOL_NORMAL.val) {
918             retVal[0] = StyleInfo.NORMAL;
919         } else if (token == SYMBOL_ACTIVE.val) {
920             retVal[0] = StyleInfo.ACTIVE;
921         } else if (token == SYMBOL_PRELIGHT.val) {
922             retVal[0] = StyleInfo.PRELIGHT;
923         } else if (token == SYMBOL_SELECTED.val) {
924             retVal[0] = StyleInfo.SELECTED;
925         } else if (token == SYMBOL_INSENSITIVE.val) {
926             retVal[0] = StyleInfo.INSENSITIVE;
927         } else {
928             return SYMBOL_NORMAL.val;
929         }
930         
931         token = scanner.getToken();
932         if (token != GTKScanner.TOKEN_RIGHT_BRACE) {
933             return GTKScanner.TOKEN_RIGHT_BRACE;
934         }
935         
936         return GTKScanner.TOKEN_NONE;
937     }
938
939     // this is static, and takes a scanner as a parameter, so that it can
940
// be used in other places that need to parse colors
941
static int parseColor(GTKScanner scanner, Color[] colors, int index)
942                                                         throws IOException {
943         int token;
944         
945         long lVal;
946         double dVal;
947         
948         float red;
949         float green;
950         float blue;
951         
952         token = scanner.getToken();
953         
954         switch(token) {
955             case GTKScanner.TOKEN_LEFT_CURLY:
956                 token = scanner.getToken();
957                 if (token == GTKScanner.TOKEN_INT) {
958                     red = javaColorVal(scanner.currValue.longVal);
959                 } else if (token == GTKScanner.TOKEN_FLOAT) {
960                     red = javaColorVal(scanner.currValue.doubleVal);
961                 } else {
962                     return GTKScanner.TOKEN_FLOAT;
963                 }
964                 
965                 token = scanner.getToken();
966                 if (token != GTKScanner.TOKEN_COMMA) {
967                     return GTKScanner.TOKEN_COMMA;
968                 }
969                 
970                 token = scanner.getToken();
971                 if (token == GTKScanner.TOKEN_INT) {
972                     green = javaColorVal(scanner.currValue.longVal);
973                 } else if (token == GTKScanner.TOKEN_FLOAT) {
974                     green = javaColorVal(scanner.currValue.doubleVal);
975                 } else {
976                     return GTKScanner.TOKEN_FLOAT;
977                 }
978                 
979                 token = scanner.getToken();
980                 if (token != GTKScanner.TOKEN_COMMA) {
981                     return GTKScanner.TOKEN_COMMA;
982                 }
983                 
984                 token = scanner.getToken();
985                 if (token == GTKScanner.TOKEN_INT) {
986                     blue = javaColorVal(scanner.currValue.longVal);
987                 } else if (token == GTKScanner.TOKEN_FLOAT) {
988                     blue = javaColorVal(scanner.currValue.doubleVal);
989                 } else {
990                     return GTKScanner.TOKEN_FLOAT;
991                 }
992                 
993                 token = scanner.getToken();
994                 if (token != GTKScanner.TOKEN_RIGHT_CURLY) {
995                     return GTKScanner.TOKEN_RIGHT_CURLY;
996                 }
997                 
998                 colors[index] = new ColorUIResource JavaDoc(red, green, blue);
999                 
1000                break;
1001            case GTKScanner.TOKEN_STRING:
1002                Color color = parseColorString(scanner.currValue.stringVal);
1003
1004                if (color == null) {
1005                    scanner.printMessage("Invalid color constant '" +
1006                                              scanner.currValue.stringVal
1007                                              + "'", false);
1008                    return GTKScanner.TOKEN_STRING;
1009                }
1010
1011                colors[index] = color;
1012                
1013                break;
1014            default:
1015                return GTKScanner.TOKEN_STRING;
1016        }
1017        
1018        return GTKScanner.TOKEN_NONE;
1019    }
1020    
1021    static Color parseColorString(String JavaDoc str) {
1022        if (str.charAt(0) == '#') {
1023            str = str.substring(1);
1024            
1025            int i = str.length();
1026            
1027            if (i < 3 || i > 12 || (i % 3) != 0) {
1028                return null;
1029            }
1030            
1031            i /= 3;
1032            
1033            int r;
1034            int g;
1035            int b;
1036            
1037            try {
1038                r = Integer.parseInt(str.substring(0, i), 16);
1039                g = Integer.parseInt(str.substring(i, i * 2), 16);
1040                b = Integer.parseInt(str.substring(i * 2, i * 3), 16);
1041            } catch (NumberFormatException JavaDoc nfe) {
1042                return null;
1043            }
1044            
1045            if (i == 4) {
1046                return new ColorUIResource JavaDoc(r / 65535.0f, g / 65535.0f, b / 65535.0f);
1047            } else if (i == 1) {
1048                return new ColorUIResource JavaDoc(r / 15.0f, g / 15.0f, b / 15.0f);
1049            } else if (i == 2) {
1050                return new ColorUIResource JavaDoc(r, g, b);
1051            } else {
1052                return new ColorUIResource JavaDoc(r / 4095.0f, g / 4095.0f, b / 4095.0f);
1053            }
1054        } else {
1055            return XColors.lookupColor(str);
1056        }
1057    }
1058    
1059    private static float javaColorVal(long col) {
1060        int color = (int)Math.max(Math.min(col, 65535), 0);
1061        return color / 65535.0f;
1062    }
1063    
1064    private static float javaColorVal(double col) {
1065        float color = (float)Math.max(Math.min(col, 1.0f), 0.0f);
1066        return color;
1067    }
1068
1069    private int parseThickness(int expVal, StyleInfo info) throws IOException {
1070        int token;
1071        boolean isXThickness;
1072
1073        token = scanner.getToken();
1074        if (token != expVal) {
1075            return expVal;
1076        }
1077
1078        if (token == SYMBOL_XTHICKNESS.val) {
1079            isXThickness = true;
1080        } else if (token == SYMBOL_YTHICKNESS.val) {
1081            isXThickness = false;
1082        } else {
1083            return SYMBOL_XTHICKNESS.val;
1084        }
1085
1086        token = scanner.getToken();
1087        if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
1088            return GTKScanner.TOKEN_EQUAL_SIGN;
1089        }
1090
1091        token = scanner.getToken();
1092        if (token != GTKScanner.TOKEN_INT) {
1093            return GTKScanner.TOKEN_INT;
1094        }
1095
1096        int thickness = (int)scanner.currValue.longVal;
1097
1098        if (isXThickness) {
1099            info.xThickness = thickness;
1100        } else {
1101            info.yThickness = thickness;
1102        }
1103
1104        return GTKScanner.TOKEN_NONE;
1105    }
1106
1107    private int parseBGPixmap(StyleInfo info) throws IOException {
1108        int token;
1109        
1110        token = scanner.getToken();
1111        if (token != SYMBOL_BG_PIXMAP.val) {
1112            return SYMBOL_BG_PIXMAP.val;
1113        }
1114        
1115        int[] state = new int[1];
1116        token = parseState(state);
1117        
1118        if (token != GTKScanner.TOKEN_NONE) {
1119            return token;
1120        }
1121        
1122        token = scanner.getToken();
1123        if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
1124            return GTKScanner.TOKEN_EQUAL_SIGN;
1125        }
1126        
1127        token = scanner.getToken();
1128        if (token != GTKScanner.TOKEN_STRING) {
1129            return GTKScanner.TOKEN_STRING;
1130        }
1131        
1132        String JavaDoc pixmapStr = null;
1133        
1134        String JavaDoc str = scanner.currValue.stringVal;
1135        
1136        if (str.equals("<none>") || str.equals("<parent>")) {
1137            pixmapStr = str.intern();
1138        } else {
1139            pixmapStr = resolvePixmapPath(str);
1140        }
1141        
1142        if (pixmapStr == null) {
1143            scanner.printMessage("Unable to locate image file in pixmap_path: \"" + str + "\"", false);
1144        } else {
1145            info.bgPixmapName[state[0]] = pixmapStr;
1146        }
1147        
1148        return GTKScanner.TOKEN_NONE;
1149    }
1150
1151    String JavaDoc resolvePixmapPath(String JavaDoc str) {
1152        // search in pixmap path
1153
if (pixmapPaths != null) {
1154            for (int i = 0; i < pixmapPaths.length; i++) {
1155                File file = new File(pixmapPaths[i], str);
1156                if (file.canRead()) {
1157                    return file.getAbsolutePath();
1158                }
1159            }
1160        }
1161        
1162        // search in rc directory stack
1163
File[] dirs = new File[dirStack.size()];
1164        dirs = (File[])dirStack.toArray(dirs);
1165        
1166        for (int i = dirs.length - 1; i >= 0; i--) {
1167            File file = new File(dirs[i], str);
1168            if (file.canRead()) {
1169                return file.getAbsolutePath();
1170            }
1171        }
1172        
1173        return null;
1174    }
1175
1176    private int parseFont(int expVal, StyleInfo info) throws IOException {
1177        int token;
1178        boolean isPango;
1179        
1180        token = scanner.getToken();
1181        if (token != expVal) {
1182            return expVal;
1183        }
1184        
1185        if (token == SYMBOL_FONT_NAME.val) {
1186            isPango = true;
1187        } else if (token == SYMBOL_FONT.val
1188                       || token == SYMBOL_FONTSET.val) {
1189            isPango = false;
1190        } else {
1191            return SYMBOL_FONT_NAME.val;
1192        }
1193        
1194        token = scanner.getToken();
1195        if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
1196            return GTKScanner.TOKEN_EQUAL_SIGN;
1197        }
1198        
1199        token = scanner.getToken();
1200        if (token != GTKScanner.TOKEN_STRING) {
1201            return GTKScanner.TOKEN_STRING;
1202        }
1203        
1204        // only need to parse pango font names
1205
if (isPango) {
1206            String JavaDoc pangoName = scanner.currValue.stringVal;
1207            
1208            info.font = PangoFonts.lookupFont(pangoName);
1209        }
1210        
1211        return GTKScanner.TOKEN_NONE;
1212    }
1213
1214    private GTKEngineParser getParser(String JavaDoc engineName) {
1215        Object JavaDoc o = engineParsers.get(engineName);
1216        
1217        if (o == null) {
1218            return null;
1219        }
1220        
1221        if (o instanceof GTKEngineParser) {
1222            return (GTKEngineParser)o;
1223        }
1224        
1225        GTKEngineParser parser = null;
1226        
1227        try {
1228            parser = (GTKEngineParser)Class.forName((String JavaDoc)o).newInstance();
1229        } catch (ClassNotFoundException JavaDoc e) {
1230        } catch (InstantiationException JavaDoc e) {
1231        } catch (IllegalAccessException JavaDoc e) {
1232        }
1233        
1234        if (parser == null) {
1235            // no need to keep trying to load it every time
1236
engineParsers.remove(engineName);
1237        } else {
1238            // replace the name with an instance of a parser
1239
engineParsers.put(engineName, parser);
1240        }
1241        
1242        return parser;
1243    }
1244
1245    private int parseEngine(StyleInfo info) throws IOException {
1246        int token;
1247
1248        token = scanner.getToken();
1249        if (token != SYMBOL_ENGINE.val) {
1250            return SYMBOL_ENGINE.val;
1251        }
1252
1253        token = scanner.getToken();
1254        if (token != GTKScanner.TOKEN_STRING) {
1255            return GTKScanner.TOKEN_STRING;
1256        }
1257
1258        String JavaDoc engineName = scanner.currValue.stringVal;
1259
1260        // engine "" {} means to use the default engine
1261
if (engineName.length() == 0) {
1262            token = scanner.getToken();
1263            if (token != GTKScanner.TOKEN_LEFT_CURLY) {
1264                return GTKScanner.TOKEN_LEFT_CURLY;
1265            }
1266
1267            token = scanner.getToken();
1268            if (token != GTKScanner.TOKEN_RIGHT_CURLY) {
1269                return GTKScanner.TOKEN_RIGHT_CURLY;
1270            }
1271
1272            info.engineInfo = null;
1273
1274            return GTKScanner.TOKEN_NONE;
1275        }
1276
1277        GTKEngineParser parser = getParser(engineName);
1278
1279        if (parser == null) {
1280            token = ignoreBlock();
1281            if (token != GTKScanner.TOKEN_NONE) {
1282                return token;
1283            }
1284            
1285            scanner.printMessage("Engine \"" + engineName + "\" is unsupported, ignoring", false);
1286        } else {
1287            token = scanner.getToken();
1288            if (token != GTKScanner.TOKEN_LEFT_CURLY) {
1289                return GTKScanner.TOKEN_LEFT_CURLY;
1290            }
1291
1292            EngineInfo[] engineInfo = new EngineInfo[1];
1293
1294            // only pass in the existing engine info if it came from this parser
1295
if (info.engineInfo != null && engineName.equals(info.engineInfo.engineName)) {
1296                engineInfo[0] = info.engineInfo;
1297            }
1298
1299            token = parser.parse(scanner, this, engineInfo);
1300            if (token != GTKScanner.TOKEN_NONE) {
1301                return token;
1302            }
1303
1304            // tag the returned engine info with the engine name
1305
if (engineInfo[0] != null) {
1306                engineInfo[0].engineName = engineName;
1307            }
1308
1309            info.engineInfo = engineInfo[0];
1310        }
1311        
1312        return GTKScanner.TOKEN_NONE;
1313    }
1314
1315    private int parseStock(StyleInfo info) throws IOException {
1316        String JavaDoc id;
1317
1318        int token;
1319        
1320        token = scanner.getToken();
1321        if (token != SYMBOL_STOCK.val) {
1322            return SYMBOL_STOCK.val;
1323        }
1324        
1325        token = scanner.getToken();
1326        if (token != GTKScanner.TOKEN_LEFT_BRACE) {
1327            return GTKScanner.TOKEN_LEFT_BRACE;
1328        }
1329        
1330        token = scanner.getToken();
1331        if (token != GTKScanner.TOKEN_STRING) {
1332            return GTKScanner.TOKEN_STRING;
1333        }
1334        
1335        id = scanner.currValue.stringVal;
1336        
1337        token = scanner.getToken();
1338        if (token != GTKScanner.TOKEN_RIGHT_BRACE) {
1339            return GTKScanner.TOKEN_RIGHT_BRACE;
1340        }
1341        
1342        token = scanner.getToken();
1343        if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
1344            return GTKScanner.TOKEN_EQUAL_SIGN;
1345        }
1346        
1347        token = scanner.getToken();
1348        if (token != GTKScanner.TOKEN_LEFT_CURLY) {
1349            return GTKScanner.TOKEN_LEFT_CURLY;
1350        }
1351        
1352        ArrayList iconSources = new ArrayList();
1353
1354        // This array will be used first to hold the return value from
1355
// parseIconSource and then the variable will be used in
1356
// converting iconSources to an array.
1357
GTKStyle.GTKIconSource[] sources = new GTKStyle.GTKIconSource[1];
1358
1359        token = scanner.peekNextToken();
1360        while (token != GTKScanner.TOKEN_RIGHT_CURLY) {
1361            token = parseIconSource(sources);
1362            
1363            if (token != GTKScanner.TOKEN_NONE) {
1364                return token;
1365            }
1366            
1367            token = scanner.getToken();
1368            if (token != GTKScanner.TOKEN_COMMA
1369                    && token != GTKScanner.TOKEN_RIGHT_CURLY) {
1370                return GTKScanner.TOKEN_RIGHT_CURLY;
1371            }
1372            
1373            if (sources[0] != null) {
1374                iconSources.add(sources[0]);
1375            }
1376        }
1377        
1378        if (iconSources.size() != 0) {
1379            sources = new GTKStyle.GTKIconSource[iconSources.size()];
1380            sources = (GTKStyle.GTKIconSource[])iconSources.toArray(sources);
1381            info.addStockItem(id, sources);
1382        }
1383        
1384        return GTKScanner.TOKEN_NONE;
1385    }
1386    
1387    private GTKStyle.GTKIconSource createIconSource(String JavaDoc path,
1388                                                    int direction,
1389                                                    int state,
1390                                                    String JavaDoc size) {
1391        String JavaDoc resolvedPath = resolvePixmapPath(path);
1392
1393        if (resolvedPath != null) {
1394            return new GTKStyle.GTKIconSource(resolvedPath, direction, state, size);
1395        }
1396        
1397        return null;
1398    }
1399    
1400    private int parseIconSource(GTKStyle.GTKIconSource[] retVal) throws IOException {
1401        int token;
1402
1403        String JavaDoc pixmapStr = null;
1404        int direction = GTKConstants.UNDEFINED;
1405        int state = GTKConstants.UNDEFINED;
1406        String JavaDoc size = null;
1407
1408        token = scanner.getToken();
1409        if (token != GTKScanner.TOKEN_LEFT_CURLY) {
1410            return GTKScanner.TOKEN_LEFT_CURLY;
1411        }
1412        
1413        token = scanner.getToken();
1414        if (token != GTKScanner.TOKEN_STRING) {
1415            return GTKScanner.TOKEN_STRING;
1416        }
1417        
1418        pixmapStr = scanner.currValue.stringVal;
1419        
1420        token = scanner.getToken();
1421        if (token == GTKScanner.TOKEN_RIGHT_CURLY) {
1422            retVal[0] = createIconSource(pixmapStr, direction, state, size);
1423            return GTKScanner.TOKEN_NONE;
1424        } else if (token != GTKScanner.TOKEN_COMMA) {
1425            return GTKScanner.TOKEN_COMMA;
1426        }
1427        
1428        token = scanner.getToken();
1429        if (token == SYMBOL_RTL.val) {
1430            direction = GTKConstants.RTL;
1431        } else if (token == SYMBOL_LTR.val) {
1432            direction = GTKConstants.LTR;
1433        } else if (token == '*') {
1434            // nothing
1435
} else {
1436            return SYMBOL_RTL.val;
1437        }
1438        
1439        token = scanner.getToken();
1440        if (token == GTKScanner.TOKEN_RIGHT_CURLY) {
1441            retVal[0] = createIconSource(pixmapStr, direction, state, size);
1442            return GTKScanner.TOKEN_NONE;
1443        } else if (token != GTKScanner.TOKEN_COMMA) {
1444            return GTKScanner.TOKEN_COMMA;
1445        }
1446        
1447        token = scanner.getToken();
1448        if (token == SYMBOL_NORMAL.val) {
1449            state = SynthConstants.ENABLED;
1450        } else if (token == SYMBOL_ACTIVE.val) {
1451            state = SynthConstants.PRESSED;
1452        } else if (token == SYMBOL_PRELIGHT.val) {
1453            state = SynthConstants.MOUSE_OVER;
1454        } else if (token == SYMBOL_SELECTED.val) {
1455            state = SynthConstants.SELECTED;
1456        } else if (token == SYMBOL_INSENSITIVE.val) {
1457            state = SynthConstants.DISABLED;
1458        } else if (token == '*') {
1459            // nothing
1460
} else {
1461            return SYMBOL_PRELIGHT.val;
1462        }
1463        
1464        token = scanner.getToken();
1465        if (token == GTKScanner.TOKEN_RIGHT_CURLY) {
1466            retVal[0] = createIconSource(pixmapStr, direction, state, size);
1467            return GTKScanner.TOKEN_NONE;
1468        } else if (token != GTKScanner.TOKEN_COMMA) {
1469            return GTKScanner.TOKEN_COMMA;
1470        }
1471        
1472        token = scanner.getToken();
1473        if (token != '*') {
1474            if (token != GTKScanner.TOKEN_STRING) {
1475                return GTKScanner.TOKEN_STRING;
1476            }
1477            size = scanner.currValue.stringVal;
1478        }
1479        
1480        token = scanner.getToken();
1481        if (token != GTKScanner.TOKEN_RIGHT_CURLY) {
1482            return GTKScanner.TOKEN_RIGHT_CURLY;
1483        }
1484        
1485        retVal[0] = createIconSource(pixmapStr, direction, state, size);
1486        
1487        return GTKScanner.TOKEN_NONE;
1488    }
1489
1490    private int parseIdentifierInStyle(StyleInfo info) throws IOException {
1491        int token;
1492        
1493        token = scanner.getToken();
1494        if (token != GTKScanner.TOKEN_IDENTIFIER
1495                || scanner.currValue.stringVal.charAt(0) < 'A'
1496                || scanner.currValue.stringVal.charAt(0) > 'Z') {
1497            return GTKScanner.TOKEN_IDENTIFIER;
1498        }
1499        
1500        String JavaDoc klass;
1501        String JavaDoc prop;
1502        Object JavaDoc[] value = new Object JavaDoc[1];
1503        
1504        klass = scanner.currValue.stringVal.intern();
1505        
1506        // check the next two tokens to make sure they're both ':'
1507
if (scanner.getToken() != ':' || scanner.getToken() != ':') {
1508            return ':';
1509        }
1510        
1511        token = scanner.getToken();
1512        if (token != GTKScanner.TOKEN_IDENTIFIER) {
1513            return GTKScanner.TOKEN_IDENTIFIER;
1514        }
1515        
1516        StringBuffer JavaDoc buf = new StringBuffer JavaDoc(scanner.currValue.stringVal);
1517        
1518        String JavaDoc validChars = GTKScanner.CHARS_A_2_Z
1519                                + GTKScanner.CHARS_a_2_z
1520                                + GTKScanner.CHARS_DIGITS
1521                                + "-";
1522
1523        // some weird logic that GTK does
1524
int len = buf.length();
1525        for (int i = 0; i < len; i++) {
1526            if (validChars.indexOf(buf.charAt(i)) == -1) {
1527                buf.setCharAt(i, '-');
1528            }
1529        }
1530        
1531        prop = buf.toString().intern();
1532        
1533        token = parsePropertyAssignment(value);
1534        if (token != GTKScanner.TOKEN_NONE) {
1535            return token;
1536        }
1537
1538        // for Strings or StringBuffers (representing complex values) we check
1539
// for a parser that might want to parse the value
1540
if (value[0] instanceof String JavaDoc || value[0] instanceof StringBuffer JavaDoc) {
1541            Object JavaDoc val = value[0];
1542
1543            PropertyParser pp = PropertyParser.getParserFor(prop);
1544
1545            if (pp == null) {
1546                // just add the property (but convert to String first if StringBuffer)
1547
info.addProperty(klass, prop,
1548                        val instanceof String JavaDoc ? val : val.toString());
1549            } else {
1550                String JavaDoc toParse;
1551                if (val instanceof String JavaDoc) {
1552                    if (pp.needSimpleStringsEscaped()) {
1553                        toParse = '"' + escapeString((String JavaDoc) val) + '"';
1554                    } else {
1555                        toParse = (String JavaDoc)val;
1556                    }
1557                } else {
1558                    toParse = val.toString();
1559                }
1560
1561                Object JavaDoc parsedVal = pp.parse(toParse);
1562                if (parsedVal == null) {
1563                    scanner.printMessage("Failed to parse property value \"" + toParse + "\" for `"
1564                            + klass + "::" + prop + "'", false);
1565                } else {
1566                    info.addProperty(klass, prop, parsedVal);
1567                }
1568            }
1569        } else {
1570            info.addProperty(klass, prop, value[0]);
1571        }
1572
1573        return GTKScanner.TOKEN_NONE;
1574    }
1575
1576    private int parsePropertyAssignment(Object JavaDoc[] retVal) throws IOException {
1577        int token;
1578
1579        token = scanner.getToken();
1580        if (token != '=') {
1581            return '=';
1582        }
1583
1584        // save the scanner mode
1585
boolean scanIdentifier = scanner.scanIdentifier;
1586        boolean scanSymbols = scanner.scanSymbols;
1587        boolean identifier2String = scanner.identifier2String;
1588        boolean char2Token = scanner.char2Token;
1589        boolean scanIdentifierNULL = scanner.scanIdentifierNULL;
1590        boolean numbers2Int = scanner.numbers2Int;
1591
1592        // modify the scanner mode for our purposes
1593
scanner.scanIdentifier = true;
1594        scanner.scanSymbols = false;
1595        scanner.identifier2String = false;
1596        scanner.char2Token = true;
1597        scanner.scanIdentifierNULL = false;
1598        scanner.numbers2Int = true;
1599
1600        boolean negate = false;
1601        
1602        if (scanner.peekNextToken() == '-') {
1603            scanner.getToken();
1604            negate = true;
1605        }
1606        
1607        token = scanner.peekNextToken();
1608        switch(token) {
1609            case GTKScanner.TOKEN_INT:
1610                scanner.getToken();
1611                retVal[0] = new Long JavaDoc(negate ? -scanner.currValue.longVal : scanner.currValue.longVal);
1612                token = GTKScanner.TOKEN_NONE;
1613                break;
1614            case GTKScanner.TOKEN_FLOAT:
1615                scanner.getToken();
1616                retVal[0] = new Double JavaDoc(negate ? -scanner.currValue.doubleVal : scanner.currValue.doubleVal);
1617                token = GTKScanner.TOKEN_NONE;
1618                break;
1619            case GTKScanner.TOKEN_STRING:
1620                scanner.getToken();
1621                if (negate) {
1622                    token = GTKScanner.TOKEN_INT;
1623                } else {
1624                    retVal[0] = scanner.currValue.stringVal;
1625                    token = GTKScanner.TOKEN_NONE;
1626                }
1627                break;
1628            case GTKScanner.TOKEN_IDENTIFIER:
1629            case GTKScanner.TOKEN_LEFT_PAREN:
1630            case GTKScanner.TOKEN_LEFT_CURLY:
1631            case GTKScanner.TOKEN_LEFT_BRACE:
1632                if (negate) {
1633                    token = GTKScanner.TOKEN_INT;
1634                } else {
1635                    StringBuffer JavaDoc result = new StringBuffer JavaDoc();
1636
1637                    token = parseComplexPropVal(result, GTKScanner.TOKEN_EOF);
1638                    if (token == GTKScanner.TOKEN_NONE) {
1639                        result.append(' ');
1640                        // return the StringBuffer directly to indicate a complex value
1641
retVal[0] = result;
1642                    }
1643                }
1644                break;
1645            default:
1646                scanner.getToken();
1647                token = GTKScanner.TOKEN_INT;
1648                break;
1649        }
1650        
1651        // restore the scanner mode
1652
scanner.scanIdentifier = scanIdentifier;
1653        scanner.scanSymbols = scanSymbols;
1654        scanner.identifier2String = identifier2String;
1655        scanner.char2Token = char2Token;
1656        scanner.scanIdentifierNULL = scanIdentifierNULL;
1657        scanner.numbers2Int = numbers2Int;
1658        
1659        return token;
1660    }
1661    
1662    private int parseComplexPropVal(StringBuffer JavaDoc into, int delim) throws IOException {
1663        int token;
1664        
1665        token = scanner.getToken();
1666        switch(token) {
1667            case GTKScanner.TOKEN_INT:
1668                into.append(" 0x");
1669                into.append(Long.toHexString(scanner.currValue.longVal));
1670                break;
1671            case GTKScanner.TOKEN_FLOAT:
1672                into.append(' ');
1673                into.append(scanner.currValue.doubleVal);
1674                break;
1675            case GTKScanner.TOKEN_STRING:
1676                into.append(" \"");
1677                into.append(escapeString(scanner.currValue.stringVal));
1678                into.append('"');
1679                break;
1680            case GTKScanner.TOKEN_IDENTIFIER:
1681                into.append(' ');
1682                into.append(scanner.currValue.stringVal);
1683                break;
1684            case GTKScanner.TOKEN_LEFT_PAREN:
1685                into.append(' ');
1686                into.append((char)token);
1687                token = parseComplexPropVal(into, GTKScanner.TOKEN_RIGHT_PAREN);
1688                if (token != GTKScanner.TOKEN_NONE) {
1689                    return token;
1690                }
1691                break;
1692            case GTKScanner.TOKEN_LEFT_CURLY:
1693                into.append(' ');
1694                into.append((char)token);
1695                token = parseComplexPropVal(into, GTKScanner.TOKEN_RIGHT_CURLY);
1696                if (token != GTKScanner.TOKEN_NONE) {
1697                    return token;
1698                }
1699                break;
1700            case GTKScanner.TOKEN_LEFT_BRACE:
1701                into.append(' ');
1702                into.append((char)token);
1703                token = parseComplexPropVal(into, GTKScanner.TOKEN_RIGHT_BRACE);
1704                if (token != GTKScanner.TOKEN_NONE) {
1705                    return token;
1706                }
1707                break;
1708            default:
1709                if (token >= GTKScanner.TOKEN_NONE || token <= GTKScanner.TOKEN_EOF) {
1710                    return delim != GTKScanner.TOKEN_EOF ? delim : GTKScanner.TOKEN_STRING;
1711                }
1712                into.append(' ');
1713                into.append((char)token);
1714                if (token == delim) {
1715                    return GTKScanner.TOKEN_NONE;
1716                }
1717        }
1718        
1719        if (delim == GTKScanner.TOKEN_EOF) {
1720            return GTKScanner.TOKEN_NONE;
1721        } else {
1722            return parseComplexPropVal(into, delim);
1723        }
1724    }
1725
1726    private String JavaDoc escapeString(String JavaDoc source) {
1727        int len = source.length();
1728        
1729        StringBuffer JavaDoc result = new StringBuffer JavaDoc(len * 4);
1730        
1731        for (int i = 0; i < len; i++) {
1732            char ch = source.charAt(i);
1733            
1734            switch(ch) {
1735                case '\b':
1736                    result.append("\\b");
1737                    break;
1738                case '\f':
1739                    result.append("\\f");
1740                    break;
1741                case '\n':
1742                    result.append("\\n");
1743                    break;
1744                case '\r':
1745                    result.append("\\r");
1746                    break;
1747                case '\t':
1748                    result.append("\\t");
1749                    break;
1750                case '\\':
1751                    result.append("\\\\");
1752                    break;
1753                case '"':
1754                    result.append("\\\"");
1755                    break;
1756                default:
1757                    if (ch < ' ' || ch > '~') {
1758                        result.append('\\');
1759                        result.append(Integer.toOctalString(ch));
1760                    } else {
1761                        result.append((char)ch);
1762                    }
1763                    break;
1764            }
1765        }
1766
1767        return result.toString();
1768    }
1769
1770    private int ignoreBlock() throws IOException {
1771        int token;
1772
1773        token = scanner.getToken();
1774        if (token != GTKScanner.TOKEN_LEFT_CURLY) {
1775            return GTKScanner.TOKEN_LEFT_CURLY;
1776        }
1777
1778        int curlys = 1;
1779
1780        while (curlys > 0) {
1781            token = scanner.getToken();
1782            switch(token) {
1783                case GTKScanner.TOKEN_EOF:
1784                    return GTKScanner.TOKEN_RIGHT_CURLY;
1785                case GTKScanner.TOKEN_LEFT_CURLY:
1786                    curlys++;
1787                    break;
1788                case GTKScanner.TOKEN_RIGHT_CURLY:
1789                    curlys--;
1790                    break;
1791                default:
1792                    // ignore
1793
}
1794        }
1795
1796        return GTKScanner.TOKEN_NONE;
1797    }
1798
1799    // for testing
1800
public static void main(String JavaDoc[] args) {
1801        if (args.length == 0) {
1802            System.err.println("Usage: java GTKParser <gtkrc file> <gtkrc file>....");
1803            System.exit(1);
1804        }
1805        
1806        GTKParser parser = new GTKParser();
1807        
1808        try {
1809            for (int i = 0; i < args.length; i++) {
1810                parser.parseFile(new File(args[i]), args[i]);
1811            }
1812        } catch (IOException ioe) {
1813            ioe.printStackTrace();
1814        }
1815        
1816        parser.printNamedStyles();
1817        System.out.println();
1818        parser.printSettings();
1819        System.out.println();
1820        parser.printAssignments();
1821    }
1822
1823    // for testing
1824
private void printNamedStyles() {
1825        System.out.println("===== Named Styles =====");
1826        
1827        StyleInfo[] infos = new StyleInfo[namedStyles.size()];
1828        infos = (StyleInfo[])namedStyles.values().toArray(infos);
1829        
1830        for (int i = 0; i < infos.length; i++) {
1831            StyleInfo info = infos[i];
1832            
1833            System.out.println("NAME: " + info.name);
1834            GTKStyle style = info.toGTKStyle();
1835            System.out.println(style == StyleInfo.EMPTY_STYLE ? "EMPTY_STYLE" : style.toString());
1836            System.out.println("---------------------------");
1837        }
1838    }
1839
1840    // for testing
1841
private void printSettings() {
1842        System.out.println("===== GTK Settings =====");
1843
1844        Iterator iter = settings.entrySet().iterator();
1845        while (iter.hasNext()) {
1846            Map.Entry entry = (Map.Entry)iter.next();
1847            System.out.println(entry.getKey() + "=" + entry.getValue());
1848        }
1849    }
1850
1851    // for testing
1852
private void printAssignments() {
1853        System.out.println("===== Assignments =====");
1854        
1855        Assignment[] assigns = new Assignment[assignments.size()];
1856        assigns = (Assignment[])assignments.toArray(assigns);
1857        
1858        for (int i = 0; i < assigns.length; i++) {
1859            System.out.println(assigns[i]);
1860        }
1861    }
1862
1863}
1864
Popular Tags