// // $Id$ // From Philippe Le Hegaret (Philippe.Le_Hegaret@sophia.inria.fr) // // (c) COPYRIGHT MIT and INRIA, 1997. // Please first read the full copyright statement in file COPYRIGHT.html package org.w3c.css.css; import org.w3c.css.parser.AtRule; import org.w3c.css.parser.CssSelectors; import org.w3c.css.parser.CssStyle; import org.w3c.css.parser.Errors; import org.w3c.css.properties.css.CssCustomProperty; import org.w3c.css.properties.css.CssProperty; import org.w3c.css.util.ApplContext; import org.w3c.css.util.Util; import org.w3c.css.util.Warnings; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; /** * This class contains a style sheet with all rules, errors and warnings. * * @version $Revision$ */ public class StyleSheet { private CssCascadingOrder cascading; private HashMap rules; private Errors errors; private Warnings warnings; private String type; private ArrayList atRuleList; private boolean doNotAddRule; private boolean doNotAddAtRule; private static final boolean debug = false; private HashMap customProperties; /** * Create a new StyleSheet. */ public StyleSheet() { rules = new HashMap<>(); errors = new Errors(); warnings = new Warnings(); cascading = new CssCascadingOrder(); atRuleList = new ArrayList<>(); customProperties = new HashMap<>(); } public void setWarningLevel(int warningLevel) { warnings.setWarningLevel(warningLevel); } /** * Get a style in a specific context. * No resolution are perfomed when this function is called * * @param context The context for the style * @return The style for the specific context. */ public CssStyle getStyle(CssSelectors context) { if (debug) { Util.verbose("StyleSheet.getStyle(" + context + ')'); } if (getContext(context) != null) { CssSelectors realContext = (CssSelectors) getContext(context); CssStyle style = realContext.getStyle(); style.setStyleSheet(this); style.setSelector(realContext); return style; } else { rules.put(context.toString(), context); context.getStyle().setStyleSheet(this); context.getStyle().setSelector(context); return context.getStyle(); } } /** * Add a property to this style sheet. * * @param selector The context where the property is defined * @param property The property to add */ public void addProperty(CssSelectors selector, CssProperty property) { if (debug) { Util.verbose("add property " + getContext(selector) + " " + property); } getContext(selector).addProperty(property, warnings); } /** * lookup a custom property * @param s, the name of the property * @return a CssCustomProperty or null if not found */ public CssCustomProperty getCustomProperty(String s) { return customProperties.get(s); } // we are not adding custom property in addProperty, as we want to be public CssCustomProperty addCustomProperty(String s, CssCustomProperty p, boolean force) { if (force) { return customProperties.put(s, p); } return customProperties.putIfAbsent(s, p); } public void remove(CssSelectors selector) { rules.remove(selector); } public void setType(String type) { this.type = type; } public String getType() { if (type == null) { return "text/css"; } else { return type; } } /** * Add some errors to this style. * * @param errors Some errors. */ public void addErrors(Errors errors) { if (errors.getErrorCount() != 0) { getErrors().addErrors(errors); } } /** * Add some warnings to this style. * * @param warnings Some warnings. */ public void addWarnings(Warnings warnings) { if (warnings.getWarningCount() != 0) getWarnings().addWarnings(warnings); } /** * Returns all errors. */ public final Errors getErrors() { return errors; } /** * Returns all warnings. */ public final Warnings getWarnings() { return warnings; } /** * Returns all rules */ public final HashMap getRules() { return rules; } /** * Returns the property for a context. * * @param property The default value returned if there is no property. * @param style The current style sheet where we can find all properties * @param selector The current context * @return the property with the right value */ public final CssProperty CascadingOrder(CssProperty property, StyleSheet style, CssSelectors selector) { return cascading.order(property, style, selector); } /** * Find all conflicts for this style sheet. */ public void findConflicts(ApplContext ac) { HashMap rules = getRules(); CssSelectors[] all = new CssSelectors[rules.size()]; all = rules.values().toArray(all); Arrays.sort(all); for (CssSelectors selector : all) { selector.markAsFinal(); } for (CssSelectors selector : all) { selector.findConflicts(ac, warnings, all); } } /** * Returns the unique context for a context * * @param selector the context to find. */ protected CssSelectors getContext(CssSelectors selector) { if (rules.containsKey(selector.toString())) { return rules.get(selector.toString()); } else { if (selector.getNext() != null) { CssSelectors next = getContext(selector.getNext()); selector.setNext(next); } rules.put(selector.toString(), selector); return selector; } } /** * dump this style sheet. */ public void dump() { StyleSheetGenerator style = new StyleSheetGenerator("", this, "text", -1); style.print(new PrintWriter(System.out)); } //part added by Sijtsche de Jong public void addCharSet(String charset) { this.charset = charset; } public void newAtRule(AtRule atRule) { CssRuleList rulelist = new CssRuleList(); rulelist.addAtRule(atRule); atRuleList.add(rulelist); indent += " "; } public void endOfAtRule() { if (!doNotAddAtRule) { CssRuleList rulelist = new CssRuleList(); atRuleList.add(rulelist); //for the new set of rules } important = false; selectortext = ""; if (indent.length() >= 3) { indent = indent.substring(3); } else { // raise a warning? This should never happen. } doNotAddAtRule = false; } public void setImportant(boolean important) { this.important = important; } public void setSelectorList(ArrayList selectors) { StringBuilder sb = new StringBuilder(); for (CssSelectors s : selectors) { if (sb.length() > 0) { sb.append(", "); } sb.append(s.toString()); } selectortext = sb.toString(); } public void setProperty(ArrayList properties) { this.properties = properties; } public void endOfRule() { CssRuleList rulelist; if (!doNotAddRule) { CssStyleRule stylerule = new CssStyleRule(indent, selectortext, properties, important); if (!atRuleList.isEmpty()) { rulelist = atRuleList.remove(atRuleList.size() - 1); } else { rulelist = new CssRuleList(); } rulelist.addStyleRule(stylerule); atRuleList.add(rulelist); } selectortext = ""; doNotAddRule = false; } public void removeThisRule() { doNotAddRule = true; } public void removeThisAtRule() { doNotAddAtRule = true; } public ArrayList newGetRules() { return atRuleList; } String selectortext; boolean important; ArrayList properties; String indent = new String(); public String charset; }