| /******************************************************************************* |
| * Copyright (c) 2004 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.document; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Vector; |
| |
| import org.eclipse.wst.css.core.internal.CSSCoreMessages; |
| import org.eclipse.wst.css.core.internal.encoding.CSSDocumentLoader; |
| import org.eclipse.wst.css.core.internal.provisional.adapters.IStyleSheetAdapter; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSCharsetRule; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSImportRule; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSMediaRule; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSModel; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSNode; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSPageRule; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSStyleDeclaration; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSStyleRule; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSStyleSheet; |
| import org.eclipse.wst.css.core.internal.util.ImportRuleCollector; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; |
| import org.eclipse.wst.sse.core.internal.util.Assert; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.w3c.dom.css.CSSFontFaceRule; |
| import org.w3c.dom.css.CSSRule; |
| import org.w3c.dom.css.CSSRuleList; |
| import org.w3c.dom.css.CSSUnknownRule; |
| import org.w3c.dom.stylesheets.MediaList; |
| import org.w3c.dom.stylesheets.StyleSheet; |
| import org.w3c.dom.stylesheets.StyleSheetList; |
| |
| /** |
| * |
| */ |
| class CSSStyleSheetImpl extends CSSDocumentImpl implements ICSSStyleSheet { |
| |
| |
| class InternalNodeList implements NodeList { |
| |
| Vector nodes = new Vector(); |
| |
| public int getLength() { |
| if (nodes == null) |
| return 0; |
| else |
| return nodes.size(); |
| } |
| |
| public Node item(int i) { |
| if (nodes == null) |
| return null; |
| if (i < 0 || nodes.size() <= i) |
| return null; |
| return (Node) nodes.get(i); |
| } |
| } |
| |
| class InternalStyleSheetList extends AbstractCSSNodeList implements StyleSheetList { |
| |
| public ICSSNode appendNode(ICSSNode node) { |
| if (nodes == null || !nodes.contains(node)) |
| return super.appendNode(node); |
| else |
| return node; |
| } |
| |
| public StyleSheet item(int i) { |
| return (StyleSheet) itemImpl(i); |
| } |
| } |
| |
| private boolean fDisabled = false; |
| |
| /** |
| * |
| */ |
| CSSStyleSheetImpl() { |
| super(); |
| setOwnerDocument(this); |
| } |
| |
| CSSStyleSheetImpl(CSSStyleSheetImpl that) { |
| super(that); |
| setOwnerDocument(this); |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSRule |
| * @param rule |
| * org.w3c.dom.css.CSSRule |
| * @exception org.w3c.dom.DOMException |
| * The exception description. |
| */ |
| public org.w3c.dom.css.CSSRule appendRule(org.w3c.dom.css.CSSRule rule) throws org.w3c.dom.DOMException { |
| if (rule == null) |
| return null; |
| |
| CSSRule ret = (CSSRule) appendChild((CSSNodeImpl) rule); |
| return ret; |
| } |
| |
| public ICSSNode cloneNode(boolean deep) { |
| CSSStyleSheetImpl cloned = new CSSStyleSheetImpl(this); |
| |
| if (deep) |
| cloneChildNodes(cloned, deep); |
| |
| return cloned; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSCharsetRule |
| */ |
| public ICSSCharsetRule createCSSCharsetRule() { |
| CSSCharsetRuleImpl rule = new CSSCharsetRuleImpl(); |
| rule.setOwnerDocument(this); |
| return rule; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSFontFaceRule |
| */ |
| public CSSFontFaceRule createCSSFontFaceRule() { |
| CSSFontFaceRuleImpl rule = new CSSFontFaceRuleImpl(); |
| CSSStyleDeclarationImpl style = (CSSStyleDeclarationImpl) createCSSStyleDeclaration(); |
| |
| rule.appendChild(style); |
| rule.setOwnerDocument(this); |
| |
| return rule; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSImportRule |
| */ |
| public ICSSImportRule createCSSImportRule() { |
| CSSImportRuleImpl rule = new CSSImportRuleImpl(); |
| MediaListImpl media = (MediaListImpl) createMediaList(); |
| |
| rule.appendChild(media); |
| rule.setOwnerDocument(this); |
| |
| return rule; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.ICSSMediaRule |
| */ |
| public ICSSMediaRule createCSSMediaRule() { |
| CSSMediaRuleImpl rule = new CSSMediaRuleImpl(); |
| MediaListImpl media = (MediaListImpl) createMediaList(); |
| |
| rule.insertBefore(media, (CSSNodeImpl) rule.getFirstChild()); // media |
| // must |
| // be |
| // the |
| // top |
| // of |
| // children |
| // list |
| rule.setOwnerDocument(this); |
| |
| return rule; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSPageRule |
| */ |
| public ICSSPageRule createCSSPageRule() { |
| CSSPageRuleImpl rule = new CSSPageRuleImpl(); |
| CSSStyleDeclarationImpl style = (CSSStyleDeclarationImpl) createCSSStyleDeclaration(); |
| |
| rule.appendChild(style); |
| rule.setOwnerDocument(this); |
| |
| return rule; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSRule |
| * @param rule |
| * java.lang.String |
| */ |
| public CSSRule createCSSRule(String rule) { |
| CSSDocumentLoader loader = new CSSDocumentLoader(); |
| IStructuredDocument structuredDocument = (IStructuredDocument) loader.createNewStructuredDocument(); |
| structuredDocument.set(rule); |
| |
| //CSSModelParser modelParser = new CSSModelParser((CSSDocumentImpl) getOwnerDocument()); |
| CSSModelParser modelParser = new CSSModelParser(getOwnerDocument()); |
| return modelParser.createCSSRule(structuredDocument.getRegionList()); |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSStyleDeclaration |
| */ |
| public ICSSStyleDeclaration createCSSStyleDeclaration() { |
| CSSStyleDeclarationImpl decl = new CSSStyleDeclarationImpl(false); |
| decl.setOwnerDocument(this); |
| |
| return decl; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSStyleRule |
| */ |
| public ICSSStyleRule createCSSStyleRule() { |
| CSSStyleRuleImpl rule = new CSSStyleRuleImpl(); |
| CSSStyleDeclarationImpl style = (CSSStyleDeclarationImpl) createCSSStyleDeclaration(); |
| |
| rule.appendChild(style); |
| rule.setOwnerDocument(this); |
| |
| return rule; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSUnknownRule |
| */ |
| public CSSUnknownRule createCSSUnknownRule() { |
| CSSUnknownRuleImpl rule = new CSSUnknownRuleImpl(); |
| rule.setOwnerDocument(this); |
| |
| return rule; |
| } |
| |
| /** |
| * @return org.w3c.dom.stylesheets.MediaList |
| */ |
| public MediaList createMediaList() { |
| MediaListImpl media = new MediaListImpl(); |
| media.setOwnerDocument(this); |
| |
| return media; |
| } |
| |
| /** |
| * Used to delete a rule from the style sheet. |
| * |
| * @param index |
| * The index within the style sheet's rule list of the rule to |
| * remove. |
| * @exception DOMException |
| * INDEX_SIZE_ERR: Raised if the specified index does not |
| * correspond to a rule in the style sheet's rule list. |
| * <br> |
| * NO_MODIFICATION_ALLOWED_ERR: Raised if this style sheet |
| * is readonly. |
| */ |
| public void deleteRule(int index) throws DOMException { |
| CSSNodeImpl node = getIndexedRule(index); |
| if (node != null) |
| removeChild(node); |
| } |
| |
| /** |
| * The list of all CSS rules contained within the style sheet. This |
| * includes both rule sets and at-rules. |
| */ |
| public CSSRuleList getCssRules() { |
| CSSRuleListImpl list = new CSSRuleListImpl(); |
| |
| for (ICSSNode node = getFirstChild(); node != null; node = node.getNextSibling()) { |
| if (node instanceof CSSRule) { |
| list.appendNode(node); |
| } |
| } |
| |
| return list; |
| } |
| |
| /** |
| * <code>false</code> if the style sheet is applied to the document. |
| * <code>true</code> if it is not. Modifying this attribute may cause a |
| * new resolution of style for the document. A stylesheet only applies if |
| * both an appropriate medium definition is present and the disabled |
| * attribute is false. So, if the media doesn't apply to the current user |
| * agent, the <code>disabled</code> attribute is ignored. |
| */ |
| public boolean getDisabled() { |
| return fDisabled; |
| } |
| |
| /** |
| * If the style sheet is a linked style sheet, the value of its attribute |
| * is its location. For inline style sheets, the value of this attribute |
| * is <code>null</code>. See the href attribute definition for the |
| * <code>LINK</code> element in HTML 4.0, and the href pseudo-attribute |
| * for the XML style sheet processing instruction. |
| */ |
| public String getHref() { |
| ICSSModel model = getModel(); |
| if (model != null && model.getStyleSheetType() == ICSSModel.EXTERNAL) { |
| return model.getBaseLocation(); |
| /* |
| * Object id = model.getId(); if (id != null) { if (id instanceof |
| * IResource) { // TODO: need to check whether this is correct or |
| * not, later. return ((IResource)id).getFullPath().toString(); } |
| * return id.toString(); } |
| */} |
| return null; |
| } |
| |
| CSSRuleImpl getIndexedRule(int index) { |
| if (index < 0) |
| return null; |
| |
| int i = 0; |
| for (ICSSNode node = getFirstChild(); node != null; node = node.getNextSibling()) { |
| if (node instanceof CSSRule) { |
| if (i++ == index) |
| return (CSSRuleImpl) node; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * The intended destination media for style information. The media is |
| * often specified in the <code>ownerNode</code>. If no media has been |
| * specified, the <code>MediaList</code> will be empty. See the media |
| * attribute definition for the <code>LINK</code> element in HTML 4.0, |
| * and the media pseudo-attribute for the XML style sheet processing |
| * instruction . Modifying the media list may cause a change to the |
| * attribute <code>disabled</code>. |
| */ |
| public MediaList getMedia() { |
| return null; |
| } |
| |
| /** |
| * @return short |
| */ |
| public short getNodeType() { |
| return STYLESHEET_NODE; |
| } |
| |
| /** |
| * The node that associates this style sheet with the document. For HTML, |
| * this may be the corresponding <code>LINK</code> or <code>STYLE</code> |
| * element. For XML, it may be the linking processing instruction. For |
| * style sheets that are included by other style sheets, the value of this |
| * attribute is <code>null</code>. |
| */ |
| public Node getOwnerNode() { |
| // for <LINK> tag or <STYLE> tag |
| ICSSModel model = getModel(); |
| if (model != null) |
| return model.getOwnerDOMNode(); |
| return null; |
| } |
| |
| /** |
| * @return org.w3c.dom.NodeList |
| */ |
| public org.w3c.dom.NodeList getOwnerNodes() { |
| List list = (getModel().getStyleListeners() != null) ? new Vector(getModel().getStyleListeners()) : null; |
| if (list == null) |
| return null; |
| InternalNodeList nodes = new InternalNodeList(); |
| Iterator it = list.iterator(); |
| while (it.hasNext()) { |
| Object obj = it.next(); |
| if (obj instanceof IStyleSheetAdapter) { |
| nodes.nodes.add(((IStyleSheetAdapter) obj).getElement()); |
| } |
| } |
| if (nodes.getLength() > 0) |
| return nodes; |
| else |
| return null; |
| } |
| |
| /** |
| * @return org.w3c.dom.NodeList |
| * @param doc |
| * org.w3c.dom.Document |
| */ |
| public NodeList getOwnerNodes(Document doc) { |
| List list = (getModel().getStyleListeners() != null) ? new Vector(getModel().getStyleListeners()) : null; |
| if (list == null) |
| return null; |
| InternalNodeList nodes = new InternalNodeList(); |
| Iterator it = list.iterator(); |
| while (it.hasNext()) { |
| Object obj = it.next(); |
| if (obj instanceof IStyleSheetAdapter) { |
| Element ele = ((IStyleSheetAdapter) obj).getElement(); |
| if (ele.getOwnerDocument() == doc) |
| nodes.nodes.add(ele); |
| } |
| } |
| if (nodes.getLength() > 0) |
| return nodes; |
| else |
| return null; |
| } |
| |
| /** |
| * If this style sheet comes from an <code>@import</code> rule, the <code>ownerRule</code> attribute will |
| * contain the <code>CSSImportRule</code>. In that case, the |
| * <code>ownerNode</code> attribute in the |
| * <code>StyleSheet</code> interface will be <code>null</code>. |
| * If the style sheet comes from an element or a processing |
| * instruction, the <code>ownerRule</code> attribute will be |
| * <code>null</code> and the <code>ownerNode</code> attribute |
| * will contain the <code>Node</code>. |
| */ |
| public CSSRule getOwnerRule() { |
| Assert.isTrue(false, CSSCoreMessages.You_cannot_use_CSSStyleShe_UI_); //$NON-NLS-1$ = "You cannot use CSSStyleSheet.getOwnerRule() because of many referencers of this rule\nPlease use getOnwerRules()" |
| // for @import |
| return null; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSRuleList |
| */ |
| public org.w3c.dom.css.CSSRuleList getOwnerRules() { |
| StyleSheetList list = getParentStyleSheets(); |
| if (list == null) |
| return null; |
| CSSRuleListImpl ruleList = new CSSRuleListImpl(); |
| for (int i = 0; i < list.getLength(); i++) { |
| ImportRuleCollector trav = new ImportRuleCollector(this); |
| trav.apply((ICSSStyleSheet) list.item(i)); |
| ruleList.nodes.addAll(trav.getRules()); |
| } |
| return ruleList; |
| } |
| |
| /** |
| * For style sheet languages that support the concept of style sheet |
| * inclusion, this attribute represents the including style sheet, if one |
| * exists. If the style sheet is a top-level style sheet, or the style |
| * sheet language does not support inclusion, the value of this attribute |
| * is <code>null</code>. |
| */ |
| public StyleSheet getParentStyleSheet() { |
| CSSRule owner = getOwnerRule(); |
| if (owner != null) |
| return owner.getParentStyleSheet(); |
| return null; |
| } |
| |
| /** |
| * @return org.w3c.dom.stylesheets.StyleSheetList |
| */ |
| public org.w3c.dom.stylesheets.StyleSheetList getParentStyleSheets() { |
| List list = (getModel().getStyleListeners() != null) ? new Vector(getModel().getStyleListeners()) : null; |
| if (list == null) |
| return null; |
| InternalStyleSheetList sheets = new InternalStyleSheetList(); |
| Iterator it = list.iterator(); |
| while (it.hasNext()) { |
| Object obj = it.next(); |
| if (obj instanceof ICSSModel) { |
| sheets.appendNode(((ICSSModel) obj).getDocument()); |
| } |
| } |
| if (sheets.getLength() > 0) |
| return sheets; |
| else |
| return null; |
| } |
| |
| /** |
| * The advisory title. The title is often specified in the |
| * <code>ownerNode</code>. See the title attribute definition for the |
| * <code>LINK</code> element in HTML 4.0, and the title pseudo-attribute |
| * for the XML style sheet processing instruction. |
| */ |
| public String getTitle() { |
| Node node = getOwnerNode(); |
| if (node instanceof Element) { |
| return ((Element) node).getAttribute("TITLE");//$NON-NLS-1$ |
| } |
| return null; |
| } |
| |
| /** |
| * This specifies the style sheet language for this style sheet. The style |
| * sheet language is specified as a content type (e.g. "text/css"). The |
| * content type is often specified in the <code>ownerNode</code>. Also |
| * see the type attribute definition for the <code>LINK</code> element |
| * in HTML 4.0, and the type pseudo-attribute for the XML style sheet |
| * processing instruction. |
| */ |
| public String getType() { |
| Node node = getOwnerNode(); |
| if (node instanceof Element) { |
| return ((Element) node).getAttribute("TYPE");//$NON-NLS-1$ |
| } |
| return null; |
| } |
| |
| /** |
| * Used to insert a new rule into the style sheet. The new rule now |
| * becomes part of the cascade. |
| * |
| * @param rule |
| * The parsable text representing the rule. For rule sets this |
| * contains both the selector and the style declaration. For |
| * at-rules, this specifies both the at-identifier and the rule |
| * content. |
| * @param index |
| * The index within the style sheet's rule list of the rule |
| * before which to insert the specified rule. If the specified |
| * index is equal to the length of the style sheet's rule |
| * collection, the rule will be added to the end of the style |
| * sheet. |
| * @return The index within the style sheet's rule collection of the newly |
| * inserted rule. |
| * @exception DOMException |
| * HIERARCHY_REQUEST_ERR: Raised if the rule cannot be |
| * inserted at the specified index e.g. if an |
| * <code>@import</code> rule is inserted after a standard rule set or other |
| * at-rule. <br> |
| * INDEX_SIZE_ERR: Raised if the specified index is not a valid |
| * insertion point. <br> |
| * NO_MODIFICATION_ALLOWED_ERR: Raised if this style sheet is |
| * readonly. <br> |
| * SYNTAX_ERR: Raised if the specified rule has a syntax error and |
| * is unparsable. |
| */ |
| public int insertRule(String rule, int index) throws DOMException { |
| int length = getCssRules().getLength(); |
| if (index < 0 || length < index) |
| throw new DOMException(DOMException.INDEX_SIZE_ERR, "");//$NON-NLS-1$ |
| |
| IStructuredDocument doc = getModel().getStructuredDocument(); |
| CSSRuleImpl refRule = (length != index) ? getIndexedRule(index) : null; |
| int offset = (refRule != null) ? refRule.getStartOffset() : doc.getLength(); |
| doc.replaceText(this, offset, 0, rule); |
| |
| // insertBefore((CSSNodeImpl) createCSSRule(rule),refRule); |
| return index; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSRule |
| * @param newRule |
| * org.w3c.dom.css.CSSRule |
| * @param refRule |
| * org.w3c.dom.css.CSSRule |
| */ |
| public org.w3c.dom.css.CSSRule insertRuleBefore(org.w3c.dom.css.CSSRule newRule, org.w3c.dom.css.CSSRule refRule) throws org.w3c.dom.DOMException { |
| if (newRule == null && refRule == null) |
| return null; |
| |
| CSSRule ret = (CSSRule) insertBefore((CSSNodeImpl) newRule, (CSSNodeImpl) refRule); |
| return ret; |
| } |
| |
| /** |
| * @return boolean |
| */ |
| public boolean isDocument() { |
| return true; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSRule |
| * @param rule |
| * org.w3c.dom.css.CSSRule |
| * @exception org.w3c.dom.DOMException |
| * The exception description. |
| */ |
| public org.w3c.dom.css.CSSRule removeRule(org.w3c.dom.css.CSSRule rule) throws org.w3c.dom.DOMException { |
| if (rule == null) |
| return null; |
| |
| CSSRule ret = (CSSRule) removeChild((CSSNodeImpl) rule); |
| return ret; |
| } |
| |
| /** |
| * @return org.w3c.dom.css.CSSRule |
| * @param newChild |
| * org.w3c.dom.css.CSSRule |
| * @param oldChild |
| * org.w3c.dom.css.CSSRule |
| * @exception org.w3c.dom.DOMException |
| * The exception description. |
| */ |
| public org.w3c.dom.css.CSSRule replaceRule(org.w3c.dom.css.CSSRule newRule, org.w3c.dom.css.CSSRule oldRule) throws org.w3c.dom.DOMException { |
| if (newRule == null && oldRule == null) |
| return null; |
| |
| CSSRule ret = (CSSRule) replaceChild((CSSNodeImpl) newRule, (CSSNodeImpl) oldRule); |
| return ret; |
| } |
| |
| /** |
| * setDisabled method comment. |
| */ |
| public void setDisabled(boolean disabled) { |
| this.fDisabled = disabled; |
| } |
| } |