blob: 82a6b33948e438d534f5a8972a17296e4ea7c48b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.css.core.internal.metamodelimpl;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Stack;
import org.eclipse.wst.css.core.internal.Logger;
import org.eclipse.wst.css.core.internal.metamodel.CSSMMNode;
import org.eclipse.wst.css.core.internal.metamodel.CSSMMSelector;
import org.eclipse.wst.css.core.internal.metamodel.CSSProfile;
import org.eclipse.wst.css.core.internal.metamodel.CSSProfileRegistry;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
class ProfileHandler extends DefaultHandler {
public ProfileHandler(CSSMetaModelImpl metamodel, ResourceBundle resourceBundle, boolean logging) {
super();
fMetaModel = metamodel;
fNodePool = metamodel.getNodePool();
fResourceBundle = resourceBundle;
fLogging = logging;
}
public ProfileHandler(CSSMetaModelImpl metamodel, ResourceBundle resourceBundle) {
super();
fMetaModel = metamodel;
fNodePool = metamodel.getNodePool();
fResourceBundle = resourceBundle;
fLogging = false;
}
private String getResourceString(String key) {
if (key.equals("%")) { //$NON-NLS-1$
return key;
}
if (!key.startsWith("%")) { //$NON-NLS-1$
return key;
}
if (key.startsWith("%%")) { //$NON-NLS-1$
return key.substring(1);
}
if (fResourceBundle != null) {
return fResourceBundle.getString(key.substring(1));
}
else {
return key;
}
}
public void startDocument() throws SAXException {
// System.out.println("startDocument");
// fNodeStack.push(metamodel);
// fCurrentNode = null;
}
public void endDocument() throws SAXException {
new ErrorCorrector().doCorrect(fMetaModel);
if (fLogging) {
Iterator i = fNodePool.getStrayNodes();
while (i.hasNext()) {
CSSMMNode node = (CSSMMNode) i.next();
String str = "[CSSProfile Warning] " + node.getName(); //$NON-NLS-1$
str += "(" + node.getType() + ") is not referred by any node."; //$NON-NLS-1$ //$NON-NLS-2$
Logger.log(Logger.WARNING, str);
// System.out.println(str);
}
}
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
TagNode tagNode = null;
CSSMMNodeImpl parentNode = null;
if (0 < fNodeStack.size()) {
tagNode = (TagNode) fNodeStack.peek();
parentNode = tagNode.node;
}
CSSMMNodeImpl node = null;
if (qName.equals(ProfileKeywords.PROFILE_IMPORT)) { // import
String profileName = attributes.getValue(ATTR_NAME_REFERENCE);
importProfile(profileName);
}
else if (isDefinition(qName)) { // node creation
String nodeName = attributes.getValue(ATTR_NAME_DEFINITION);
node = fNodePool.getNode(qName, nodeName);
if (node != null) {
String overwrite = attributes.getValue(ATTR_OVERWRITE);
if (overwrite == null || overwrite.equals(ATTR_VALUE_OVERWRITE_FALSE)) {
node.removeAllChildNodes();
}
Map attrMap = new HashMap();
for (int i = 0; i < attributes.getLength(); i++) {
attrMap.put(attributes.getQName(i), attributes.getValue(i));
}
try {
node.initializeAttribute(attrMap);
}
catch (IllegalArgumentException e) {
Logger.logException(e);
}
}
}
else if (node == null) { // node reference
String nodeName = attributes.getValue(ATTR_NAME_REFERENCE);
node = fNodePool.getNode(qName, nodeName);
}
if (node != null) {
if (parentNode != null && parentNode.canContain(node)) {
String enabled = attributes.getValue(ATTR_ENABLED);
if (enabled != null && enabled.equals(ATTR_VALUE_ENABLED_FALSE)) {
parentNode.removeChild(node);
}
else {
parentNode.appendChild(node);
}
}
else if (node.getType() == CSSMMNode.TYPE_STYLE_SHEET || node.getType() == CSSMMNode.TYPE_CATEGORY) {
fMetaModel.appendChild(node);
}
else {
if (fLogging && parentNode != null) {
Logger.log(Logger.ERROR, parentNode.getType() + " cannot contain " + //$NON-NLS-1$
node.getType() + " (" + qName + ")"); //$NON-NLS-2$//$NON-NLS-1$
}
}
}
fNodeStack.push(new TagNode(qName, (node != null) ? node : parentNode));
}
public void endElement(String uri, String localName, String qName) throws SAXException {
fNodeStack.pop();
}
public void characters(char[] ch, int start, int length) throws SAXException {
TagNode tagNode = (TagNode) fNodeStack.peek();
String tagName = tagNode.tag;
if (tagName.equals(ProfileKeywords.KEYWORD_VALUE) || tagName.equals(ProfileKeywords.UNIT_VALUE) || tagName.equals(ProfileKeywords.FUNCTION_VALUE) || tagName.equals(ProfileKeywords.SELECTOR_VALUE) || tagName.equals(ProfileKeywords.DESCRIPTION) || tagName.equals(ProfileKeywords.CAPTION)) {
StringBuffer buf = new StringBuffer(length);
for (int i = 0; i < length; i++) {
buf.append(ch[start + i]);
}
String value = getResourceString(buf.toString().trim());
CSSMMNodeImpl node = tagNode.node;
if (node != null) {
if (node.getType() == CSSMMNode.TYPE_KEYWORD && tagName.equals(ProfileKeywords.KEYWORD_VALUE)) {
((CSSMMKeywordImpl) node).setKeywordString(value);
}
else if (node.getType() == CSSMMNode.TYPE_UNIT && tagName.equals(ProfileKeywords.UNIT_VALUE)) {
((CSSMMUnitImpl) node).setUnitString(value);
}
else if (node.getType() == CSSMMNode.TYPE_FUNCTION && tagName.equals(ProfileKeywords.FUNCTION_VALUE)) {
((CSSMMFunctionImpl) node).setFunctionString(value);
}
else if (node.getType() == CSSMMNode.TYPE_SELECTOR && ((CSSMMSelector) node).getSelectorType() == CSSMMSelector.TYPE_PSEUDO_ELEMENT) {
((CSSMMPseudoElementImpl) node).setSelectorString(value);
}
else if (node.getType() == CSSMMNode.TYPE_SELECTOR && ((CSSMMSelector) node).getSelectorType() == CSSMMSelector.TYPE_PSEUDO_CLASS) {
((CSSMMPseudoClassImpl) node).setSelectorString(value);
}
else if (node.getType() == CSSMMNode.TYPE_CATEGORY && tagName.equals(ProfileKeywords.CAPTION)) {
((CSSMMCategoryImpl) node).setCaption(value);
}
else if (tagName.equals(ProfileKeywords.DESCRIPTION)) {
node.setDescription(value);
}
}
}
}
private boolean isDefinition(String tagName) {
return (tagName.equals(ProfileKeywords.STYLESHEET_DEF) || tagName.equals(ProfileKeywords.CHARSET_RULE_DEF) || tagName.equals(ProfileKeywords.IMPORT_RULE_DEF) || tagName.equals(ProfileKeywords.PAGE_RULE_DEF) || tagName.equals(ProfileKeywords.MEDIA_RULE_DEF) || tagName.equals(ProfileKeywords.FONTFACE_RULE_DEF) || tagName.equals(ProfileKeywords.STYLE_RULE_DEF) || tagName.equals(ProfileKeywords.KEYWORD_DEF) || tagName.equals(ProfileKeywords.NUMBER_DEF) || tagName.equals(ProfileKeywords.PROPERTY_DEF) || tagName.equals(ProfileKeywords.DESCRIPTOR_DEF) || tagName.equals(ProfileKeywords.CONTAINER_DEF) || tagName.equals(ProfileKeywords.UNIT_DEF) || tagName.equals(ProfileKeywords.FUNCTION_DEF) || tagName.equals(ProfileKeywords.STRING) || tagName.equals(ProfileKeywords.CATEGORY_DEF) || tagName.equals(ProfileKeywords.PSEUDO_CLASS_DEF) || tagName.equals(ProfileKeywords.PSEUDO_ELEMENT_DEF) || tagName.equals(ProfileKeywords.SELECTOR_EXPRESSION) || tagName.equals(ProfileKeywords.SEPARATOR));
}
private void importProfile(String profileName) {
URL profileURL = null;
CSSProfileRegistry reg = CSSProfileRegistry.getInstance();
CSSProfile profile = reg.getProfile(profileName);
if (profile != null) {
// first: find URL by ID
profileURL = profile.getProfileURL();
}
else {
// second: find URL by filename of profile URL
Iterator i = reg.getProfiles();
while (i.hasNext()) {
profile = (CSSProfile) i.next();
URL url = profile.getProfileURL();
if (url.getFile().endsWith(profileName)) {
profileURL = url;
break;
}
}
}
if (profileURL == null) {
// final: it may be url itself
try {
profileURL = new URL(profileName);
}
catch (MalformedURLException e) {
Logger.logException(e);
}
}
if (profileURL != null) {
try {
ProfileLoader.loadProfile(fMetaModel, profileURL.openStream(), fResourceBundle, fLogging);
}
catch (IOException e) {
Logger.logException("Cannot open stream for profile", //$NON-NLS-1$
e);
}
}
}
class TagNode {
String tag = null;
CSSMMNodeImpl node = null;
TagNode(String tag, CSSMMNodeImpl node) {
this.tag = tag;
this.node = node;
}
}
class ErrorCorrector {
void doCorrect(CSSMMNodeImpl node) {
Iterator i = node.getChildNodes();
ArrayList errorNodes = new ArrayList();
while (i.hasNext()) {
CSSMMNodeImpl child = (CSSMMNodeImpl) i.next();
doCorrect(child);
short error = child.getError();
if (error != MetaModelErrors.NO_ERROR) {
// node.removeChild(child);
errorNodes.add(child);
String str = "[CSSProfile Error] " + node.getName(); //$NON-NLS-1$
str += "(" + node.getType() + ") contains error node: "; //$NON-NLS-1$ //$NON-NLS-2$
str += child.getName() + "(" + child.getType() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
str += " - error code = " + error; //$NON-NLS-1$
if (fLogging) {
Logger.log(Logger.ERROR, str);
// System.out.println(str);
}
}
}
int errorSize = errorNodes.size();
if (errorSize > 0) {
for (int j = 0; j < errorSize; j++) {
CSSMMNodeImpl errorNode = (CSSMMNodeImpl) errorNodes.get(j);
node.removeChild(errorNode);
}
}
}
}
private CSSMetaModelImpl fMetaModel = null;
private NodePool fNodePool = null;
private Stack fNodeStack = new Stack();
boolean fLogging = false;
private ResourceBundle fResourceBundle = null;
private final static String ATTR_NAME_DEFINITION = "name"; //$NON-NLS-1$
private final static String ATTR_NAME_REFERENCE = "name"; //$NON-NLS-1$
private final static String ATTR_OVERWRITE = "overwrite"; //$NON-NLS-1$
private final static String ATTR_ENABLED = "enabled"; //$NON-NLS-1$
private final static String ATTR_VALUE_OVERWRITE_FALSE = "false"; //$NON-NLS-1$
private final static String ATTR_VALUE_ENABLED_FALSE = "false"; //$NON-NLS-1$
}