Package org.eclipse.wst.html.core.internal.htmlcss

Source Code of org.eclipse.wst.html.core.internal.htmlcss.HTMLDocumentAdapter

/*******************************************************************************
* Copyright (c) 2004, 2010 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.html.core.internal.htmlcss;



import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.eclipse.wst.css.core.internal.provisional.adapters.IStyleSheetAdapter;
import org.eclipse.wst.css.core.internal.provisional.adapters.IStyleSheetListAdapter;
import org.eclipse.wst.css.core.internal.provisional.document.ICSSImportRule;
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.util.CSSClassTraverser;
import org.eclipse.wst.css.core.internal.util.ImportRuleCollector;
import org.eclipse.wst.html.core.internal.contentmodel.JSP11Namespace;
import org.eclipse.wst.html.core.internal.provisional.HTML40Namespace;
import org.eclipse.wst.sse.core.internal.provisional.INodeAdapter;
import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.css.CSSStyleDeclaration;
import org.w3c.dom.stylesheets.StyleSheet;
import org.w3c.dom.stylesheets.StyleSheetList;



/**
*/
public class HTMLDocumentAdapter implements IStyleSheetListAdapter, StyleSheetList {

  private Document document = null;
  private Vector styleAdapters = null;
  private Vector oldStyleAdapters = null;

  /**
   */
  HTMLDocumentAdapter() {
    super();
  }

