0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package javax.swing.plaf.synth;
0019:
0020: import java.awt.Color;
0021: import java.awt.Dimension;
0022: import java.awt.Font;
0023: import java.awt.Insets;
0024: import java.beans.XMLDecoder;
0025: import java.io.ByteArrayInputStream;
0026: import java.io.IOException;
0027: import java.net.URL;
0028: import java.util.Arrays;
0029: import java.util.HashMap;
0030: import java.util.LinkedList;
0031: import java.util.List;
0032: import java.util.Map;
0033: import java.util.StringTokenizer;
0034:
0035: import javax.swing.Icon;
0036: import javax.swing.ImageIcon;
0037: import javax.swing.JSplitPane;
0038: import javax.swing.SwingConstants;
0039: import javax.swing.UIManager;
0040:
0041: import org.apache.harmony.x.swing.internal.nls.Messages;
0042: import org.xml.sax.Attributes;
0043: import org.xml.sax.SAXException;
0044: import org.xml.sax.helpers.DefaultHandler;
0045:
0046: /**
0047: * XMLSynthParser creates a set of SynthStyles that satisfied XML description of
0048: * the look and feel. SynthLookAndFeel can access to the styles through
0049: * SynthFactory
0050: */
0051: class XMLSynthParser extends DefaultHandler {
0052:
0053: /* All the known elements */
0054: private static final String STYLE_ELEMENT = "style"; //$NON-NLS-1$
0055:
0056: private static final String STATE_ELEMENT = "state"; //$NON-NLS-1$
0057:
0058: private static final String FONT_ELEMENT = "font"; //$NON-NLS-1$
0059:
0060: private static final String COLOR_ELEMENT = "color"; //$NON-NLS-1$
0061:
0062: private static final String G_UTILS_ELEMENT = "graphicsUtils"; //$NON-NLS-1$
0063:
0064: private static final String DEFAULTS_ELEMENT = "defaultsProperty"; //$NON-NLS-1$
0065:
0066: private static final String INSETS_ELEMENT = "insets"; //$NON-NLS-1$
0067:
0068: private static final String OPAQUE_ELEMENT = "opaque"; //$NON-NLS-1$
0069:
0070: private static final String PROPERTY_ELEMENT = "property"; //$NON-NLS-1$
0071:
0072: private static final String BIND_ELEMENT = "bind"; //$NON-NLS-1$
0073:
0074: private static final String IM_PAINTER_ELEMENT = "imagePainter"; //$NON-NLS-1$
0075:
0076: private static final String PAINTER_ELEMENT = "painter"; //$NON-NLS-1$
0077:
0078: private static final String IMAGE_ICON_ELEMENT = "imageIcon"; //$NON-NLS-1$
0079:
0080: private static final String SYNTH_ELEMENT = "synth"; //$NON-NLS-1$
0081:
0082: /**
0083: * BeansAdapter to process unknown elements
0084: */
0085: private final BeansAdapter adapter = new BeansAdapter();
0086:
0087: /**
0088: * The base used for correct URL creating
0089: */
0090: private final Class<?> base;
0091:
0092: /**
0093: * The marking for default state. Used in parser to mark state as default
0094: * and indirectly in XMLSynthStyle in findColorForState, findFontForState
0095: * methods.
0096: */
0097: private final int DEFAULT_STATE = 0;
0098:
0099: /**
0100: * The XMLStyleFactory to add configured styles
0101: */
0102: private final DefaultStyleFactory styleFactory = new DefaultStyleFactory();
0103:
0104: /**
0105: * Map used for correct references processing. Key is Element id in xml
0106: * style. Value is the element to be inserted in the style
0107: */
0108: private final Map<String, Object> namedElements = new HashMap<String, Object>();
0109:
0110: /**
0111: * Map used for correct references processing. Key is the complex key (see
0112: * private class below). Value is the SynthStyle to be value from
0113: * namedElements be inserted
0114: */
0115: private final Map<XMLSynthKey, XMLSynthStyle> namedReferences = new HashMap<XMLSynthKey, XMLSynthStyle>();
0116:
0117: /**
0118: * The style under modification
0119: */
0120: private XMLSynthStyle currentStyle;
0121:
0122: /**
0123: * State marking
0124: */
0125: private int currentState;
0126:
0127: /**
0128: * The colors, that can be obtained from the string description
0129: */
0130: enum Colors {
0131: RED(Color.RED), GREEN(Color.GREEN), BLUE(Color.BLUE), CYAN(
0132: Color.CYAN), BLACK(Color.BLACK), WHITE(Color.WHITE), GRAY(
0133: Color.GRAY), DARK_GRAY(Color.DARK_GRAY), ORANGE(
0134: Color.ORANGE), YELLOW(Color.YELLOW);
0135:
0136: final Color color;
0137:
0138: Colors(Color color) {
0139:
0140: this .color = color;
0141: }
0142: }
0143:
0144: /**
0145: * The directions used in Painters, that can be obtained from the string
0146: * description
0147: */
0148: enum Directions {
0149: EAST(SwingConstants.EAST), NORTH(SwingConstants.NORTH), SOUTH(
0150: SwingConstants.SOUTH), WEST(SwingConstants.WEST), TOP(
0151: SwingConstants.TOP), BOTTOM(SwingConstants.BOTTOM), LEFT(
0152: SwingConstants.LEFT), RIGHT(SwingConstants.RIGHT), HORIZONTAL(
0153: SwingConstants.HORIZONTAL), VERTICAL(
0154: SwingConstants.VERTICAL), HORIZONTAL_SPLIT(
0155: JSplitPane.HORIZONTAL_SPLIT), VERTICAL_SPLIT(
0156: JSplitPane.VERTICAL_SPLIT);
0157:
0158: final int direction;
0159:
0160: Directions(int direction) {
0161:
0162: this .direction = direction;
0163: }
0164: }
0165:
0166: XMLSynthParser(Class<?> resourseBase) {
0167: this .base = resourseBase;
0168: }
0169:
0170: /**
0171: * Process all the known tags
0172: */
0173: @Override
0174: public void startElement(String namespaceURI, String localName,
0175: String qName, Attributes attrs) throws SAXException {
0176:
0177: String element = ("".equals(localName)) ? qName.intern() : //$NON-NLS-1$
0178: localName.intern();
0179:
0180: if (element == STYLE_ELEMENT) {
0181:
0182: processStyleElement(attrs);
0183:
0184: } else if (element == STATE_ELEMENT) {
0185:
0186: currentState = computeStateValue(attrs.getValue("value")); //$NON-NLS-1$
0187:
0188: } else if (element == FONT_ELEMENT) {
0189:
0190: processFontElement(attrs);
0191:
0192: } else if (element == COLOR_ELEMENT) {
0193:
0194: processColorElement(attrs);
0195:
0196: } else if (element == G_UTILS_ELEMENT) {
0197:
0198: processGraphicsUtilsElement(attrs);
0199:
0200: } else if (element == DEFAULTS_ELEMENT) {
0201:
0202: processDefaultsProperyElement(attrs);
0203:
0204: } else if (element == INSETS_ELEMENT) {
0205:
0206: processInsetsElement(attrs);
0207:
0208: } else if (element == OPAQUE_ELEMENT) {
0209:
0210: processOpaqueElement(attrs);
0211:
0212: } else if (element == PROPERTY_ELEMENT) {
0213:
0214: processProperyElement(attrs);
0215:
0216: } else if (element == BIND_ELEMENT) {
0217:
0218: processBindElement(attrs);
0219:
0220: } else if (element == IM_PAINTER_ELEMENT) {
0221:
0222: processImagePainterElement(attrs);
0223:
0224: } else if (element == PAINTER_ELEMENT) {
0225:
0226: processPainterElement(attrs);
0227:
0228: } else if (element == IMAGE_ICON_ELEMENT) {
0229:
0230: processIconElement(attrs);
0231:
0232: } else if (element == SYNTH_ELEMENT) {
0233:
0234: // Do nothing
0235:
0236: } else {
0237: adapter.pushStartTag(element, attrs);
0238: }
0239: }
0240:
0241: /**
0242: * Characters need to beansPersistance entities only
0243: */
0244: @Override
0245: public void characters(char[] ch, int start, int size)
0246: throws SAXException {
0247: adapter.pushCharacters(ch, start, size);
0248: }
0249:
0250: @Override
0251: @SuppressWarnings("unused")
0252: public void endElement(String namespaceURI, String sName,
0253: String qName) {
0254:
0255: String element = ("".equals(sName)) ? qName.intern() : sName //$NON-NLS-1$
0256: .intern();
0257:
0258: if ((STYLE_ELEMENT == element)) {
0259: currentStyle = null;
0260: } else if (STATE_ELEMENT == element) {
0261: currentState = DEFAULT_STATE;
0262: } else if ((!(BIND_ELEMENT == element))
0263: && (!(COLOR_ELEMENT == element))
0264: && (!(G_UTILS_ELEMENT == element))
0265: && (!(DEFAULTS_ELEMENT == element))
0266: && (!(INSETS_ELEMENT == element))
0267: && (!(OPAQUE_ELEMENT == element))
0268: && (!(PROPERTY_ELEMENT == element))
0269: && (!(IM_PAINTER_ELEMENT == element))
0270: && (!(PAINTER_ELEMENT == element))
0271: && (!(IMAGE_ICON_ELEMENT == element))
0272: && (!(SYNTH_ELEMENT == element))
0273: && (!(FONT_ELEMENT == element))) {
0274: adapter.pushEndTag(element);
0275: }
0276:
0277: }
0278:
0279: /**
0280: * After the xml document parsing process all the references in
0281: * nameReferences map
0282: *
0283: * All the RuntimeExceptions are internal synth exceptions
0284: */
0285: @Override
0286: public void endDocument() throws SAXException {
0287:
0288: adapter.putAdaptedBeansToMap(namedElements);
0289:
0290: fillReferences();
0291:
0292: SynthLookAndFeel.setStyleFactory(styleFactory);
0293: }
0294:
0295: /**
0296: * Called in endDocument
0297: *
0298: * Process all the found references (idref in xml document and
0299: * namedReferences Map in this class) and binds it with exiting objects (id
0300: * in xml document and namedElements Map in this class)
0301: */
0302: private void fillReferences() {
0303:
0304: for (Map.Entry<XMLSynthKey, XMLSynthStyle> entry : namedReferences
0305: .entrySet()) {
0306:
0307: XMLSynthKey key = entry.getKey();
0308: String element = key.getElementName().intern();
0309:
0310: if (element == INSETS_ELEMENT) {
0311: // Just put the insets with given idref to style it (idref)
0312: // contains
0313: entry.getValue().setInsets(
0314: (Insets) namedElements.get(key.getReference()));
0315:
0316: } else if (element == FONT_ELEMENT) {
0317: // put the font with given idref to style it (idref)
0318: // contains, according to staieId obtained from key (key
0319: // filling can be found in )
0320: entry.getValue().addFont(
0321: (Font) namedElements.get(key.getReference()),
0322: key.getState());
0323:
0324: } else if (element == G_UTILS_ELEMENT) {
0325:
0326: entry.getValue().setGraphicsUtils(
0327: (SynthGraphicsUtils) namedElements.get(key
0328: .getReference()));
0329:
0330: } else if (element == COLOR_ELEMENT) {
0331:
0332: entry.getValue()
0333: .addColor(
0334: (Color) namedElements.get(key
0335: .getReference()),
0336: key.getState(),
0337: ColorType.calculateColorType(key
0338: .getFirstInfo()));
0339:
0340: } else if (element == PROPERTY_ELEMENT) {
0341: if (key.getAllInfo().length == 2) {
0342: entry.getValue().addIcon(
0343: (Icon) namedElements
0344: .get(key.getReference()),
0345: key.getState(), key.getFirstInfo());
0346: } else {
0347: entry.getValue().setProperty(key.getFirstInfo(),
0348: namedElements.get(key.getReference()));
0349: }
0350:
0351: } else if (element == DEFAULTS_ELEMENT) {
0352:
0353: UIManager.put(key.getFirstInfo(), namedElements.get(key
0354: .getReference()));
0355:
0356: } else if (element == PAINTER_ELEMENT) {
0357:
0358: String directionAttr = key.getAllInfo()[1];
0359: int direction = (directionAttr != null) ? Integer
0360: .parseInt(directionAttr)
0361: : PaintersManager.NO_DIRECTION;
0362:
0363: entry.getValue().addPainter(
0364: (SynthPainter) namedElements.get(key
0365: .getReference()), key.getState(),
0366: key.getAllInfo()[0], direction);
0367:
0368: } else {
0369: // impossible case because namedReferences filled by known
0370: // Elements only
0371: assert false : "Error in parser code"; //$NON-NLS-1$
0372: }
0373: }
0374: }
0375:
0376: private void processStyleElement(Attributes attrs)
0377: throws SAXException {
0378:
0379: String cloneAttr = attrs.getValue("clone"); //$NON-NLS-1$
0380: String styleName = attrs.getValue("id"); //$NON-NLS-1$
0381:
0382: if (cloneAttr == null) {
0383:
0384: currentStyle = new XMLSynthStyle();
0385: namedElements.put(styleName, currentStyle);
0386:
0387: } else {
0388: try {
0389: currentStyle = (XMLSynthStyle) ((XMLSynthStyle) namedElements
0390: .get(cloneAttr)).clone();
0391:
0392: } catch (CloneNotSupportedException e) {
0393: throw new SAXException(e);
0394: }
0395:
0396: namedElements.put(styleName, currentStyle);
0397: }
0398:
0399: currentState = DEFAULT_STATE;
0400: }
0401:
0402: @SuppressWarnings("nls")
0403: private void processFontElement(Attributes attrs)
0404: throws SAXException {
0405:
0406: String idref = attrs.getValue("idref");
0407: String id = attrs.getValue("id");
0408: String name = attrs.getValue("name");
0409: String styleAttr = attrs.getValue("style");
0410:
0411: int size = 0;
0412: int style = Font.PLAIN;
0413:
0414: if (idref != null) {
0415: namedReferences.put(new XMLSynthKey(FONT_ELEMENT,
0416: currentState, idref, new String[0]), currentStyle);
0417: return;
0418: }
0419:
0420: try {
0421: size = Integer.parseInt(attrs.getValue("size"));
0422: } finally {
0423: if (size == 0) {
0424: throw new SAXException("Invalid font size:"
0425: + attrs.getValue("size"));
0426: }
0427: }
0428:
0429: if (styleAttr != null) {
0430: StringTokenizer tk = new StringTokenizer(styleAttr);
0431: while (tk.hasMoreTokens()) {
0432: String st = tk.nextToken();
0433: if (st.equals("BOLD")) {
0434: style |= Font.BOLD;
0435: } else if (st.equals("ITALIC")) {
0436: style |= Font.ITALIC;
0437: }
0438: }
0439: }
0440:
0441: if (name == null) {
0442: throw new SAXException(Messages.getString("swing.err.1E"));
0443: }
0444:
0445: Font currentFont = new Font(name, style, size);
0446:
0447: if (currentStyle != null) {
0448: currentStyle.addFont(currentFont, currentState);
0449: }
0450:
0451: if (id != null) {
0452: namedElements.put(id, currentFont);
0453: }
0454: }
0455:
0456: private void processColorElement(Attributes attrs)
0457: throws SAXException {
0458:
0459: String colorTypeAttr = attrs.getValue("type"); //$NON-NLS-1$
0460: String idRefAttr = attrs.getValue("idref"); //$NON-NLS-1$
0461: String colorValueAttr = attrs.getValue("value"); //$NON-NLS-1$
0462: String idAttr = attrs.getValue("id"); //$NON-NLS-1$
0463:
0464: if ((idRefAttr != null) && (colorTypeAttr != null)) {
0465: namedReferences.put(new XMLSynthKey(COLOR_ELEMENT,
0466: currentState, idRefAttr, colorTypeAttr),
0467: currentStyle);
0468: return;
0469: }
0470:
0471: Color currentColor;
0472:
0473: try {
0474: if (colorValueAttr.length() == 7) {
0475:
0476: currentColor = Color.decode(colorValueAttr);
0477:
0478: } else if (colorValueAttr.length() == 9) {
0479:
0480: currentColor = new Color(Integer.parseInt(
0481: colorValueAttr, 16), true);
0482:
0483: } else {
0484:
0485: currentColor = Colors.valueOf(colorValueAttr
0486: .toUpperCase()).color;
0487:
0488: }
0489: } catch (Exception e) {
0490: throw new SAXException("Color value is incorrect", e); //$NON-NLS-1$
0491: }
0492:
0493: if (idAttr != null) {
0494:
0495: namedElements.put(idAttr, currentColor);
0496:
0497: } else {
0498:
0499: ColorType currentColorType = ColorType
0500: .calculateColorType(colorTypeAttr);
0501:
0502: if (currentColorType == null) {
0503: try {
0504: Class.forName(colorTypeAttr).newInstance();
0505: } catch (InstantiationException e) {
0506: throw new SAXException(Messages
0507: .getString("swing.err.1C") //$NON-NLS-1$
0508: + colorTypeAttr);
0509: } catch (IllegalAccessException e) {
0510: throw new SAXException(Messages
0511: .getString("swing.err.1C") //$NON-NLS-1$
0512: + colorTypeAttr);
0513: } catch (ClassNotFoundException e) {
0514: throw new SAXException(Messages
0515: .getString("swing.err.1C") //$NON-NLS-1$
0516: + colorTypeAttr);
0517: }
0518: }
0519:
0520: currentStyle.addColor(currentColor, currentState,
0521: currentColorType);
0522: }
0523: }
0524:
0525: @SuppressWarnings({"nls","boxing"})
0526: private void processProperyElement(Attributes attrs)
0527: throws SAXException {
0528:
0529: String propertyType = attrs.getValue("type");
0530: String keyAttr = attrs.getValue("key");
0531:
0532: if ("idref".equals(propertyType) || propertyType == null) {
0533:
0534: if ((keyAttr.endsWith("icon"))
0535: || (keyAttr.endsWith("Icon"))) {
0536: // Markup that it is icon property is XMLSynthKey.info array
0537: // length
0538: namedReferences.put(new XMLSynthKey(PROPERTY_ELEMENT,
0539: currentState, attrs.getValue("value"),
0540: new String[] { keyAttr, "" }), currentStyle);
0541: } else {
0542: namedReferences.put(
0543: new XMLSynthKey(PROPERTY_ELEMENT, currentState,
0544: attrs.getValue("value"), keyAttr),
0545: currentStyle);
0546: }
0547:
0548: } else if ("boolean".equalsIgnoreCase(propertyType)) {
0549:
0550: currentStyle.setProperty(keyAttr, new Boolean(attrs
0551: .getValue("value")));
0552:
0553: } else if ("dimension".equalsIgnoreCase(propertyType)) {
0554:
0555: String size = attrs.getValue("value");
0556: int width = Integer.parseInt(size.substring(0, size
0557: .indexOf(" ")));
0558: int height = Integer.parseInt(size.substring(size
0559: .indexOf(" ") + 1));
0560:
0561: currentStyle.setProperty(keyAttr, new Dimension(width,
0562: height));
0563:
0564: } else if ("insets".equalsIgnoreCase(propertyType)) {
0565:
0566: currentStyle.setProperty(keyAttr, getInsetsFromString(attrs
0567: .getValue("value")));
0568:
0569: } else if ("integer".equalsIgnoreCase(propertyType)) {
0570:
0571: currentStyle.setProperty(keyAttr, Integer.parseInt(attrs
0572: .getValue("value")));
0573:
0574: } else {
0575: throw new SAXException(Messages.getString("swing.err.1F",
0576: propertyType));
0577: }
0578: }
0579:
0580: @SuppressWarnings({"nls","boxing"})
0581: private void processDefaultsProperyElement(Attributes attrs)
0582: throws SAXException {
0583:
0584: String propertyType = attrs.getValue("type");
0585:
0586: if ("idref".equals(propertyType) || propertyType == null) {
0587: namedReferences.put(new XMLSynthKey(DEFAULTS_ELEMENT,
0588: currentState, attrs.getValue("value"), attrs
0589: .getValue("key")), currentStyle);
0590:
0591: } else if ("boolean".equalsIgnoreCase(propertyType)) {
0592:
0593: UIManager.put(attrs.getValue("key"), new Boolean(attrs
0594: .getValue("value")));
0595:
0596: } else if ("dimension".equalsIgnoreCase(propertyType)) {
0597:
0598: String size = attrs.getValue("value");
0599: int width = Integer.parseInt(size.substring(0, size
0600: .indexOf(" ")));
0601: int height = Integer.parseInt(size.substring(size
0602: .indexOf(" ") + 1));
0603:
0604: UIManager.put(attrs.getValue("key"), new Dimension(width,
0605: height));
0606:
0607: } else if ("insets".equalsIgnoreCase(propertyType)) {
0608:
0609: UIManager.put(attrs.getValue("key"),
0610: getInsetsFromString(attrs.getValue("value")));
0611:
0612: } else if ("integer".equalsIgnoreCase(propertyType)) {
0613:
0614: UIManager.put(attrs.getValue("key"), Integer.parseInt(attrs
0615: .getValue("value")));
0616:
0617: } else {
0618: throw new SAXException(Messages.getString("swing.err.1F",
0619: propertyType));
0620: }
0621: }
0622:
0623: @SuppressWarnings("nls")
0624: private void processBindElement(Attributes attrs)
0625: throws SAXException {
0626: /*
0627: * This method works with previously defined in parsed xml SynthStyles.
0628: * It's compatible with RI.
0629: */
0630: String bindType = attrs.getValue("type");
0631:
0632: if ("region".equalsIgnoreCase(bindType)) {
0633: styleFactory.putStyle(bindType, attrs.getValue("key"),
0634: (XMLSynthStyle) namedElements.get(attrs
0635: .getValue("style")));
0636: } else if ("name".equalsIgnoreCase(bindType)) {
0637: styleFactory.putStyle(bindType, attrs.getValue("key"),
0638: (XMLSynthStyle) namedElements.get(attrs
0639: .getValue("style")));
0640: } else {
0641: throw new SAXException(Messages.getString("swing.err.22",
0642: bindType, attrs.getValue("style")));
0643: }
0644: }
0645:
0646: private void processImagePainterElement(Attributes attrs)
0647: throws SAXException {
0648:
0649: String sourceInsetsAttr = attrs.getValue("sourceInsets"); //$NON-NLS-1$
0650: String pathAttr = attrs.getValue("path"); //$NON-NLS-1$
0651: String destinationInsetsAttr = attrs
0652: .getValue("destinationInsets"); //$NON-NLS-1$
0653: String methodAttr = attrs.getValue("method").toLowerCase(); //$NON-NLS-1$
0654: String directionAttr = attrs.getValue("direction"); //$NON-NLS-1$
0655: String idAttr = attrs.getValue("id"); //$NON-NLS-1$
0656:
0657: boolean paintCenter = "false".equalsIgnoreCase(attrs //$NON-NLS-1$
0658: .getValue("paintCenter")) ? false : true; //$NON-NLS-1$
0659: boolean stretch = "false".equalsIgnoreCase(attrs.getValue("stretch")) ? false : true; //$NON-NLS-1$ //$NON-NLS-2$
0660:
0661: Insets sourseInsets;
0662:
0663: // Compute SourceInsets
0664: if (sourceInsetsAttr != null && pathAttr != null) {
0665: sourseInsets = getInsetsFromString(sourceInsetsAttr);
0666: } else {
0667: throw new SAXException(Messages.getString("swing.err.23")); //$NON-NLS-1$
0668: }
0669:
0670: // Compute Direction.
0671: int direction = PaintersManager.NO_DIRECTION;
0672: if (directionAttr != null) {
0673: try {
0674: direction = Directions.valueOf(directionAttr
0675: .toUpperCase()).direction;
0676: } catch (IllegalArgumentException e) {
0677: throw new SAXException(Messages
0678: .getString("swing.err.20") //$NON-NLS-1$
0679: + directionAttr, e);
0680: }
0681: }
0682:
0683: Insets destinationInsets = destinationInsetsAttr == null ? sourseInsets
0684: : getInsetsFromString(destinationInsetsAttr);
0685:
0686: ImagePainter currentPainer;
0687: try {
0688: currentPainer = new ImagePainter(pathAttr, sourseInsets,
0689: destinationInsets, paintCenter, stretch, base);
0690:
0691: if (idAttr != null) {
0692: namedElements.put(idAttr, currentPainer);
0693: }
0694: if (currentStyle != null) {
0695: if (methodAttr == null) {
0696: currentStyle.addPainter(currentPainer,
0697: currentState, "default", direction); //$NON-NLS-1$
0698: } else {
0699:
0700: if ((methodAttr.contains("border"))) { //$NON-NLS-1$
0701: currentStyle
0702: .setProperty(
0703: getBorgerPaintedPropertyKey(methodAttr),
0704: Boolean.TRUE);
0705: }
0706: currentStyle.addPainter(currentPainer,
0707: currentState, methodAttr, direction);
0708: }
0709: }
0710:
0711: } catch (IOException e) {
0712: // Exception trows in ImageIo.read method and all the comments are
0713: // in e stack
0714: throw new SAXException(e);
0715: }
0716: }
0717:
0718: @SuppressWarnings("nls")
0719: private void processPainterElement(Attributes attrs) {
0720: String method = attrs.getValue("method").toLowerCase();
0721:
0722: if ((method != null) && (method.contains("border"))) {
0723: currentStyle.setProperty(
0724: getBorgerPaintedPropertyKey(method), Boolean.TRUE);
0725:
0726: }
0727:
0728: namedReferences.put(new XMLSynthKey(PAINTER_ELEMENT,
0729: currentState, attrs.getValue("idref"), new String[] {
0730: method, attrs.getValue("direction") }),
0731: currentStyle);
0732: }
0733:
0734: /**
0735: * The name of the method used as a key to let an UI know is paint border or
0736: * not
0737: */
0738: static String getBorgerPaintedPropertyKey(String method) {
0739: return "Synth" + method; //$NON-NLS-1$
0740: }
0741:
0742: @SuppressWarnings("nls")
0743: private void processIconElement(Attributes attrs) {
0744: URL imageURL = base.getResource(attrs.getValue("path"));
0745: namedElements
0746: .put(attrs.getValue("id"), new ImageIcon(imageURL));
0747: }
0748:
0749: private void processOpaqueElement(Attributes attrs) {
0750: currentStyle.setOpaque(Boolean.parseBoolean(attrs
0751: .getValue("value"))); //$NON-NLS-1$
0752: }
0753:
0754: private void processInsetsElement(Attributes attrs)
0755: throws SAXException {
0756:
0757: String idref = attrs.getValue("idref"); //$NON-NLS-1$
0758: if (idref != null) {
0759: namedReferences.put(new XMLSynthKey(
0760: "insets", currentState, idref, new String[0]), //$NON-NLS-1$
0761: currentStyle);
0762: return;
0763: }
0764:
0765: try {
0766:
0767: Insets insets = new Insets(0, 0, 0, 0);
0768: String top = attrs.getValue("top"); //$NON-NLS-1$
0769: String bottom = attrs.getValue("bottom"); //$NON-NLS-1$
0770: String left = attrs.getValue("left"); //$NON-NLS-1$
0771: String right = attrs.getValue("right"); //$NON-NLS-1$
0772: if (top != null) {
0773: insets.top = Integer.parseInt(top);
0774: }
0775: if (bottom != null) {
0776:
0777: insets.bottom = Integer.parseInt(bottom);
0778: }
0779: if (left != null) {
0780:
0781: insets.left = Integer.parseInt(left);
0782: }
0783: if (right != null) {
0784:
0785: insets.right = Integer.parseInt(right);
0786: }
0787:
0788: currentStyle.setInsets(insets);
0789: String id = attrs.getValue("id"); //$NON-NLS-1$
0790:
0791: if (id != null) {
0792:
0793: namedElements.put(id, insets);
0794: }
0795:
0796: } catch (NumberFormatException e) {
0797:
0798: throw new SAXException(e);
0799: }
0800: }
0801:
0802: @SuppressWarnings("nls")
0803: private Insets getInsetsFromString(String source) {
0804:
0805: int top = Integer.parseInt(source.substring(0, source
0806: .indexOf(" ")));
0807: source = source.substring(source.indexOf(" ") + 1);
0808: int bottom = Integer.parseInt(source.substring(0, source
0809: .indexOf(" ")));
0810: source = source.substring(source.indexOf(" ") + 1);
0811: int left = Integer.parseInt(source.substring(0, source
0812: .indexOf(" ")));
0813: source = source.substring(source.indexOf(" ") + 1);
0814: int right = Integer.parseInt(source.substring(source
0815: .indexOf(" ") + 1));
0816:
0817: return new Insets(top, left, bottom, right);
0818: }
0819:
0820: /**
0821: * GraphicsUtils that can be obtained according to beansAdapter only.
0822: */
0823: private void processGraphicsUtilsElement(Attributes attrs) {
0824:
0825: namedReferences
0826: .put(
0827: new XMLSynthKey(G_UTILS_ELEMENT, currentState,
0828: attrs.getValue("idref"), new String[0]), currentStyle); //$NON-NLS-1$
0829: }
0830:
0831: private int computeStateValue(String stateName) throws SAXException {
0832:
0833: if (stateName == null) {
0834:
0835: return DEFAULT_STATE;
0836:
0837: } else if ("ENABLED".equals(stateName)) { //$NON-NLS-1$
0838:
0839: return SynthConstants.ENABLED;
0840:
0841: } else if ("DISABLED".equals(stateName)) { //$NON-NLS-1$
0842:
0843: return SynthConstants.DISABLED;
0844:
0845: } else if ("MOUSE_OVER".equals(stateName)) { //$NON-NLS-1$
0846:
0847: return SynthConstants.MOUSE_OVER;
0848:
0849: } else if ("PRESSED".equals(stateName)) { //$NON-NLS-1$
0850:
0851: return SynthConstants.PRESSED;
0852:
0853: } else if ("DEFAULT".equals(stateName)) { //$NON-NLS-1$
0854:
0855: return SynthConstants.DEFAULT;
0856:
0857: } else if ("FOCUSED".equals(stateName)) { //$NON-NLS-1$
0858:
0859: return SynthConstants.FOCUSED;
0860:
0861: } else if ("SELECTED".equals(stateName)) { //$NON-NLS-1$
0862:
0863: return SynthConstants.SELECTED;
0864: }
0865:
0866: int indexOfAND = stateName.indexOf(" AND "); //$NON-NLS-1$
0867:
0868: if (indexOfAND != -1) {
0869:
0870: return computeStateValue(stateName.substring(0, indexOfAND))
0871: + computeStateValue(stateName
0872: .substring(indexOfAND + 5));
0873:
0874: }
0875:
0876: throw new SAXException(Messages.getString(
0877: "swing.err.21", stateName)); //$NON-NLS-1$
0878: }
0879:
0880: /**
0881: * Beans adapter processing the unknown elements and obtains objects from
0882: * elements known to beansAdapter. All the obtained objects should be added
0883: * to namedElements map (parser do it in endDocument() method)
0884: */
0885: private static class BeansAdapter {
0886:
0887: private final String lsp = System.getProperty("line.separator"); //$NON-NLS-1$
0888:
0889: private final StringBuffer xmlLine = new StringBuffer();
0890:
0891: private final List<String> idList = new LinkedList<String>();
0892:
0893: /**
0894: * The nesting depth of xml tags
0895: */
0896: private int validatingCounter = 0;
0897:
0898: @SuppressWarnings("nls")
0899: public BeansAdapter() {
0900: xmlLine
0901: .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
0902: xmlLine.append(lsp);
0903: xmlLine.append("<java>");
0904: xmlLine.append(lsp);
0905: }
0906:
0907: @SuppressWarnings("nls")
0908: public void pushStartTag(String element, Attributes attrs) {
0909:
0910: String id = attrs.getValue("id");
0911:
0912: if (id != null && validatingCounter == 0) {
0913: idList.add(id);
0914: }
0915:
0916: xmlLine.append("<");
0917: xmlLine.append(element);
0918:
0919: for (int i = 0; i < attrs.getLength(); i++) {
0920: String localName = attrs.getLocalName(i);
0921: xmlLine.append(" ");
0922: xmlLine.append(("".equals(localName)) ? attrs
0923: .getQName(i) : localName);
0924: xmlLine.append("=\"");
0925: xmlLine.append(attrs.getValue(i));
0926: xmlLine.append("\" ");
0927: }
0928:
0929: xmlLine.append(">");
0930: xmlLine.append(lsp);
0931:
0932: validatingCounter++;
0933:
0934: }
0935:
0936: public void pushCharacters(char[] ch, int start, int end) {
0937:
0938: if (validatingCounter > 0) {
0939: xmlLine.append(ch, start, end);
0940: }
0941:
0942: }
0943:
0944: @SuppressWarnings("nls")
0945: public void pushEndTag(String element) {
0946:
0947: xmlLine.append("</");
0948: xmlLine.append(element);
0949: xmlLine.append(">");
0950: xmlLine.append(lsp);
0951:
0952: validatingCounter--;
0953: }
0954:
0955: private XMLDecoder createDecoder() {
0956: xmlLine.append("</java>"); //$NON-NLS-1$
0957: return new XMLDecoder(new ByteArrayInputStream(xmlLine
0958: .toString().getBytes()));
0959: }
0960:
0961: public void putAdaptedBeansToMap(Map<String, Object> elementsMap) {
0962: XMLDecoder d = createDecoder();
0963: for (String id : idList) {
0964: elementsMap.put(id, d.readObject());
0965: }
0966: d.close();
0967:
0968: }
0969: }
0970:
0971: /**
0972: * This class is used to represent correct keys in namedReferences table
0973: * which helps to unambiguously insert named element instead of reference in
0974: * the concluding stage of parsing
0975: */
0976: private static class XMLSynthKey {
0977:
0978: /**
0979: * This field represents the name of element to refer. By convention (in
0980: * this class) the type defines the additional info needed (i.e. the
0981: * Color element needed in colorType info and stateID, Insets element
0982: * not needed in info at all, etc)
0983: */
0984: private final String elementName;
0985:
0986: /**
0987: * This field represents the key to find in the namedElements table
0988: * (idref in xml file)
0989: */
0990: private final String reference;
0991:
0992: /**
0993: * This field provides information about concerned Objects necessary to
0994: * correct insertion to style (such as ColorType, method attribute for
0995: * painters etc)
0996: */
0997: private final String[] info;
0998:
0999: /**
1000: * StateID is also additional info, but because it is integer it taken
1001: * out from info array for performance reasons
1002: */
1003: private final int stateID;
1004:
1005: XMLSynthKey(String elementName, int stateID, String reference,
1006: String[] info) {
1007: this .elementName = elementName;
1008: this .reference = reference;
1009: this .info = info;
1010: this .stateID = stateID;
1011: }
1012:
1013: XMLSynthKey(String type, int stateID, String reference,
1014: String info) {
1015: this .elementName = type;
1016: this .reference = reference;
1017: this .info = new String[] { info };
1018: this .stateID = stateID;
1019: }
1020:
1021: String getElementName() {
1022: return elementName;
1023: }
1024:
1025: String getReference() {
1026: return reference;
1027: }
1028:
1029: String[] getAllInfo() {
1030: return info;
1031: }
1032:
1033: int getState() {
1034: return stateID;
1035: }
1036:
1037: /**
1038: * This method used if info array contains one element
1039: *
1040: * @return the first element in the info array
1041: */
1042: String getFirstInfo() {
1043: return info != null ? info[0] : null;
1044: }
1045:
1046: @Override
1047: public boolean equals(Object key) {
1048:
1049: XMLSynthKey _key = (XMLSynthKey) key;
1050: boolean result;
1051: result = (_key.elementName == null) ? (this .elementName == null)
1052: : _key.elementName.equals(this .elementName);
1053: result &= (this .stateID == _key.stateID);
1054: result &= (_key.reference == null) ? this .reference == null
1055: : _key.reference.equals(this .reference);
1056: result &= Arrays.equals(_key.info, this .info);
1057:
1058: return result;
1059: }
1060:
1061: @Override
1062: public int hashCode() {
1063: return elementName.hashCode() + reference.hashCode()
1064: + info.hashCode();
1065: }
1066: }
1067:
1068: }
|