blob: ec31ff02d7bbf065137296a1b009df7180b0aeb2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2006 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;
}
}