  /**
   */
  private void addStyleSheet(Element node) {
    IDOMElement element = (IDOMElement) node;
    String tagName = element.getTagName();
    if (tagName == null)
      return;
    boolean isContainer = false;
    if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HTML) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HEAD) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.NOSCRIPT) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.BASE) || tagName.equalsIgnoreCase(JSP11Namespace.ElementName.ROOT) || (!element.isGlobalTag() && element.isContainer())) {
      isContainer = true;
    }
    else if (element.isCommentTag()) {
      Node parent = element.getParentNode();
      if (parent == element.getOwnerDocument()) {
        // This condition is too severe, actually do not work for JSF template.
        // But above (! globalTag() && isContainer()) cover JSF template + tpl template
        isContainer = true;
      }
      else if (parent.getNodeType() == Node.ELEMENT_NODE) {
        tagName = ((Element) parent).getTagName();
        if (tagName != null && tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HEAD)) {
          isContainer = true;
        }
      }
    }

    else {
      String localName = element.getLocalName();
      if (localName != null && localName.equalsIgnoreCase(HTML40Namespace.ElementName.HTML)) {
        // taglib html tag
        isContainer = true;
      }
      else {
        INodeNotifier notifier = element;
        INodeAdapter adapter = notifier.getAdapterFor(IStyleSheetAdapter.class);
        if (adapter != null && adapter instanceof IStyleSheetAdapter) {
          this.styleAdapters.addElement(adapter);
        }
      }
    }
    if (isContainer) {
      INodeNotifier notifier = element;
      if (notifier.getExistingAdapter(IStyleSheetListAdapter.class) == null) {
        notifier.addAdapter(this);
      }
      for (Node child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
        if (child.getNodeType() != Node.ELEMENT_NODE)
          continue;
        addStyleSheet((Element) child);
      }
    }
  }

  /**
   */
  void childReplaced() {
    if (this.styleAdapters == null)
      return;

    // backup old adapters to be released on updating in getStyleSheets()
    this.oldStyleAdapters = this.styleAdapters;
    // invalidate the list
    this.styleAdapters = null;

    notifyStyleSheetsChanged(this.document);
  }

  /**
   */
  public Enumeration getClasses() {
    StyleSheetList sheetList = getStyleSheets();
    int nSheets = sheetList.getLength();

    final ArrayList classes = new ArrayList();

    CSSClassTraverser traverser = new CSSClassTraverser();
    traverser.setTraverseImported(true);

    for (int i = 0; i < nSheets; i++) {
      org.w3c.dom.stylesheets.StyleSheet sheet = sheetList.item(i);
      if (sheet instanceof ICSSNode) {
        traverser.apply((ICSSNode) sheet);
      }
    }
    classes.addAll(traverser.getClassNames());

    return new Enumeration() {
      int i = 0;

      public boolean hasMoreElements() {
        return i < classes.size();
      }

      public Object nextElement() {
        return classes.get(i++);
      }
    };
  }

  /**
   */
  private List getValidAdapters() {
    Vector validAdapters = new Vector();
    if (this.styleAdapters != null) {
      Iterator i = this.styleAdapters.iterator();
      while (i.hasNext()) {
        Object obj = i.next();
        if (obj instanceof AbstractStyleSheetAdapter && ((AbstractStyleSheetAdapter) obj).isValidAttribute()) {
          validAdapters.add(obj);
        }
      }
    }
    return validAdapters;
  }

  /**
   */
  public int getLength() {
    return getValidAdapters().size();
  }

  /**
   */
  public CSSStyleDeclaration getOverrideStyle(Element element, String pseudoName) {
    StyleSheetList ssl = getStyleSheets();
    int numStyles = ssl.getLength();

    CSSQueryTraverser query = new CSSQueryTraverser();
    query.setTraverseImported(true);
    query.setTraverseImportFirst(true);
    query.setElement(element, pseudoName);

    for (int i = 0; i < numStyles; i++) {
      // loop for styles (<style> and <link>)
      org.w3c.dom.stylesheets.StyleSheet ss = ssl.item(i);

      try {
        query.apply((ICSSNode) ss);
      }
      catch (ClassCastException ex) {
        // I can handle only CSS style
      }
    }

    return query.getDeclaration();
  }

  /**
   */
  public StyleSheetList getStyleSheets() {
    if (this.styleAdapters == null) {
      if (this.document == null)
        return null;

      this.styleAdapters = new Vector();
      for (Node child = this.document.getFirstChild(); child != null; child = child.getNextSibling()) {
        if (child.getNodeType() != Node.ELEMENT_NODE)
          continue;
        addStyleSheet((Element) child);
      }

      removeOldStyleSheets();
    }
    return this;
  }

  /**
   * Allowing the INodeAdapter to compare itself against the type
   * allows it to return true in more than one case.
   */
  public boolean isAdapterForType(Object type) {
    return (type == IStyleSheetListAdapter.class);
  }

  /**
   */
  public StyleSheet item(int index) {
    if (this.styleAdapters == null)
      return null;

    List validAdapters = getValidAdapters();

    if (index < 0 || index >= validAdapters.size())
      return null;
    StyleSheet sheet = ((IStyleSheetAdapter) validAdapters.get(index)).getSheet();
    if (sheet == null) {// for LINK element whose link is broken
      ICSSModel model = ((AbstractStyleSheetAdapter) validAdapters.get(index)).createModel();
      sheet = ((model != null) ? (StyleSheet) model.getDocument() : null);
    }
    return sheet;
  }

  /**
   */
  public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
    Node node = null;
    switch (eventType) {
      case INodeNotifier.ADD :
        if (newValue instanceof Node)
          node = (Node) newValue;
        else if (changedFeature instanceof Attr)
          node = ((Attr) changedFeature);
        break;
      case INodeNotifier.REMOVE :
        if (oldValue instanceof Node)
          node = (Node) oldValue;
        else if (changedFeature instanceof Attr)
          node = ((Attr) changedFeature);
        break;
      case INodeNotifier.CHANGE :
        node = (Node) notifier;
        break;
      default :
        break;
    }
   
    if (node == null)
      return;
   
    switch(node.getNodeType()) {
      case Node.ELEMENT_NODE: {
        IDOMElement element = (IDOMElement) node;
        String tagName = element.getTagName();
        if (tagName == null)
          return;

        if (eventType == INodeNotifier.CHANGE) {
          if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.BASE)) {
            refreshAdapters();
          }
        }
        else {
          if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HTML) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HEAD) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.STYLE) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.LINK) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.NOSCRIPT) || tagName.equalsIgnoreCase(JSP11Namespace.ElementName.ROOT) || element.isCommentTag() || (!element.isGlobalTag() && element.isContainer())) {
            childReplaced();
          }
          else if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.BASE)) {
            refreshAdapters();
          }
          else {
            String localName = element.getLocalName();
            if (localName != null && localName.equalsIgnoreCase(HTML40Namespace.ElementName.HTML)) {
              // taglib html tag
              childReplaced();
            }
          }
        }
        break;
      }
      case Node.ATTRIBUTE_NODE : {
        if (HTML40Namespace.ElementName.BASE.equals(((Attr) node).getOwnerElement().getLocalName())) {
          refreshAdapters();
        }
      }
    }
   
  }

  /**
   * reload LINK / @import if BASE changed
   */
  private void refreshAdapters() {
    Iterator iAdapter = this.styleAdapters.iterator();
    while (iAdapter.hasNext()) {
      Object adapter = iAdapter.next();
      if (adapter instanceof LinkElementAdapter) {
        ((LinkElementAdapter) adapter).refreshSheet();
      }
      else if (adapter instanceof StyleElementAdapter) {
        ICSSModel model = ((StyleElementAdapter) adapter).getModel();
        ImportRuleCollector trav = new ImportRuleCollector();
        trav.apply(model);
        Iterator iRule = trav.getRules().iterator();
        while (iRule.hasNext()) {
          ICSSImportRule rule = (ICSSImportRule) iRule.next();
          rule.refreshStyleSheet();
        }
      }
    }
  }

  /**
   */
  private void notifyStyleSheetsChanged(Document target) {
    INodeNotifier notifier = (INodeNotifier) target;
    if (notifier == null)
      return;
    Collection adapters = notifier.getAdapters();
    if (adapters == null)
      return;
    Iterator it = adapters.iterator();
    if (it == null)
      return;
    while (it.hasNext()) {
      INodeAdapter adapter = (INodeAdapter) it.next();
      if (adapter instanceof StyleListener) {
        StyleListener listener = (StyleListener) adapter;
        listener.styleChanged();
      }
    }
  }

  /**
   */
  private void releaseOldStyleSheets() {
    if (this.oldStyleAdapters == null)
      return;
    Iterator it = this.oldStyleAdapters.iterator();
    while (it.hasNext()) {
      IStyleSheetAdapter adapter = (IStyleSheetAdapter) it.next();
      if (adapter == null)
        continue;
      // if the same adapter is in the current list,
      // do not release
      if (this.styleAdapters != null && this.styleAdapters.contains(adapter))
        continue;
      adapter.released();
    }
    this.oldStyleAdapters = null;
  }

  /**
   */
  public void releaseStyleSheets() {
    releaseOldStyleSheets();

    if (this.styleAdapters == null)
      return;
    Iterator it = this.styleAdapters.iterator();
    while (it.hasNext()) {
      IStyleSheetAdapter adapter = (IStyleSheetAdapter) it.next();
      if (adapter != null)
        adapter.released();
    }
    this.styleAdapters = null;
  }

  /**
   */
  private void removeOldStyleSheets() {
    if (this.oldStyleAdapters == null)
      return;
    Iterator it = this.oldStyleAdapters.iterator();
    while (it.hasNext()) {
      IStyleSheetAdapter adapter = (IStyleSheetAdapter) it.next();
      if (adapter == null)
        continue;
      // if the same adapter is in the current list,
      // do not release
      if (this.styleAdapters != null && this.styleAdapters.contains(adapter))
        continue;
      adapter.removed();
    }
    this.oldStyleAdapters = null;
  }

  /**
   */
  void setDocument(Document document) {
    this.document = document;
  }
}
TOP

Related Classes of org.eclipse.wst.html.core.internal.htmlcss.HTMLDocumentAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.