📄 stylesheet.java
字号:
/* * @(#)StyleSheet.java 1.91 05/11/30 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package javax.swing.text.html;import sun.swing.SwingUtilities2;import java.util.*;import java.awt.*;import java.io.*;import java.net.*;import javax.swing.Icon;import javax.swing.ImageIcon;import javax.swing.border.*;import javax.swing.event.ChangeListener;import javax.swing.text.*;/** * Support for defining the visual characteristics of * HTML views being rendered. The StyleSheet is used to * translate the HTML model into visual characteristics. * This enables views to be customized by a look-and-feel, * multiple views over the same model can be rendered * differently, etc. This can be thought of as a CSS * rule repository. The key for CSS attributes is an * object of type CSS.Attribute. The type of the value * is up to the StyleSheet implementation, but the * <code>toString</code> method is required * to return a string representation of CSS value. * <p> * The primary entry point for HTML View implementations * to get their attributes is the * <a href="#getViewAttributes">getViewAttributes</a> * method. This should be implemented to establish the * desired policy used to associate attributes with the view. * Each HTMLEditorKit (i.e. and therefore each associated * JEditorPane) can have its own StyleSheet, but by default one * sheet will be shared by all of the HTMLEditorKit instances. * HTMLDocument instance can also have a StyleSheet, which * holds the document-specific CSS specifications. * <p> * In order for Views to store less state and therefore be * more lightweight, the StyleSheet can act as a factory for * painters that handle some of the rendering tasks. This allows * implementations to determine what they want to cache * and have the sharing potentially at the level that a * selector is common to multiple views. Since the StyleSheet * may be used by views over multiple documents and typically * the HTML attributes don't effect the selector being used, * the potential for sharing is significant. * <p> * The rules are stored as named styles, and other information * is stored to translate the context of an element to a * rule quickly. The following code fragment will display * the named styles, and therefore the CSS rules contained. * <code><pre> * * import java.util.*; * import javax.swing.text.*; * import javax.swing.text.html.*; * * public class ShowStyles { * * public static void main(String[] args) { * HTMLEditorKit kit = new HTMLEditorKit(); * HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument(); * StyleSheet styles = doc.getStyleSheet(); * * Enumeration rules = styles.getStyleNames(); * while (rules.hasMoreElements()) { * String name = (String) rules.nextElement(); * Style rule = styles.getStyle(name); * System.out.println(rule.toString()); * } * System.exit(0); * } * } * * </pre></code> * <p> * The semantics for when a CSS style should overide visual attributes * defined by an element are not well defined. For example, the html * <code><body bgcolor=red></code> makes the body have a red * background. But if the html file also contains the CSS rule * <code>body { background: blue }</code> it becomes less clear as to * what color the background of the body should be. The current * implemention gives visual attributes defined in the element the * highest precedence, that is they are always checked before any styles. * Therefore, in the previous example the background would have a * red color as the body element defines the background color to be red. * <p> * As already mentioned this supports CSS. We don't support the full CSS * spec. Refer to the javadoc of the CSS class to see what properties * we support. The two major CSS parsing related * concepts we do not currently * support are pseudo selectors, such as <code>A:link { color: red }</code>, * and the <code>important</code> modifier. * <p> * <font color="red">Note: This implementation is currently * incomplete. It can be replaced with alternative implementations * that are complete. Future versions of this class will provide * better CSS support.</font> * * @author Timothy Prinzing * @author Sunita Mani * @author Sara Swanson * @author Jill Nakata * @version 1.91 11/30/05 */public class StyleSheet extends StyleContext { // As the javadoc states, this class maintains a mapping between // a CSS selector (such as p.bar) and a Style. // This consists of a number of parts: // . Each selector is broken down into its constituent simple selectors, // and stored in an inverted graph, for example: // p { color: red } ol p { font-size: 10pt } ul p { font-size: 12pt } // results in the graph: // root // | // p // / \ // ol ul // each node (an instance of SelectorMapping) has an associated // specificity and potentially a Style. // . Every rule that is asked for (either by way of getRule(String) or // getRule(HTML.Tag, Element)) results in a unique instance of // ResolvedStyle. ResolvedStyles contain the AttributeSets from the // SelectorMapping. // . When a new rule is created it is inserted into the graph, and // the AttributeSets of each ResolvedStyles are updated appropriately. // . This class creates special AttributeSets, LargeConversionSet and // SmallConversionSet, that maintain a mapping between StyleConstants // and CSS so that developers that wish to use the StyleConstants // methods can do so. // . When one of the AttributeSets is mutated by way of a // StyleConstants key, all the associated CSS keys are removed. This is // done so that the two representations don't get out of sync. For // example, if the developer adds StyleConsants.BOLD, FALSE to an // AttributeSet that contains HTML.Tag.B, the HTML.Tag.B entry will // be removed. /** * Construct a StyleSheet */ public StyleSheet() { super(); selectorMapping = new SelectorMapping(0); resolvedStyles = new Hashtable(); if (css == null) { css = new CSS(); } } /** * Fetches the style to use to render the given type * of HTML tag. The element given is representing * the tag and can be used to determine the nesting * for situations where the attributes will differ * if nesting inside of elements. * * @param t the type to translate to visual attributes * @param e the element representing the tag; the element * can be used to determine the nesting for situations where * the attributes will differ if nested inside of other * elements * @return the set of CSS attributes to use to render * the tag */ public Style getRule(HTML.Tag t, Element e) { SearchBuffer sb = SearchBuffer.obtainSearchBuffer(); try { // Build an array of all the parent elements. Vector searchContext = sb.getVector(); for (Element p = e; p != null; p = p.getParentElement()) { searchContext.addElement(p); } // Build a fully qualified selector. int n = searchContext.size(); StringBuffer cacheLookup = sb.getStringBuffer(); AttributeSet attr; String eName; Object name; // >= 1 as the HTML.Tag for the 0th element is passed in. for (int counter = n - 1; counter >= 1; counter--) { e = (Element)searchContext.elementAt(counter); attr = e.getAttributes(); name = attr.getAttribute(StyleConstants.NameAttribute); eName = name.toString(); cacheLookup.append(eName); if (attr != null) { if (attr.isDefined(HTML.Attribute.ID)) { cacheLookup.append('#'); cacheLookup.append(attr.getAttribute (HTML.Attribute.ID)); } else if (attr.isDefined(HTML.Attribute.CLASS)) { cacheLookup.append('.'); cacheLookup.append(attr.getAttribute (HTML.Attribute.CLASS)); } } cacheLookup.append(' '); } cacheLookup.append(t.toString()); e = (Element)searchContext.elementAt(0); attr = e.getAttributes(); if (e.isLeaf()) { // For leafs, we use the second tier attributes. Object testAttr = attr.getAttribute(t); if (testAttr instanceof AttributeSet) { attr = (AttributeSet)testAttr; } else { attr = null; } } if (attr != null) { if (attr.isDefined(HTML.Attribute.ID)) { cacheLookup.append('#'); cacheLookup.append(attr.getAttribute(HTML.Attribute.ID)); } else if (attr.isDefined(HTML.Attribute.CLASS)) { cacheLookup.append('.'); cacheLookup.append(attr.getAttribute (HTML.Attribute.CLASS)); } } Style style = getResolvedStyle(cacheLookup.toString(), searchContext, t); return style; } finally { SearchBuffer.releaseSearchBuffer(sb); } } /** * Fetches the rule that best matches the selector given * in string form. Where <code>selector</code> is a space separated * String of the element names. For example, <code>selector</code> * might be 'html body tr td''<p> * The attributes of the returned Style will change * as rules are added and removed. That is if you to ask for a rule * with a selector "table p" and a new rule was added with a selector * of "p" the returned Style would include the new attributes from * the rule "p". */ public Style getRule(String selector) { selector = cleanSelectorString(selector); if (selector != null) { Style style = getResolvedStyle(selector); return style; } return null; } /** * Adds a set of rules to the sheet. The rules are expected to * be in valid CSS format. Typically this would be called as * a result of parsing a <style> tag. */ public void addRule(String rule) { if (rule != null) { //tweaks to control display properties //see BasicEditorPaneUI final String baseUnitsDisable = "BASE_SIZE_DISABLE"; final String baseUnits = "BASE_SIZE "; final String w3cLengthUnitsEnable = "W3C_LENGTH_UNITS_ENABLE"; final String w3cLengthUnitsDisable = "W3C_LENGTH_UNITS_DISABLE"; if (rule == baseUnitsDisable) { sizeMap = sizeMapDefault; } else if (rule.startsWith(baseUnits)) { rebaseSizeMap(Integer. parseInt(rule.substring(baseUnits.length()))); } else if (rule == w3cLengthUnitsEnable) { w3cLengthUnits = true; } else if (rule == w3cLengthUnitsDisable) { w3cLengthUnits = false; } else { CssParser parser = new CssParser(); try { parser.parse(getBase(), new StringReader(rule), false, false); } catch (IOException ioe) { } } } } /** * Translates a CSS declaration to an AttributeSet that represents * the CSS declaration. Typically this would be called as a * result of encountering an HTML style attribute. */ public AttributeSet getDeclaration(String decl) { if (decl == null) { return SimpleAttributeSet.EMPTY; } CssParser parser = new CssParser(); return parser.parseDeclaration(decl); } /** * Loads a set of rules that have been specified in terms of * CSS1 grammar. If there are collisions with existing rules, * the newly specified rule will win. * * @param in the stream to read the CSS grammar from * @param ref the reference URL. This value represents the * location of the stream and may be null. All relative * URLs specified in the stream will be based upon this * parameter. */ public void loadRules(Reader in, URL ref) throws IOException { CssParser parser = new CssParser(); parser.parse(ref, in, false, false); } /** * Fetches a set of attributes to use in the view for * displaying. This is basically a set of attributes that * can be used for View.getAttributes. */ public AttributeSet getViewAttributes(View v) { return new ViewAttributeSet(v); } /** * Removes a named style previously added to the document. * * @param nm the name of the style to remove */ public void removeStyle(String nm) { Style aStyle = getStyle(nm); if (aStyle != null) { String selector = cleanSelectorString(nm); String[] selectors = getSimpleSelectors(selector); synchronized(this) { SelectorMapping mapping = getRootSelectorMapping(); for (int i = selectors.length - 1; i >= 0; i--) { mapping = mapping.getChildSelectorMapping(selectors[i], true); } Style rule = mapping.getStyle(); if (rule != null) { mapping.setStyle(null); if (resolvedStyles.size() > 0) { Enumeration values = resolvedStyles.elements(); while (values.hasMoreElements()) { ResolvedStyle style = (ResolvedStyle)values. nextElement(); style.removeStyle(rule); } } } } } super.removeStyle(nm); } /** * Adds the rules from the StyleSheet <code>ss</code> to those of * the receiver. <code>ss's</code> rules will override the rules of * any previously added style sheets. An added StyleSheet will never * override the rules of the receiving style sheet. * * @since 1.3 */ public void addStyleSheet(StyleSheet ss) { synchronized(this) { if (linkedStyleSheets == null) { linkedStyleSheets = new Vector(); } if (!linkedStyleSheets.contains(ss)) { int index = 0; if (ss instanceof javax.swing.plaf.UIResource && linkedStyleSheets.size() > 1) { index = linkedStyleSheets.size() - 1; } linkedStyleSheets.insertElementAt(ss, index); linkStyleSheetAt(ss, index); } } } /** * Removes the StyleSheet <code>ss</code> from those of the receiver. * * @since 1.3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -