1. /*
  2. * @(#)GTKParser.java 1.79 03/07/25
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.gtk;
  8. import java.util.*;
  9. import java.io.*;
  10. import java.awt.*;
  11. import java.util.regex.PatternSyntaxException;
  12. import javax.swing.plaf.ColorUIResource;
  13. import java.security.AccessController;
  14. import sun.security.action.GetPropertyAction;
  15. /**
  16. * @author Shannon Hickey
  17. * @version 1.79 07/25/03
  18. */
  19. class GTKParser {
  20. private ArrayList freeScanners = new ArrayList();
  21. private HashMap namedStyles = new HashMap();
  22. private ArrayList assignments = new ArrayList();
  23. private HashMap settings = new HashMap();
  24. private File[] pixmapPaths = null;
  25. private ArrayList dirStack = new ArrayList();
  26. private HashMap engineParsers = new HashMap();
  27. // Register parsers here for now. Later we can add methods to register
  28. // new parser classes.
  29. {
  30. engineParsers.put("pixmap", "com.sun.java.swing.plaf.gtk.PixmapEngineParser");
  31. engineParsers.put("bluecurve", "com.sun.java.swing.plaf.gtk.BluecurveEngineParser");
  32. engineParsers.put("blueprint", "com.sun.java.swing.plaf.gtk.BlueprintEngineParser");
  33. }
  34. private GTKScanner scanner;
  35. private final String CWD = (String)AccessController.doPrivileged(
  36. new GetPropertyAction("user.dir"));
  37. static class Symbol {
  38. public String name;
  39. public int val;
  40. public Symbol(String name, int val) {
  41. this.name = name;
  42. this.val = val;
  43. }
  44. }
  45. private static final Symbol SYMBOL_INVALID = new Symbol("invalid", GTKScanner.TOKEN_LAST);
  46. private static final Symbol SYMBOL_INCLUDE = new Symbol("include", SYMBOL_INVALID.val + 1);
  47. private static final Symbol SYMBOL_NORMAL = new Symbol("NORMAL", SYMBOL_INCLUDE.val + 1);
  48. private static final Symbol SYMBOL_ACTIVE = new Symbol("ACTIVE", SYMBOL_NORMAL.val + 1);
  49. private static final Symbol SYMBOL_PRELIGHT = new Symbol("PRELIGHT", SYMBOL_ACTIVE.val + 1);
  50. private static final Symbol SYMBOL_SELECTED = new Symbol("SELECTED", SYMBOL_PRELIGHT.val + 1);
  51. private static final Symbol SYMBOL_INSENSITIVE = new Symbol("INSENSITIVE", SYMBOL_SELECTED.val + 1);
  52. private static final Symbol SYMBOL_FG = new Symbol("fg", SYMBOL_INSENSITIVE.val + 1);
  53. private static final Symbol SYMBOL_BG = new Symbol("bg", SYMBOL_FG.val + 1);
  54. private static final Symbol SYMBOL_TEXT = new Symbol("text", SYMBOL_BG.val + 1);
  55. private static final Symbol SYMBOL_BASE = new Symbol("base", SYMBOL_TEXT.val + 1);
  56. private static final Symbol SYMBOL_XTHICKNESS = new Symbol("xthickness", SYMBOL_BASE.val + 1);
  57. private static final Symbol SYMBOL_YTHICKNESS = new Symbol("ythickness", SYMBOL_XTHICKNESS.val + 1);
  58. private static final Symbol SYMBOL_FONT = new Symbol("font", SYMBOL_YTHICKNESS.val + 1);
  59. private static final Symbol SYMBOL_FONTSET = new Symbol("fontset", SYMBOL_FONT.val + 1);
  60. private static final Symbol SYMBOL_FONT_NAME = new Symbol("font_name", SYMBOL_FONTSET.val + 1);
  61. private static final Symbol SYMBOL_BG_PIXMAP = new Symbol("bg_pixmap", SYMBOL_FONT_NAME.val + 1);
  62. private static final Symbol SYMBOL_PIXMAP_PATH = new Symbol("pixmap_path", SYMBOL_BG_PIXMAP.val + 1);
  63. private static final Symbol SYMBOL_STYLE = new Symbol("style", SYMBOL_PIXMAP_PATH.val + 1);
  64. private static final Symbol SYMBOL_BINDING = new Symbol("binding", SYMBOL_STYLE.val + 1);
  65. private static final Symbol SYMBOL_BIND = new Symbol("bind", SYMBOL_BINDING.val + 1);
  66. private static final Symbol SYMBOL_WIDGET = new Symbol("widget", SYMBOL_BIND.val + 1);
  67. private static final Symbol SYMBOL_WIDGET_CLASS = new Symbol("widget_class", SYMBOL_WIDGET.val + 1);
  68. private static final Symbol SYMBOL_CLASS = new Symbol("class", SYMBOL_WIDGET_CLASS.val + 1);
  69. private static final Symbol SYMBOL_LOWEST = new Symbol("lowest", SYMBOL_CLASS.val + 1);
  70. private static final Symbol SYMBOL_GTK = new Symbol("gtk", SYMBOL_LOWEST.val + 1);
  71. private static final Symbol SYMBOL_APPLICATION = new Symbol("application", SYMBOL_GTK.val + 1);
  72. private static final Symbol SYMBOL_THEME = new Symbol("theme", SYMBOL_APPLICATION.val + 1);
  73. private static final Symbol SYMBOL_RC = new Symbol("rc", SYMBOL_THEME.val + 1);
  74. private static final Symbol SYMBOL_HIGHEST = new Symbol("highest", SYMBOL_RC.val + 1);
  75. private static final Symbol SYMBOL_ENGINE = new Symbol("engine", SYMBOL_HIGHEST.val + 1);
  76. private static final Symbol SYMBOL_MODULE_PATH = new Symbol("module_path", SYMBOL_ENGINE.val + 1);
  77. private static final Symbol SYMBOL_IM_MODULE_PATH = new Symbol("im_module_path", SYMBOL_MODULE_PATH.val + 1);
  78. private static final Symbol SYMBOL_IM_MODULE_FILE = new Symbol("im_module_file", SYMBOL_IM_MODULE_PATH.val + 1);
  79. private static final Symbol SYMBOL_STOCK = new Symbol("stock", SYMBOL_IM_MODULE_FILE.val + 1);
  80. private static final Symbol SYMBOL_LTR = new Symbol("LTR", SYMBOL_STOCK.val + 1);
  81. private static final Symbol SYMBOL_RTL = new Symbol("RTL", SYMBOL_LTR.val + 1);
  82. private static final Symbol SYMBOL_LAST = new Symbol("last", SYMBOL_RTL.val + 1);
  83. private static final Symbol[] symbols = {
  84. SYMBOL_INCLUDE, SYMBOL_NORMAL, SYMBOL_ACTIVE, SYMBOL_PRELIGHT,
  85. SYMBOL_SELECTED, SYMBOL_INSENSITIVE, SYMBOL_FG, SYMBOL_BG,
  86. SYMBOL_TEXT, SYMBOL_BASE, SYMBOL_XTHICKNESS, SYMBOL_YTHICKNESS,
  87. SYMBOL_FONT, SYMBOL_FONTSET, SYMBOL_FONT_NAME, SYMBOL_BG_PIXMAP,
  88. SYMBOL_PIXMAP_PATH, SYMBOL_STYLE, SYMBOL_BINDING, SYMBOL_BIND,
  89. SYMBOL_WIDGET, SYMBOL_WIDGET_CLASS, SYMBOL_CLASS, SYMBOL_LOWEST,
  90. SYMBOL_GTK, SYMBOL_APPLICATION, SYMBOL_THEME, SYMBOL_RC,
  91. SYMBOL_HIGHEST, SYMBOL_ENGINE, SYMBOL_MODULE_PATH,
  92. SYMBOL_IM_MODULE_FILE, SYMBOL_STOCK, SYMBOL_LTR, SYMBOL_RTL
  93. };
  94. private static class StyleInfo {
  95. String name;
  96. static final int NUM_STATES = 5;
  97. static final int NORMAL = 0;
  98. static final int PRELIGHT = 1;
  99. static final int ACTIVE = 2;
  100. static final int INSENSITIVE = 3;
  101. static final int SELECTED = 4;
  102. Color[] fg = new Color[NUM_STATES];
  103. Color[] bg = new Color[NUM_STATES];
  104. Color[] text = new Color[NUM_STATES];
  105. Color[] base = new Color[NUM_STATES];
  106. String[] bgPixmapName = new String[NUM_STATES];
  107. Font font = null;
  108. int xThickness = GTKStyle.UNDEFINED_THICKNESS;
  109. int yThickness = GTKStyle.UNDEFINED_THICKNESS;
  110. // An array of HashMaps. The first HashMap is for stock
  111. // icons defined in this style. The other elements are
  112. // those inherited from parent.
  113. ArrayList stocks = null;
  114. CircularIdentityList props = null;
  115. EngineInfo engineInfo = null;
  116. private GTKStyle cachedStyle = null;
  117. private static GTKStyle EMPTY_STYLE = new GTKStyle();
  118. StyleInfo(String name) {
  119. this.name = name;
  120. }
  121. private void initStocksIfNecessary() {
  122. if (stocks == null) {
  123. stocks = new ArrayList();
  124. // for stock icons defined in this style
  125. stocks.add(new HashMap());
  126. }
  127. }
  128. void addStockItem(String id, GTKStyle.GTKIconSource[] sources) {
  129. initStocksIfNecessary();
  130. GTKStyle.GTKStockIconInfo iconInfo = new GTKStyle.GTKStockIconInfo(id, sources);
  131. HashMap map = (HashMap)stocks.get(0);
  132. map.put(id, iconInfo);
  133. }
  134. void addProperty(String klass, String prop, Object value) {
  135. if (props == null) {
  136. props = new CircularIdentityList();
  137. }
  138. CircularIdentityList subList = (CircularIdentityList)props.get(klass);
  139. if (subList == null) {
  140. subList = new CircularIdentityList();
  141. props.set(klass, subList);
  142. }
  143. subList.set(prop, value);
  144. }
  145. void copyDataFrom(StyleInfo other) {
  146. for (int i = 0; i < NUM_STATES; i++) {
  147. fg[i] = other.fg[i];
  148. bg[i] = other.bg[i];
  149. text[i] = other.text[i];
  150. base[i] = other.base[i];
  151. bgPixmapName[i] = other.bgPixmapName[i];
  152. }
  153. xThickness = other.xThickness;
  154. yThickness = other.yThickness;
  155. font = other.font;
  156. if (other.stocks != null) {
  157. initStocksIfNecessary();
  158. stocks.addAll(other.stocks);
  159. }
  160. if (props == null) {
  161. props = GTKStyle.cloneClassSpecificValues(other.props);
  162. } else {
  163. GTKStyle.addClassSpecificValues(other.props, props);
  164. }
  165. }
  166. GTKStyle toGTKStyle() {
  167. if (cachedStyle != null) {
  168. return cachedStyle;
  169. }
  170. ArrayList stateInfos = new ArrayList();
  171. for (int i = 0; i < NUM_STATES; i++) {
  172. Color[] colors = null;
  173. if (fg[i] != null
  174. || bg[i] != null
  175. || text[i] != null
  176. || base[i] != null) {
  177. colors = new Color[GTKColorType.MAX_COUNT];
  178. colors[GTKColorType.FOREGROUND.getID()] = fg[i];
  179. colors[GTKColorType.BACKGROUND.getID()] = bg[i];
  180. colors[GTKColorType.TEXT_FOREGROUND.getID()] = text[i];
  181. colors[GTKColorType.TEXT_BACKGROUND.getID()] = base[i];
  182. }
  183. if (colors != null || bgPixmapName[i] != null) {
  184. GTKStyle.GTKStateInfo stateInfo =
  185. new GTKStyle.GTKStateInfo(toSynthState(i),
  186. null, null, null,
  187. colors, bgPixmapName[i]);
  188. stateInfos.add(stateInfo);
  189. }
  190. }
  191. GTKStyle.GTKStateInfo[] infoArray = null;
  192. if (stateInfos.size() != 0) {
  193. infoArray = new GTKStyle.GTKStateInfo[stateInfos.size()];
  194. infoArray = (GTKStyle.GTKStateInfo[])stateInfos.toArray(infoArray);
  195. }
  196. GTKStyle.GTKStockIconInfo[] stockArray = stocksToArray();
  197. // if this style has engine information, delegate the creation
  198. if (engineInfo != null) {
  199. cachedStyle = engineInfo.constructGTKStyle(infoArray,
  200. props,
  201. font,
  202. xThickness,
  203. yThickness,
  204. stockArray);
  205. // otherwise, create a regular GTKStyle
  206. } else if (infoArray != null
  207. || stockArray != null
  208. || props != null
  209. || font != null
  210. || xThickness != GTKStyle.UNDEFINED_THICKNESS
  211. || yThickness != GTKStyle.UNDEFINED_THICKNESS) {
  212. cachedStyle = new GTKStyle(infoArray,
  213. props,
  214. font,
  215. xThickness,
  216. yThickness,
  217. stockArray);
  218. } else {
  219. cachedStyle = EMPTY_STYLE;
  220. }
  221. return cachedStyle;
  222. }
  223. private GTKStyle.GTKStockIconInfo[] stocksToArray() {
  224. if (stocks == null) {
  225. return null;
  226. }
  227. ArrayList tmpList = new ArrayList();
  228. HashMap[] maps = new HashMap[stocks.size()];
  229. maps = (HashMap[])stocks.toArray(maps);
  230. for (int i = 0; i < maps.length; i++) {
  231. tmpList.addAll(maps[i].values());
  232. }
  233. GTKStyle.GTKStockIconInfo[] retVal = new GTKStyle.GTKStockIconInfo[tmpList.size()];
  234. retVal = (GTKStyle.GTKStockIconInfo[])tmpList.toArray(retVal);
  235. return retVal;
  236. }
  237. private static int toSynthState(int ourState) {
  238. switch(ourState) {
  239. case NORMAL: return SynthConstants.ENABLED;
  240. case PRELIGHT: return SynthConstants.MOUSE_OVER;
  241. case ACTIVE: return SynthConstants.PRESSED;
  242. case INSENSITIVE: return SynthConstants.DISABLED;
  243. case SELECTED: return SynthConstants.SELECTED;
  244. }
  245. // should not happen
  246. return SynthConstants.ENABLED;
  247. }
  248. }
  249. static abstract class EngineInfo {
  250. private String engineName;
  251. abstract GTKStyle constructGTKStyle(GTKStyle.GTKStateInfo[] infoArray,
  252. CircularIdentityList props,
  253. Font font,
  254. int xThickness,
  255. int yThickness,
  256. GTKStyle.GTKStockIconInfo[] stockArray);
  257. }
  258. private static class Assignment {
  259. int type;
  260. String pattern;
  261. StyleInfo info;
  262. Assignment(int type, String pattern, StyleInfo info) {
  263. this.type = type;
  264. this.pattern = pattern;
  265. this.info = info;
  266. }
  267. public String toString() {
  268. String sVal = "";
  269. switch(type) {
  270. case GTKStyleFactory.WIDGET: sVal = "widget, "; break;
  271. case GTKStyleFactory.WIDGET_CLASS: sVal = "widget_class, "; break;
  272. case GTKStyleFactory.CLASS: sVal = "class, "; break;
  273. }
  274. sVal += pattern + ", ";
  275. sVal += info.name;
  276. return sVal;
  277. }
  278. }
  279. private static Symbol getSymbol(int symbol) {
  280. if (symbol > SYMBOL_INVALID.val && symbol < SYMBOL_LAST.val) {
  281. for (int i = 0; i < symbols.length; i++) {
  282. if (symbols[i].val == symbol) {
  283. return symbols[i];
  284. }
  285. }
  286. }
  287. return null;
  288. }
  289. public GTKParser() {
  290. freeScanners.add(createScanner());
  291. }
  292. public void parseString(String str) throws IOException {
  293. StringReader reader = new StringReader(str);
  294. parseReader(reader, "-");
  295. }
  296. public void parseFile(File file, String name) throws IOException {
  297. if (!file.canRead() || !file.isFile()) {
  298. return;
  299. }
  300. File parent = file.getParentFile();
  301. if (parent == null) {
  302. parent = new File(CWD);
  303. }
  304. dirStack.add(parent);
  305. try {
  306. BufferedReader reader = new BufferedReader(new FileReader(file));
  307. parseReader(reader, name);
  308. } finally {
  309. dirStack.remove(dirStack.size() - 1);
  310. }
  311. // PENDING(shannonh) - This is where we should look up and parse
  312. // the locale-specific version of the file.
  313. }
  314. private void parseReader(Reader reader, String name) throws IOException {
  315. int len = freeScanners.size();
  316. if (len == 0) {
  317. scanner = createScanner();
  318. } else {
  319. scanner = (GTKScanner)freeScanners.remove(len - 1);
  320. }
  321. scanner.scanReader(reader, name);
  322. try {
  323. parseCurrent();
  324. } finally {
  325. scanner.clearScanner();
  326. freeScanners.add(scanner);
  327. }
  328. }
  329. private static GTKScanner createScanner() {
  330. GTKScanner scanner = new GTKScanner();
  331. // configure scanner for GTK rc files
  332. scanner.caseSensitive = true;
  333. scanner.scanBinary = true;
  334. scanner.scanHexDollar = true;
  335. scanner.symbol2Token = true;
  336. for (int i = 0; i < symbols.length; i++) {
  337. scanner.addSymbol(symbols[i].name, symbols[i].val);
  338. }
  339. return scanner;
  340. }
  341. public void loadStylesInto(GTKStyleFactory factory) {
  342. Assignment[] assigns = new Assignment[assignments.size()];
  343. assigns = (Assignment[])assignments.toArray(assigns);
  344. for (int i = 0; i < assigns.length; i++) {
  345. Assignment assign = assigns[i];
  346. GTKStyle style = assign.info.toGTKStyle();
  347. if (style != StyleInfo.EMPTY_STYLE) {
  348. try {
  349. factory.addStyle(style, assign.pattern, assign.type);
  350. } catch (PatternSyntaxException pse) {
  351. // should not happen
  352. }
  353. }
  354. }
  355. }
  356. public HashMap getGTKSettings() {
  357. return settings;
  358. }
  359. public void clearParser() {
  360. namedStyles.clear();
  361. settings.clear();
  362. assignments.clear();
  363. dirStack.clear();
  364. pixmapPaths = null;
  365. }
  366. //------------------------- Parsing Methods ------------------------------//
  367. private void parseCurrent() throws IOException {
  368. while (true) {
  369. if (scanner.peekNextToken() == GTKScanner.TOKEN_EOF) {
  370. break;
  371. }
  372. int expected = parseStatement();
  373. if (expected != GTKScanner.TOKEN_NONE) {
  374. String symbolName = null;
  375. String msg = null;
  376. if (scanner.currScope == 0) {
  377. Symbol lookup;
  378. lookup = getSymbol(expected);
  379. if (lookup != null) {
  380. msg = "e.g. `" + lookup.name + "'";
  381. }
  382. lookup = getSymbol(scanner.currToken);
  383. if (lookup != null) {
  384. symbolName = lookup.name;
  385. }
  386. }
  387. scanner.unexpectedToken(expected, symbolName, msg, true);
  388. break;
  389. }
  390. }
  391. }
  392. private int parseStatement() throws IOException {
  393. int token;
  394. token = scanner.peekNextToken();
  395. if (token == SYMBOL_INCLUDE.val) {
  396. return parseInclude();
  397. } else if (token == SYMBOL_STYLE.val) {
  398. return parseStyle();
  399. } else if (token == SYMBOL_BINDING.val) {
  400. return parseBinding();
  401. } else if (token == SYMBOL_PIXMAP_PATH.val) {
  402. return parsePixmapPath();
  403. } else if (token == SYMBOL_WIDGET.val
  404. || token == SYMBOL_WIDGET_CLASS.val
  405. || token == SYMBOL_CLASS.val) {
  406. return parseAssignment(token);
  407. } else if (token == SYMBOL_MODULE_PATH.val) {
  408. return parseModulePath();
  409. } else if (token == SYMBOL_IM_MODULE_FILE.val) {
  410. return parseIMModuleFile();
  411. } else if (token == GTKScanner.TOKEN_IDENTIFIER) {
  412. return parseIdentifier();
  413. }
  414. scanner.getToken();
  415. return SYMBOL_STYLE.val;
  416. }
  417. private int parseInclude() throws IOException {
  418. int token;
  419. token = scanner.getToken();
  420. if (token != SYMBOL_INCLUDE.val) {
  421. return SYMBOL_INCLUDE.val;
  422. }
  423. token = scanner.getToken();
  424. if (token != GTKScanner.TOKEN_STRING) {
  425. return GTKScanner.TOKEN_STRING;
  426. }
  427. File parseFile = null;
  428. String name = scanner.currValue.stringVal;
  429. File file = new File(name);
  430. if (file.isAbsolute()) {
  431. parseFile = file;
  432. } else {
  433. File[] dirs = new File[dirStack.size()];
  434. dirs = (File[])dirStack.toArray(dirs);
  435. for (int i = dirs.length - 1; i >= 0; i--) {
  436. file = new File(dirs[i], name);
  437. if (file.exists()) {
  438. parseFile = file;
  439. break;
  440. }
  441. }
  442. }
  443. if (parseFile == null) {
  444. scanner.printMessage("Unable to find include file: \"" + name + "\"", false);
  445. } else {
  446. // save the current scanner and recurse
  447. GTKScanner savedScanner = scanner;
  448. try {
  449. parseFile(file, name);
  450. } catch (IOException ioe) {
  451. savedScanner.printMessage("(" + ioe.toString()
  452. + ") while parsing include file: \""
  453. + name
  454. + "\"", false);
  455. }
  456. // restore the scanner
  457. scanner = savedScanner;
  458. }
  459. return GTKScanner.TOKEN_NONE;
  460. }
  461. private int parseStyle() throws IOException {
  462. int token;
  463. token = scanner.getToken();
  464. if (token != SYMBOL_STYLE.val) {
  465. return SYMBOL_STYLE.val;
  466. }
  467. token = scanner.getToken();
  468. if (token != GTKScanner.TOKEN_STRING) {
  469. return GTKScanner.TOKEN_STRING;
  470. }
  471. StyleInfo info = (StyleInfo)namedStyles.get(scanner.currValue.stringVal);
  472. if (info == null) {
  473. info = new StyleInfo(scanner.currValue.stringVal);
  474. }
  475. token = scanner.peekNextToken();
  476. if (token == GTKScanner.TOKEN_EQUAL_SIGN) {
  477. token = scanner.getToken();
  478. token = scanner.getToken();
  479. if (token != GTKScanner.TOKEN_STRING) {
  480. return GTKScanner.TOKEN_STRING;
  481. }
  482. StyleInfo parent = (StyleInfo)namedStyles.get(scanner.currValue.stringVal);
  483. if (parent != null) {
  484. info.copyDataFrom(parent);
  485. }
  486. }
  487. token = scanner.getToken();
  488. if (token != GTKScanner.TOKEN_LEFT_CURLY) {
  489. return GTKScanner.TOKEN_LEFT_CURLY;
  490. }
  491. token = scanner.peekNextToken();
  492. while (token != GTKScanner.TOKEN_RIGHT_CURLY) {
  493. if (token == SYMBOL_FG.val
  494. || token == SYMBOL_BG.val
  495. || token == SYMBOL_TEXT.val
  496. || token == SYMBOL_BASE.val) {
  497. token = parseColorSetting(token, info);
  498. } else if (token == SYMBOL_XTHICKNESS.val
  499. || token == SYMBOL_YTHICKNESS.val) {
  500. token = parseThickness(token, info);
  501. } else if (token == SYMBOL_BG_PIXMAP.val) {
  502. token = parseBGPixmap(info);
  503. } else if (token == SYMBOL_FONT.val
  504. || token == SYMBOL_FONTSET.val
  505. || token == SYMBOL_FONT_NAME.val) {
  506. token = parseFont(token, info);
  507. } else if (token == SYMBOL_ENGINE.val) {
  508. token = parseEngine(info);
  509. } else if (token == SYMBOL_STOCK.val) {
  510. token = parseStock(info);
  511. } else if (token == GTKScanner.TOKEN_IDENTIFIER) {
  512. token = parseIdentifierInStyle(info);
  513. } else {
  514. scanner.getToken();
  515. token = GTKScanner.TOKEN_RIGHT_CURLY;
  516. }
  517. if (token != GTKScanner.TOKEN_NONE) {
  518. return token;
  519. }
  520. token = scanner.peekNextToken();
  521. }
  522. token = scanner.getToken();
  523. if (token != GTKScanner.TOKEN_RIGHT_CURLY) {
  524. return GTKScanner.TOKEN_RIGHT_CURLY;
  525. }
  526. namedStyles.put(info.name, info);
  527. return GTKScanner.TOKEN_NONE;
  528. }
  529. private int parseBinding() throws IOException {
  530. int token;
  531. token = scanner.getToken();
  532. if (token != SYMBOL_BINDING.val) {
  533. return SYMBOL_BINDING.val;
  534. }
  535. token = scanner.getToken();
  536. if (token != GTKScanner.TOKEN_STRING) {
  537. return GTKScanner.TOKEN_STRING;
  538. }
  539. token = ignoreBlock();
  540. if (token != GTKScanner.TOKEN_NONE) {
  541. return token;
  542. }
  543. scanner.printMessage("Binding specification is unsupported, ignoring", false);
  544. return GTKScanner.TOKEN_NONE;
  545. }
  546. private int parsePixmapPath() throws IOException {
  547. int token;
  548. token = scanner.getToken();
  549. if (token != SYMBOL_PIXMAP_PATH.val) {
  550. return SYMBOL_PIXMAP_PATH.val;
  551. }
  552. token = scanner.getToken();
  553. if (token != GTKScanner.TOKEN_STRING) {
  554. return GTKScanner.TOKEN_STRING;
  555. }
  556. pixmapPaths = null;
  557. ArrayList tempPaths = new ArrayList();
  558. StringTokenizer tok = new StringTokenizer(scanner.currValue.stringVal, File.pathSeparator);
  559. while (tok.hasMoreTokens()) {
  560. String path = tok.nextToken();
  561. File file = new File(path);
  562. if (file.isAbsolute()) {
  563. tempPaths.add(file);
  564. } else {
  565. scanner.printMessage("Pixmap path element: \"" + path + "\" must be absolute", false);
  566. }
  567. }
  568. if (tempPaths.size() > 0) {
  569. pixmapPaths = new File[tempPaths.size()];
  570. pixmapPaths = (File[])tempPaths.toArray(pixmapPaths);
  571. }
  572. return GTKScanner.TOKEN_NONE;
  573. }
  574. private int parseAssignment(int expVal) throws IOException {
  575. int token;
  576. token = scanner.getToken();
  577. if (token != expVal) {
  578. return expVal;
  579. }
  580. int type;
  581. String pattern;
  582. StyleInfo info;
  583. boolean isBinding;
  584. if (token == SYMBOL_WIDGET.val) {
  585. type = GTKStyleFactory.WIDGET;
  586. } else if (token == SYMBOL_WIDGET_CLASS.val) {
  587. type = GTKStyleFactory.WIDGET_CLASS;
  588. } else if (token == SYMBOL_CLASS.val) {
  589. type = GTKStyleFactory.CLASS;
  590. } else {
  591. return SYMBOL_WIDGET_CLASS.val;
  592. }
  593. token = scanner.getToken();
  594. if (token != GTKScanner.TOKEN_STRING) {
  595. return GTKScanner.TOKEN_STRING;
  596. }
  597. pattern = scanner.currValue.stringVal;
  598. token = scanner.getToken();
  599. if (token == SYMBOL_STYLE.val) {
  600. isBinding = false;
  601. } else if (token == SYMBOL_BINDING.val) {
  602. isBinding = true;
  603. } else {
  604. return SYMBOL_STYLE.val;
  605. }
  606. token = scanner.peekNextToken();
  607. if (token == ':') {
  608. token = scanner.getToken();
  609. token = scanner.getToken();
  610. if (token != SYMBOL_LOWEST.val
  611. && token != SYMBOL_GTK.val
  612. && token != SYMBOL_APPLICATION.val
  613. && token != SYMBOL_THEME.val
  614. && token != SYMBOL_RC.val
  615. && token != SYMBOL_HIGHEST.val) {
  616. return SYMBOL_APPLICATION.val;
  617. }
  618. scanner.printMessage("Priority specification is unsupported, ignoring", false);
  619. }
  620. token = scanner.getToken();
  621. if (token != GTKScanner.TOKEN_STRING) {
  622. return GTKScanner.TOKEN_STRING;
  623. }
  624. // PENDING(shannonh) - When we start handling priority, the information will
  625. // probably be stored as part of an Assignment here
  626. if (isBinding) {
  627. // PENDING(shannonh) - Key binding support
  628. scanner.printMessage("Binding assignment is unsupported, ignoring", false);
  629. } else {
  630. info = (StyleInfo)namedStyles.get(scanner.currValue.stringVal);
  631. if (info == null) {
  632. return GTKScanner.TOKEN_STRING;
  633. }
  634. Assignment assignment = new Assignment(type, pattern, info);
  635. assignments.add(assignment);
  636. }
  637. return GTKScanner.TOKEN_NONE;
  638. }
  639. private int parseModulePath() throws IOException {
  640. int token;
  641. token = scanner.getToken();
  642. if (token != SYMBOL_MODULE_PATH.val) {
  643. return SYMBOL_MODULE_PATH.val;
  644. }
  645. token = scanner.getToken();
  646. if (token != GTKScanner.TOKEN_STRING) {
  647. return GTKScanner.TOKEN_STRING;
  648. }
  649. scanner.printMessage("module_path directive is now ignored", false);
  650. return GTKScanner.TOKEN_NONE;
  651. }
  652. private int parseIMModuleFile() throws IOException {
  653. int token;
  654. token = scanner.getToken();
  655. if (token != SYMBOL_IM_MODULE_FILE.val) {
  656. return SYMBOL_IM_MODULE_FILE.val;
  657. }
  658. token = scanner.getToken();
  659. if (token != GTKScanner.TOKEN_STRING) {
  660. return GTKScanner.TOKEN_STRING;
  661. }
  662. scanner.printMessage("im_module_file directive is unsupported, ignoring", false);
  663. return GTKScanner.TOKEN_NONE;
  664. }
  665. private int parseIdentifier() throws IOException {
  666. int token;
  667. token = scanner.getToken();
  668. if (token != GTKScanner.TOKEN_IDENTIFIER) {
  669. return GTKScanner.TOKEN_IDENTIFIER;
  670. }
  671. String prop;
  672. Object[] value = new Object[1];
  673. StringBuffer buf = new StringBuffer(scanner.currValue.stringVal);
  674. String validChars = GTKScanner.CHARS_A_2_Z
  675. + GTKScanner.CHARS_a_2_z
  676. + GTKScanner.CHARS_DIGITS
  677. + "-";
  678. // some weird logic that GTK does
  679. int len = buf.length();
  680. for (int i = 0; i < len; i++) {
  681. if (validChars.indexOf(buf.charAt(i)) == -1) {
  682. buf.setCharAt(i, '-');
  683. }
  684. }
  685. prop = buf.toString().intern();
  686. token = parsePropertyAssignment(value);
  687. if (token != GTKScanner.TOKEN_NONE) {
  688. return token;
  689. }
  690. settings.put(prop, value[0]);
  691. return GTKScanner.TOKEN_NONE;
  692. }
  693. private int parseColorSetting(int expVal, StyleInfo info) throws IOException {
  694. int token;
  695. token = scanner.getToken();
  696. if (token != expVal) {
  697. return expVal;
  698. }
  699. Color[] cols = null;
  700. if (token == SYMBOL_FG.val) {
  701. cols = info.fg;
  702. } else if (token == SYMBOL_BG.val) {
  703. cols = info.bg;
  704. } else if (token == SYMBOL_TEXT.val) {
  705. cols = info.text;
  706. } else if (token == SYMBOL_BASE.val) {
  707. cols = info.base;
  708. } else {
  709. return SYMBOL_FG.val;
  710. }
  711. int[] state = new int[1];
  712. token = parseState(state);
  713. if (token != GTKScanner.TOKEN_NONE) {
  714. return token;
  715. }
  716. token = scanner.getToken();
  717. if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
  718. return GTKScanner.TOKEN_EQUAL_SIGN;
  719. }
  720. return parseColor(cols, state[0]);
  721. }
  722. private int parseState(int[] retVal) throws IOException {
  723. int token;
  724. token = scanner.getToken();
  725. if (token != GTKScanner.TOKEN_LEFT_BRACE) {
  726. return GTKScanner.TOKEN_LEFT_BRACE;
  727. }
  728. token = scanner.getToken();
  729. if (token == SYMBOL_NORMAL.val) {
  730. retVal[0] = StyleInfo.NORMAL;
  731. } else if (token == SYMBOL_ACTIVE.val) {
  732. retVal[0] = StyleInfo.ACTIVE;
  733. } else if (token == SYMBOL_PRELIGHT.val) {
  734. retVal[0] = StyleInfo.PRELIGHT;
  735. } else if (token == SYMBOL_SELECTED.val) {
  736. retVal[0] = StyleInfo.SELECTED;
  737. } else if (token == SYMBOL_INSENSITIVE.val) {
  738. retVal[0] = StyleInfo.INSENSITIVE;
  739. } else {
  740. return SYMBOL_NORMAL.val;
  741. }
  742. token = scanner.getToken();
  743. if (token != GTKScanner.TOKEN_RIGHT_BRACE) {
  744. return GTKScanner.TOKEN_RIGHT_BRACE;
  745. }
  746. return GTKScanner.TOKEN_NONE;
  747. }
  748. private int parseColor(Color[] colors, int index) throws IOException {
  749. int token;
  750. long lVal;
  751. double dVal;
  752. float red;
  753. float green;
  754. float blue;
  755. token = scanner.getToken();
  756. switch(token) {
  757. case GTKScanner.TOKEN_LEFT_CURLY:
  758. token = scanner.getToken();
  759. if (token == GTKScanner.TOKEN_INT) {
  760. red = javaColorVal(scanner.currValue.longVal);
  761. } else if (token == GTKScanner.TOKEN_FLOAT) {
  762. red = javaColorVal(scanner.currValue.doubleVal);
  763. } else {
  764. return GTKScanner.TOKEN_FLOAT;
  765. }
  766. token = scanner.getToken();
  767. if (token != GTKScanner.TOKEN_COMMA) {
  768. return GTKScanner.TOKEN_COMMA;
  769. }
  770. token = scanner.getToken();
  771. if (token == GTKScanner.TOKEN_INT) {
  772. green = javaColorVal(scanner.currValue.longVal);
  773. } else if (token == GTKScanner.TOKEN_FLOAT) {
  774. green = javaColorVal(scanner.currValue.doubleVal);
  775. } else {
  776. return GTKScanner.TOKEN_FLOAT;
  777. }
  778. token = scanner.getToken();
  779. if (token != GTKScanner.TOKEN_COMMA) {
  780. return GTKScanner.TOKEN_COMMA;
  781. }
  782. token = scanner.getToken();
  783. if (token == GTKScanner.TOKEN_INT) {
  784. blue = javaColorVal(scanner.currValue.longVal);
  785. } else if (token == GTKScanner.TOKEN_FLOAT) {
  786. blue = javaColorVal(scanner.currValue.doubleVal);
  787. } else {
  788. return GTKScanner.TOKEN_FLOAT;
  789. }
  790. token = scanner.getToken();
  791. if (token != GTKScanner.TOKEN_RIGHT_CURLY) {
  792. return GTKScanner.TOKEN_RIGHT_CURLY;
  793. }
  794. colors[index] = new ColorUIResource(red, green, blue);
  795. break;
  796. case GTKScanner.TOKEN_STRING:
  797. Color color = parseColorString(scanner.currValue.stringVal);
  798. if (color == null) {
  799. scanner.printMessage("Invalid color constant '" +
  800. scanner.currValue.stringVal
  801. + "'", false);
  802. return GTKScanner.TOKEN_STRING;
  803. }
  804. colors[index] = color;
  805. break;
  806. default:
  807. return GTKScanner.TOKEN_STRING;
  808. }
  809. return GTKScanner.TOKEN_NONE;
  810. }
  811. private static Color parseColorString(String str) {
  812. if (str.charAt(0) == '#') {
  813. str = str.substring(1);
  814. int i = str.length();
  815. if (i < 3 || i > 12 || (i % 3) != 0) {
  816. return null;
  817. }
  818. i /= 3;
  819. int r;
  820. int g;
  821. int b;
  822. try {
  823. r = Integer.parseInt(str.substring(0, i), 16);
  824. g = Integer.parseInt(str.substring(i, i * 2), 16);
  825. b = Integer.parseInt(str.substring(i * 2, i * 3), 16);
  826. } catch (NumberFormatException nfe) {
  827. return null;
  828. }
  829. if (i == 4) {
  830. return new ColorUIResource(r / 65535.0f, g / 65535.0f, b / 65535.0f);
  831. } else if (i == 1) {
  832. return new ColorUIResource(r / 15.0f, g / 15.0f, b / 15.0f);
  833. } else if (i == 2) {
  834. return new ColorUIResource(r, g, b);
  835. } else {
  836. return new ColorUIResource(r / 4095.0f, g / 4095.0f, b / 4095.0f);
  837. }
  838. } else {
  839. return XColors.lookupColor(str);
  840. }
  841. }
  842. private static float javaColorVal(long col) {
  843. int color = (int)Math.max(Math.min(col, 65535), 0);
  844. return col / 65535.0f;
  845. }
  846. private static float javaColorVal(double col) {
  847. float color = (float)Math.max(Math.min(col, 1.0f), 0.0f);
  848. return color;
  849. }
  850. private int parseThickness(int expVal, StyleInfo info) throws IOException {
  851. int token;
  852. boolean isXThickness;
  853. token = scanner.getToken();
  854. if (token != expVal) {
  855. return expVal;
  856. }
  857. if (token == SYMBOL_XTHICKNESS.val) {
  858. isXThickness = true;
  859. } else if (token == SYMBOL_YTHICKNESS.val) {
  860. isXThickness = false;
  861. } else {
  862. return SYMBOL_XTHICKNESS.val;
  863. }
  864. token = scanner.getToken();
  865. if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
  866. return GTKScanner.TOKEN_EQUAL_SIGN;
  867. }
  868. token = scanner.getToken();
  869. if (token != GTKScanner.TOKEN_INT) {
  870. return GTKScanner.TOKEN_INT;
  871. }
  872. int thickness = (int)scanner.currValue.longVal;
  873. if (isXThickness) {
  874. info.xThickness = thickness;
  875. } else {
  876. info.yThickness = thickness;
  877. }
  878. return GTKScanner.TOKEN_NONE;
  879. }
  880. private int parseBGPixmap(StyleInfo info) throws IOException {
  881. int token;
  882. token = scanner.getToken();
  883. if (token != SYMBOL_BG_PIXMAP.val) {
  884. return SYMBOL_BG_PIXMAP.val;
  885. }
  886. int[] state = new int[1];
  887. token = parseState(state);
  888. if (token != GTKScanner.TOKEN_NONE) {
  889. return token;
  890. }
  891. token = scanner.getToken();
  892. if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
  893. return GTKScanner.TOKEN_EQUAL_SIGN;
  894. }
  895. token = scanner.getToken();
  896. if (token != GTKScanner.TOKEN_STRING) {
  897. return GTKScanner.TOKEN_STRING;
  898. }
  899. String pixmapStr = null;
  900. String str = scanner.currValue.stringVal;
  901. if (str.equals("<none>") || str.equals("<parent>")) {
  902. pixmapStr = str.intern();
  903. } else {
  904. pixmapStr = resolvePixmapPath(str);
  905. }
  906. if (pixmapStr == null) {
  907. scanner.printMessage("Unable to locate image file in pixmap_path: \"" + str + "\"", false);
  908. } else {
  909. info.bgPixmapName[state[0]] = pixmapStr;
  910. }
  911. return GTKScanner.TOKEN_NONE;
  912. }
  913. String resolvePixmapPath(String str) {
  914. // search in pixmap path
  915. if (pixmapPaths != null) {
  916. for (int i = 0; i < pixmapPaths.length; i++) {
  917. File file = new File(pixmapPaths[i], str);
  918. if (file.canRead()) {
  919. return file.getAbsolutePath();
  920. }
  921. }
  922. }
  923. // search in rc directory stack
  924. File[] dirs = new File[dirStack.size()];
  925. dirs = (File[])dirStack.toArray(dirs);
  926. for (int i = dirs.length - 1; i >= 0; i--) {
  927. File file = new File(dirs[i], str);
  928. if (file.canRead()) {
  929. return file.getAbsolutePath();
  930. }
  931. }
  932. return null;
  933. }
  934. private int parseFont(int expVal, StyleInfo info) throws IOException {
  935. int token;
  936. boolean isPango;
  937. token = scanner.getToken();
  938. if (token != expVal) {
  939. return expVal;
  940. }
  941. if (token == SYMBOL_FONT_NAME.val) {
  942. isPango = true;
  943. } else if (token == SYMBOL_FONT.val
  944. || token == SYMBOL_FONTSET.val) {
  945. isPango = false;
  946. } else {
  947. return SYMBOL_FONT_NAME.val;
  948. }
  949. token = scanner.getToken();
  950. if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
  951. return GTKScanner.TOKEN_EQUAL_SIGN;
  952. }
  953. token = scanner.getToken();
  954. if (token != GTKScanner.TOKEN_STRING) {
  955. return GTKScanner.TOKEN_STRING;
  956. }
  957. // only need to parse pango font names
  958. if (isPango) {
  959. String pangoName = scanner.currValue.stringVal;
  960. info.font = PangoFonts.lookupFont(pangoName);
  961. }
  962. return GTKScanner.TOKEN_NONE;
  963. }
  964. private GTKEngineParser getParser(String engineName) {
  965. Object o = engineParsers.get(engineName);
  966. if (o == null) {
  967. return null;
  968. }
  969. if (o instanceof GTKEngineParser) {
  970. return (GTKEngineParser)o;
  971. }
  972. GTKEngineParser parser = null;
  973. try {
  974. parser = (GTKEngineParser)Class.forName((String)o).newInstance();
  975. } catch (ClassNotFoundException e) {
  976. } catch (InstantiationException e) {
  977. } catch (IllegalAccessException e) {
  978. }
  979. if (parser == null) {
  980. // no need to keep trying to load it every time
  981. engineParsers.remove(engineName);
  982. } else {
  983. // replace the name with an instance of a parser
  984. engineParsers.put(engineName, parser);
  985. }
  986. return parser;
  987. }
  988. private int parseEngine(StyleInfo info) throws IOException {
  989. int token;
  990. token = scanner.getToken();
  991. if (token != SYMBOL_ENGINE.val) {
  992. return SYMBOL_ENGINE.val;
  993. }
  994. token = scanner.getToken();
  995. if (token != GTKScanner.TOKEN_STRING) {
  996. return GTKScanner.TOKEN_STRING;
  997. }
  998. String engineName = scanner.currValue.stringVal;
  999. // engine "" {} means to use the default engine
  1000. if (engineName.length() == 0) {
  1001. token = scanner.getToken();
  1002. if (token != GTKScanner.TOKEN_LEFT_CURLY) {
  1003. return GTKScanner.TOKEN_LEFT_CURLY;
  1004. }
  1005. token = scanner.getToken();
  1006. if (token != GTKScanner.TOKEN_RIGHT_CURLY) {
  1007. return GTKScanner.TOKEN_RIGHT_CURLY;
  1008. }
  1009. info.engineInfo = null;
  1010. return GTKScanner.TOKEN_NONE;
  1011. }
  1012. GTKEngineParser parser = getParser(engineName);
  1013. if (parser == null) {
  1014. token = ignoreBlock();
  1015. if (token != GTKScanner.TOKEN_NONE) {
  1016. return token;
  1017. }
  1018. scanner.printMessage("Engine \"" + engineName + "\" is unsupported, ignoring", false);
  1019. } else {
  1020. token = scanner.getToken();
  1021. if (token != GTKScanner.TOKEN_LEFT_CURLY) {
  1022. return GTKScanner.TOKEN_LEFT_CURLY;
  1023. }
  1024. EngineInfo[] engineInfo = new EngineInfo[1];
  1025. // only pass in the existing engine info if it came from this parser
  1026. if (info.engineInfo != null && engineName.equals(info.engineInfo.engineName)) {
  1027. engineInfo[0] = info.engineInfo;
  1028. }
  1029. token = parser.parse(scanner, this, engineInfo);
  1030. if (token != GTKScanner.TOKEN_NONE) {
  1031. return token;
  1032. }
  1033. // tag the returned engine info with the engine name
  1034. if (engineInfo[0] != null) {
  1035. engineInfo[0].engineName = engineName;
  1036. }
  1037. info.engineInfo = engineInfo[0];
  1038. }
  1039. return GTKScanner.TOKEN_NONE;
  1040. }
  1041. private int parseStock(StyleInfo info) throws IOException {
  1042. String id;
  1043. int token;
  1044. token = scanner.getToken();
  1045. if (token != SYMBOL_STOCK.val) {
  1046. return SYMBOL_STOCK.val;
  1047. }
  1048. token = scanner.getToken();
  1049. if (token != GTKScanner.TOKEN_LEFT_BRACE) {
  1050. return GTKScanner.TOKEN_LEFT_BRACE;
  1051. }
  1052. token = scanner.getToken();
  1053. if (token != GTKScanner.TOKEN_STRING) {
  1054. return GTKScanner.TOKEN_STRING;
  1055. }
  1056. id = scanner.currValue.stringVal;
  1057. token = scanner.getToken();
  1058. if (token != GTKScanner.TOKEN_RIGHT_BRACE) {
  1059. return GTKScanner.TOKEN_RIGHT_BRACE;
  1060. }
  1061. token = scanner.getToken();
  1062. if (token != GTKScanner.TOKEN_EQUAL_SIGN) {
  1063. return GTKScanner.TOKEN_EQUAL_SIGN;
  1064. }
  1065. token = scanner.getToken();
  1066. if (token != GTKScanner.TOKEN_LEFT_CURLY) {
  1067. return GTKScanner.TOKEN_LEFT_CURLY;
  1068. }
  1069. ArrayList iconSources = new ArrayList();
  1070. // This array will be used first to hold the return value from
  1071. // parseIconSource and then the variable will be used in
  1072. // converting iconSources to an array.
  1073. GTKStyle.GTKIconSource[] sources = new GTKStyle.GTKIconSource[1];
  1074. token = scanner.peekNextToken();
  1075. while (token != GTKScanner.TOKEN_RIGHT_CURLY) {
  1076. token = parseIconSource(sources);
  1077. if (token != GTKScanner.TOKEN_NONE) {
  1078. return token;
  1079. }
  1080. token = scanner.getToken();
  1081. if (token != GTKScanner.TOKEN_COMMA
  1082. && token != GTKScanner.TOKEN_RIGHT_CURLY) {
  1083. return GTKScanner.TOKEN_RIGHT_CURLY;
  1084. }
  1085. if (sources[0] != null) {
  1086. iconSources.add(sources[0]);
  1087. }
  1088. }
  1089. if (iconSources.size() != 0) {
  1090. sources = new GTKStyle.GTKIconSource[iconSources.size()];
  1091. sources = (GTKStyle.GTKIconSource[])iconSources.toArray(sources);
  1092. info.addStockItem(id, sources);
  1093. }
  1094. return GTKScanner.TOKEN_NONE;
  1095. }
  1096. private GTKStyle.GTKIconSource createIconSource(String path,
  1097. int direction,
  1098. int state,
  1099. String size) {
  1100. String resolvedPath = resolvePixmapPath(path);
  1101. if (resolvedPath != null) {
  1102. return new GTKStyle.GTKIconSource(resolvedPath, direction, state, size);
  1103. }
  1104. return null;
  1105. }
  1106. private int parseIconSource(GTKStyle.GTKIconSource[] retVal) throws IOException {
  1107. int token;
  1108. String pixmapStr = null;
  1109. int direction = GTKConstants.UNDEFINED;
  1110. int state = GTKConstants.UNDEFINED;
  1111. String size = null;
  1112. token = scanner.getToken();
  1113. if (token != GTKScanner.TOKEN_LEFT_CURLY) {
  1114. return GTKScanner.TOKEN_LEFT_CURLY;
  1115. }
  1116. token = scanner.getToken();
  1117. if (token != GTKScanner.TOKEN_STRING) {
  1118. return GTKScanner.TOKEN_STRING;
  1119. }
  1120. pixmapStr = scanner.currValue.stringVal;
  1121. token = scanner.getToken();
  1122. if (token == GTKScanner.TOKEN_RIGHT_CURLY) {
  1123. retVal[0] = createIconSource(pixmapStr, direction, state, size);
  1124. return GTKScanner.TOKEN_NONE;
  1125. } else if (token != GTKScanner.TOKEN_COMMA) {
  1126. return GTKScanner.TOKEN_COMMA;
  1127. }
  1128. token = scanner.getToken();
  1129. if (token == SYMBOL_RTL.val) {
  1130. direction = GTKConstants.RTL;
  1131. } else if (token == SYMBOL_LTR.val) {
  1132. direction = GTKConstants.LTR;
  1133. } else if (token == '*') {
  1134. // nothing
  1135. } else {
  1136. return SYMBOL_RTL.val;
  1137. }
  1138. token = scanner.getToken();
  1139. if (token == GTKScanner.TOKEN_RIGHT_CURLY) {
  1140. retVal[0] = createIconSource(pixmapStr, direction, state, size);
  1141. return GTKScanner.TOKEN_NONE;
  1142. } else if (token != GTKScanner.TOKEN_COMMA) {
  1143. return GTKScanner.TOKEN_COMMA;
  1144. }
  1145. token = scanner.getToken();
  1146. if (token == SYMBOL_NORMAL.val) {
  1147. state = SynthConstants.ENABLED;
  1148. } else if (token == SYMBOL_ACTIVE.val) {
  1149. state = SynthConstants.PRESSED;
  1150. } else if (token == SYMBOL_PRELIGHT.val) {
  1151. state = SynthConstants.MOUSE_OVER;
  1152. } else if (token == SYMBOL_SELECTED.val) {
  1153. state = SynthConstants.SELECTED;
  1154. } else if (token == SYMBOL_INSENSITIVE.val) {
  1155. state = SynthConstants.DISABLED;
  1156. } else if (token == '*') {
  1157. // nothing
  1158. } else {
  1159. return SYMBOL_PRELIGHT.val;
  1160. }
  1161. token = scanner.getToken();
  1162. if (token == GTKScanner.TOKEN_RIGHT_CURLY) {
  1163. retVal[0] = createIconSource(pixmapStr, direction, state, size);
  1164. return GTKScanner.TOKEN_NONE;
  1165. } else if (token != GTKScanner.TOKEN_COMMA) {
  1166. return GTKScanner.TOKEN_COMMA;
  1167. }
  1168. token = scanner.getToken();
  1169. if (token != '*') {
  1170. if (token != GTKScanner.TOKEN_STRING) {
  1171. return GTKScanner.TOKEN_STRING;
  1172. }
  1173. size = scanner.currValue.stringVal;
  1174. // if an invalid size, use * instead
  1175. if (GTKStyle.getIconSize(size) == null) {
  1176. size = null;
  1177. }
  1178. }
  1179. token = scanner.getToken();
  1180. if (token != GTKScanner.TOKEN_RIGHT_CURLY) {
  1181. return GTKScanner.TOKEN_RIGHT_CURLY;
  1182. }
  1183. retVal[0] = createIconSource(pixmapStr, direction, state, size);
  1184. return GTKScanner.TOKEN_NONE;
  1185. }
  1186. private int parseIdentifierInStyle(StyleInfo info) throws IOException {
  1187. int token;
  1188. token = scanner.getToken();
  1189. if (token != GTKScanner.TOKEN_IDENTIFIER
  1190. || scanner.currValue.stringVal.charAt(0) < 'A'
  1191. || scanner.currValue.stringVal.charAt(0) > 'Z') {
  1192. return GTKScanner.TOKEN_IDENTIFIER;
  1193. }
  1194. String klass;
  1195. String prop;
  1196. Object[] value = new Object[1];
  1197. klass = scanner.currValue.stringVal.intern();
  1198. // check the next two tokens to make sure they're both ':'
  1199. if (scanner.getToken() != ':' || scanner.getToken() != ':') {
  1200. return ':';
  1201. }
  1202. token = scanner.getToken();
  1203. if (token != GTKScanner.TOKEN_IDENTIFIER) {
  1204. return GTKScanner.TOKEN_IDENTIFIER;
  1205. }
  1206. StringBuffer buf = new StringBuffer(scanner.currValue.stringVal);
  1207. String validChars = GTKScanner.CHARS_A_2_Z
  1208. + GTKScanner.CHARS_a_2_z
  1209. + GTKScanner.CHARS_DIGITS
  1210. + "-";
  1211. // some weird logic that GTK does
  1212. int len = buf.length();
  1213. for (int i = 0; i < len; i++) {
  1214. if (validChars.indexOf(buf.charAt(i)) == -1) {
  1215. buf.setCharAt(i, '-');
  1216. }
  1217. }
  1218. prop = buf.toString().intern();
  1219. token = parsePropertyAssignment(value);
  1220. if (token != GTKScanner.TOKEN_NONE) {
  1221. return token;
  1222. }
  1223. PropertyParser pp = null;
  1224. if (value[0] instanceof String && (pp = PropertyParser.getParserFor(prop)) != null) {
  1225. Object parsedVal = pp.parse((String)value[0]);
  1226. if (parsedVal == null) {
  1227. scanner.printMessage("Failed to parse property value \"" + value[0] + "\" for `"
  1228. + klass + "::" + prop + "'", false);
  1229. } else {
  1230. info.addProperty(klass, prop, parsedVal);
  1231. }
  1232. } else {
  1233. info.addProperty(klass, prop, value[0]);
  1234. }
  1235. return GTKScanner.TOKEN_NONE;
  1236. }
  1237. private int parsePropertyAssignment(Object[] retVal) throws IOException {
  1238. int token;
  1239. token = scanner.getToken();
  1240. if (token != '=') {
  1241. return '=';
  1242. }
  1243. // save the scanner mode
  1244. boolean scanIdentifier = scanner.scanIdentifier;
  1245. boolean scanSymbols = scanner.scanSymbols;
  1246. boolean identifier2String = scanner.identifier2String;
  1247. boolean char2Token = scanner.char2Token;
  1248. boolean scanIdentifierNULL = scanner.scanIdentifierNULL;
  1249. boolean numbers2Int = scanner.numbers2Int;
  1250. // modify the scanner mode for our purposes
  1251. scanner.scanIdentifier = true;
  1252. scanner.scanSymbols = false;
  1253. scanner.identifier2String = false;
  1254. scanner.char2Token = true;
  1255. scanner.scanIdentifierNULL = false;
  1256. scanner.numbers2Int = true;
  1257. boolean negate = false;
  1258. if (scanner.peekNextToken() == '-') {
  1259. scanner.getToken();
  1260. negate = true;
  1261. }
  1262. token = scanner.peekNextToken();
  1263. switch(token) {
  1264. case GTKScanner.TOKEN_INT:
  1265. scanner.getToken();
  1266. retVal[0] = new Long(negate ? -scanner.currValue.longVal : scanner.currValue.longVal);
  1267. token = GTKScanner.TOKEN_NONE;
  1268. break;
  1269. case GTKScanner.TOKEN_FLOAT:
  1270. scanner.getToken();
  1271. retVal[0] = new Double(negate ? -scanner.currValue.doubleVal : scanner.currValue.doubleVal);
  1272. token = GTKScanner.TOKEN_NONE;
  1273. break;
  1274. case GTKScanner.TOKEN_STRING:
  1275. scanner.getToken();
  1276. if (negate) {
  1277. token = GTKScanner.TOKEN_INT;
  1278. } else {
  1279. retVal[0] = scanner.currValue.stringVal;
  1280. token = GTKScanner.TOKEN_NONE;
  1281. }
  1282. break;
  1283. case GTKScanner.TOKEN_IDENTIFIER:
  1284. case GTKScanner.TOKEN_LEFT_PAREN:
  1285. case GTKScanner.TOKEN_LEFT_CURLY:
  1286. case GTKScanner.TOKEN_LEFT_BRACE:
  1287. if (negate) {
  1288. token = GTKScanner.TOKEN_INT;
  1289. } else {
  1290. StringBuffer result = new StringBuffer();
  1291. token = parseComplexPropVal(result, GTKScanner.TOKEN_EOF);
  1292. if (token == GTKScanner.TOKEN_NONE) {
  1293. result.append(' ');
  1294. retVal[0] = result.toString();
  1295. }
  1296. }
  1297. break;
  1298. default:
  1299. scanner.getToken();
  1300. token = GTKScanner.TOKEN_INT;
  1301. break;
  1302. }
  1303. // restore the scanner mode
  1304. scanner.scanIdentifier = scanIdentifier;
  1305. scanner.scanSymbols = scanSymbols;
  1306. scanner.identifier2String = identifier2String;
  1307. scanner.char2Token = char2Token;
  1308. scanner.scanIdentifierNULL = scanIdentifierNULL;
  1309. scanner.numbers2Int = numbers2Int;
  1310. return token;
  1311. }
  1312. private int parseComplexPropVal(StringBuffer into, int delim) throws IOException {
  1313. int token;
  1314. token = scanner.getToken();
  1315. switch(token) {
  1316. case GTKScanner.TOKEN_INT:
  1317. into.append(" 0x");
  1318. into.append(Long.toHexString(scanner.currValue.longVal));
  1319. break;
  1320. case GTKScanner.TOKEN_FLOAT:
  1321. into.append(' ');
  1322. into.append(scanner.currValue.doubleVal);
  1323. break;
  1324. case GTKScanner.TOKEN_STRING:
  1325. into.append(" \"");
  1326. into.append(escapeString(scanner.currValue.stringVal));
  1327. into.append('"');
  1328. break;
  1329. case GTKScanner.TOKEN_IDENTIFIER:
  1330. into.append(' ');
  1331. into.append(scanner.currValue.stringVal);
  1332. break;
  1333. case GTKScanner.TOKEN_LEFT_PAREN:
  1334. into.append(' ');
  1335. into.append((char)token);
  1336. token = parseComplexPropVal(into, GTKScanner.TOKEN_RIGHT_PAREN);
  1337. if (token != GTKScanner.TOKEN_NONE) {
  1338. return token;
  1339. }
  1340. break;
  1341. case GTKScanner.TOKEN_LEFT_CURLY:
  1342. into.append(' ');
  1343. into.append((char)token);
  1344. token = parseComplexPropVal(into, GTKScanner.TOKEN_RIGHT_CURLY);
  1345. if (token != GTKScanner.TOKEN_NONE) {
  1346. return token;
  1347. }
  1348. break;
  1349. case GTKScanner.TOKEN_LEFT_BRACE:
  1350. into.append(' ');
  1351. into.append((char)token);
  1352. token = parseComplexPropVal(into, GTKScanner.TOKEN_RIGHT_BRACE);
  1353. if (token != GTKScanner.TOKEN_NONE) {
  1354. return token;
  1355. }
  1356. break;
  1357. default:
  1358. if (token >= GTKScanner.TOKEN_NONE || token <= GTKScanner.TOKEN_EOF) {
  1359. return delim != GTKScanner.TOKEN_EOF ? delim : GTKScanner.TOKEN_STRING;
  1360. }
  1361. into.append(' ');
  1362. into.append((char)token);
  1363. if (token == delim) {
  1364. return GTKScanner.TOKEN_NONE;
  1365. }
  1366. }
  1367. if (delim == GTKScanner.TOKEN_EOF) {
  1368. return GTKScanner.TOKEN_NONE;
  1369. } else {
  1370. return parseComplexPropVal(into, delim);
  1371. }
  1372. }
  1373. private String escapeString(String source) {
  1374. int len = source.length();
  1375. StringBuffer result = new StringBuffer(len * 4);
  1376. for (int i = 0; i < len; i++) {
  1377. char ch = source.charAt(i);
  1378. switch(ch) {
  1379. case '\b':
  1380. result.append("\\b");
  1381. break;
  1382. case '\f':
  1383. result.append("\\f");
  1384. break;
  1385. case '\n':
  1386. result.append("\\n");
  1387. break;
  1388. case '\r':
  1389. result.append("\\r");
  1390. break;
  1391. case '\t':
  1392. result.append("\\t");
  1393. break;
  1394. case '\\':
  1395. result.append("\\\\");
  1396. break;
  1397. case '"':
  1398. result.append("\\\"");
  1399. break;
  1400. default:
  1401. if (ch < ' ' || ch > '~') {
  1402. result.append('\\');
  1403. result.append(Integer.toOctalString(ch));
  1404. } else {
  1405. result.append((char)ch);
  1406. }
  1407. break;
  1408. }
  1409. }
  1410. return result.toString();
  1411. }
  1412. private int ignoreBlock() throws IOException {
  1413. int token;
  1414. token = scanner.getToken();
  1415. if (token != GTKScanner.TOKEN_LEFT_CURLY) {
  1416. return GTKScanner.TOKEN_LEFT_CURLY;
  1417. }
  1418. int curlys = 1;
  1419. while (curlys > 0) {
  1420. token = scanner.getToken();
  1421. switch(token) {
  1422. case GTKScanner.TOKEN_EOF:
  1423. return GTKScanner.TOKEN_RIGHT_CURLY;
  1424. case GTKScanner.TOKEN_LEFT_CURLY:
  1425. curlys++;
  1426. break;
  1427. case GTKScanner.TOKEN_RIGHT_CURLY:
  1428. curlys--;
  1429. break;
  1430. default:
  1431. // ignore
  1432. }
  1433. }
  1434. return GTKScanner.TOKEN_NONE;
  1435. }
  1436. // for testing
  1437. public static void main(String[] args) {
  1438. if (args.length == 0) {
  1439. System.err.println("Usage: java GTKParser <gtkrc file> <gtkrc file>....");
  1440. System.exit(1);
  1441. }
  1442. GTKParser parser = new GTKParser();
  1443. try {
  1444. for (int i = 0; i < args.length; i++) {
  1445. parser.parseFile(new File(args[i]), args[i]);
  1446. }
  1447. } catch (IOException ioe) {
  1448. ioe.printStackTrace();
  1449. }
  1450. parser.printNamedStyles();
  1451. System.out.println();
  1452. parser.printSettings();
  1453. System.out.println();
  1454. parser.printAssignments();
  1455. }
  1456. // for testing
  1457. private void printNamedStyles() {
  1458. System.out.println("===== Named Styles =====");
  1459. StyleInfo[] infos = new StyleInfo[namedStyles.size()];
  1460. infos = (StyleInfo[])namedStyles.values().toArray(infos);
  1461. for (int i = 0; i < infos.length; i++) {
  1462. StyleInfo info = infos[i];
  1463. System.out.println("NAME: " + info.name);
  1464. GTKStyle style = info.toGTKStyle();
  1465. System.out.println(style == StyleInfo.EMPTY_STYLE ? "EMPTY_STYLE" : style.toString());
  1466. System.out.println("---------------------------");
  1467. }
  1468. }
  1469. // for testing
  1470. private void printSettings() {
  1471. System.out.println("===== GTK Settings =====");
  1472. Iterator iter = settings.entrySet().iterator();
  1473. while (iter.hasNext()) {
  1474. Map.Entry entry = (Map.Entry)iter.next();
  1475. System.out.println(entry.getKey() + "=" + entry.getValue());
  1476. }
  1477. }
  1478. // for testing
  1479. private void printAssignments() {
  1480. System.out.println("===== Assignments =====");
  1481. Assignment[] assigns = new Assignment[assignments.size()];
  1482. assigns = (Assignment[])assignments.toArray(assigns);
  1483. for (int i = 0; i < assigns.length; i++) {
  1484. System.out.println(assigns[i]);
  1485. }
  1486. }
  1487. }