| /******************************************************************************* |
| * 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.html.core.internal.htmlcss; |
| |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| |
| import org.eclipse.wst.css.core.internal.event.ICSSStyleListener; |
| import org.eclipse.wst.css.core.internal.provisional.adapters.IModelProvideAdapter; |
| import org.eclipse.wst.css.core.internal.provisional.adapters.IStyleSheetAdapter; |
| 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.ICSSSelector; |
| import org.eclipse.wst.css.core.internal.util.ImportedCollector; |
| 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.document.XMLModelNotifier; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.stylesheets.DocumentStyle; |
| import org.w3c.dom.stylesheets.StyleSheet; |
| import org.w3c.dom.stylesheets.StyleSheetList; |
| import org.w3c.dom.traversal.DocumentTraversal; |
| import org.w3c.dom.traversal.NodeFilter; |
| import org.w3c.dom.traversal.NodeIterator; |
| |
| /** |
| */ |
| public abstract class AbstractStyleSheetAdapter extends AbstractCSSModelAdapter implements ICSSStyleListener, IStyleSheetAdapter { |
| |
| // this variable to hold the class is just a VAJava trick. |
| // it improves performance in VAJava by minimizing class loading. |
| private final Class StyleSheetAdapterClass = IStyleSheetAdapter.class; |
| private Collection styleChangedNodes; |
| |
| /** |
| */ |
| protected AbstractStyleSheetAdapter() { |
| super(); |
| } |
| |
| /** |
| */ |
| protected ICSSModel createModel() { |
| ICSSModel newModel = super.createModel(); |
| if (newModel != null) { |
| // get ModelProvideAdapter |
| IModelProvideAdapter adapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(IModelProvideAdapter.class); |
| // notify adapter |
| if (adapter != null) |
| adapter.modelProvided(newModel); |
| } |
| return newModel; |
| } |
| |
| /** |
| */ |
| public StyleSheet getSheet() { |
| ICSSModel model = getModel(); |
| if (model == null) |
| return null; |
| return (StyleSheet) model.getDocument(); |
| } |
| |
| /** |
| * 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 == StyleSheetAdapterClass); |
| } |
| |
| /** |
| */ |
| public void released() { |
| ICSSModel currentModel = getModel(); |
| |
| // get ModelProvideAdapter |
| IModelProvideAdapter adapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(IModelProvideAdapter.class); |
| |
| setElement(null); |
| setModel(null); |
| |
| if (adapter != null) |
| adapter.modelReleased(currentModel); |
| |
| if (currentModel != null) |
| currentModel.releaseFromRead(); |
| } |
| |
| /** |
| */ |
| public void removed() { |
| ICSSModel currentModel = getModel(); |
| |
| setModel(null); |
| |
| // get ModelProvideAdapter |
| IModelProvideAdapter adapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(IModelProvideAdapter.class); |
| if (adapter != null) |
| adapter.modelRemoved(currentModel); |
| |
| if (currentModel != null) |
| currentModel.releaseFromRead(); |
| } |
| |
| |
| public void styleChanged(ICSSModel srcModel, ICSSSelector[] removed, ICSSSelector[] added, String media) { |
| Element element = getElement(); |
| if (element == null) |
| return; // might released |
| Document doc = element.getOwnerDocument(); |
| if (doc == null) |
| return; // error |
| |
| // to notify GEF tree |
| if (doc instanceof INodeNotifier) { |
| Collection adapters = ((INodeNotifier) doc).getAdapters(); |
| if (adapters == null) |
| return; |
| Iterator it = adapters.iterator(); |
| if (it == null) |
| return; |
| while (it.hasNext()) { |
| INodeAdapter adapter = (INodeAdapter) it.next(); |
| if (adapter instanceof ICSSStyleListener) { |
| ((ICSSStyleListener) adapter).styleChanged(srcModel, removed, added, media); |
| } |
| } |
| } |
| // |
| |
| if (styleChangedNodes == null) { |
| styleChangedNodes = new HashSet(); |
| } |
| |
| try { |
| int removedSelNum = removed != null ? removed.length : 0; |
| int addedSelNum = added != null ? added.length : 0; |
| |
| NodeIterator iter = ((DocumentTraversal) doc).createNodeIterator(doc, NodeFilter.SHOW_ELEMENT, null, true); |
| Node node; |
| while ((node = iter.nextNode()) != null) { |
| if (node.getNodeType() == Node.ELEMENT_NODE) { |
| Element elm = (Element) node; |
| boolean match = false; |
| int i; |
| for (i = 0; i < removedSelNum && !match; i++) { |
| match = removed[i].match(elm, null); |
| } |
| for (i = 0; i < addedSelNum && !match; i++) { |
| match = added[i].match(elm, null); |
| } |
| if (match) { |
| if (!styleChangedNodes.contains(elm)) |
| styleChangedNodes.add(elm); |
| // notifyStyleChanged(elm); |
| } |
| } |
| } |
| } |
| catch (ClassCastException ex) { |
| // Document doesn't implement DocumentTraversal... |
| } |
| |
| } |
| |
| |
| public void styleUpdate(ICSSModel srcModel) { |
| IDOMNode node = (IDOMNode) getElement(); |
| if (node == null) |
| return; |
| IDOMModel model = node.getModel(); |
| if (model == null) |
| return; |
| XMLModelNotifier notifier = model.getModelNotifier(); |
| if (notifier == null) |
| return; |
| |
| // before updating, all sub-models should be loaded! |
| DocumentStyle document = (DocumentStyle) model.getDocument(); |
| StyleSheetList styles = document.getStyleSheets(); |
| if (styles != null) { |
| int n = styles.getLength(); |
| ImportedCollector trav = new ImportedCollector(); |
| for (int i = 0; i < n; i++) { |
| org.w3c.dom.stylesheets.StyleSheet sheet = styles.item(i); |
| if (sheet instanceof ICSSNode) |
| trav.apply((ICSSNode) sheet); |
| } |
| } |
| |
| // flash style changed events |
| if (styleChangedNodes != null) { |
| Object[] elements = styleChangedNodes.toArray(); |
| for (int i = 0; elements != null && i < elements.length; i++) |
| notifyStyleChanged((Element) elements[i]); |
| styleChangedNodes.clear(); |
| } |
| |
| // to notify GEF tree |
| if (document instanceof INodeNotifier) { |
| Collection adapters = ((INodeNotifier) document).getAdapters(); |
| if (adapters == null) |
| return; |
| Iterator it = adapters.iterator(); |
| if (it == null) |
| return; |
| while (it.hasNext()) { |
| INodeAdapter adapter = (INodeAdapter) it.next(); |
| if (adapter instanceof ICSSStyleListener) { |
| ((ICSSStyleListener) adapter).styleUpdate(srcModel); |
| } |
| } |
| } |
| |
| notifier.propertyChanged(node); |
| } |
| } |