| /******************************************************************************* |
| * 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.io.IOException; |
| import java.io.UnsupportedEncodingException; |
| |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.wst.css.core.internal.provisional.adapters.IModelProvideAdapter; |
| import org.eclipse.wst.css.core.internal.provisional.adapters.IStyleSheetListAdapter; |
| import org.eclipse.wst.css.core.internal.provisional.contenttype.ContentTypeIdForCSS; |
| import org.eclipse.wst.css.core.internal.provisional.document.ICSSModel; |
| import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier; |
| import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; |
| import org.eclipse.wst.sse.core.internal.util.URIResolver; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| |
| /** |
| */ |
| public class LinkElementAdapter extends AbstractStyleSheetAdapter { |
| |
| private final static String CSS_ID = ContentTypeIdForCSS.ContentTypeID_CSS; |
| private boolean replaceModel = true; |
| // this variable to hold the class is just a VAJava trick. |
| // it improves performance in VAJava by minimizing class loading. |
| private final Class ModelProvideAdapterClass = IModelProvideAdapter.class; |
| |
| /** |
| */ |
| protected LinkElementAdapter() { |
| super(); |
| } |
| |
| /** |
| */ |
| private void attrReplaced() { |
| this.replaceModel = true; |
| |
| Element element = getElement(); |
| if (element == null) |
| return; // error |
| Document document = element.getOwnerDocument(); |
| if (document == null) |
| return; // error |
| INodeNotifier notifier = (INodeNotifier) document; |
| HTMLDocumentAdapter adapter = (HTMLDocumentAdapter) notifier.getAdapterFor(IStyleSheetListAdapter.class); |
| if (adapter == null) |
| return; |
| adapter.childReplaced(); |
| } |
| |
| protected ICSSModel createModel() { |
| // create phantom(broken link) external CSS model |
| if (getElement() == null) |
| return null; |
| IStructuredModel baseModel = ((IDOMNode) getElement()).getModel(); |
| ICSSModel newModel = (ICSSModel) baseModel.getModelManager().createUnManagedStructuredModelFor(CSS_ID); |
| |
| // calculate base location and set |
| // get resolver in Model |
| URIResolver resolver = baseModel.getResolver(); |
| |
| // resolve to absolute url : this need not exact location of css file. It is important that absurl is not null. |
| String ref = getElement().getAttribute(org.eclipse.wst.html.core.internal.provisional.HTML40Namespace.ATTR_NAME_HREF); |
| String absurl = (resolver != null && ref != null) ? resolver.getLocationByURI(ref, true) : null; |
| if ((absurl == null) || (absurl.length() == 0)) { |
| IPath basePath = new Path(baseModel.getBaseLocation()); |
| URLHelper helper = new URLHelper(basePath.removeLastSegments(1).toString()); |
| absurl = helper.toAbsolute(ref == null ? "" : ref);//$NON-NLS-1$ |
| } |
| if ((absurl == null) || (absurl.length() == 0)) { |
| absurl = ref; |
| } |
| if (absurl == null) { |
| absurl = "";//$NON-NLS-1$ |
| } |
| newModel.setBaseLocation(absurl); |
| |
| // set style listener |
| newModel.addStyleListener(this); |
| |
| return newModel; |
| } |
| |
| /** |
| */ |
| public ICSSModel getModel() { |
| ICSSModel model = getExistingModel(); |
| if (this.replaceModel) { |
| ICSSModel oldModel = model; |
| |
| model = retrieveModel(); |
| setModel(model); |
| |
| // release old model |
| if (oldModel != null) { |
| // get ModelProvideAdapter |
| IModelProvideAdapter adapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(IModelProvideAdapter.class); |
| adapter.modelRemoved(oldModel); |
| |
| oldModel.releaseFromRead(); |
| |
| } |
| this.replaceModel = false; |
| } |
| return model; |
| } |
| |
| /** |
| */ |
| public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { |
| if (eventType != INodeNotifier.CHANGE) |
| return; |
| Attr attr = (Attr) changedFeature; |
| if (attr == null) |
| return; |
| String name = attr.getName(); |
| if (name.equalsIgnoreCase("rel") || //$NON-NLS-1$ |
| name.equalsIgnoreCase("type") || //$NON-NLS-1$ |
| name.equalsIgnoreCase("href")) {//$NON-NLS-1$ |
| attrReplaced(); |
| } |
| } |
| |
| /** |
| */ |
| public void refreshSheet() { |
| if (!replaceModel) { |
| removed(); |
| replaceModel = true; |
| |
| IDOMNode node = (IDOMNode) getElement(); |
| if (node != null) { |
| node.notify(INodeNotifier.CHANGE, getElement().getAttributeNode(org.eclipse.wst.html.core.internal.provisional.HTML40Namespace.ATTR_NAME_HREF), null, null, node.getStartOffset()); |
| } |
| } |
| } |
| |
| /** |
| */ |
| public void released() { |
| ICSSModel model = getExistingModel(); |
| if (model != null) { |
| try { |
| // get ModelProvideAdapter |
| IModelProvideAdapter adapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(IModelProvideAdapter.class); |
| |
| // set element to null first, so that no document wide updates |
| setElement(null); |
| setModel(null); |
| |
| if (adapter != null) |
| adapter.modelReleased(model); |
| } |
| finally { |
| model.releaseFromRead(); |
| } |
| } |
| this.replaceModel = false; |
| } |
| |
| /** |
| */ |
| public void removed() { |
| ICSSModel model = getExistingModel(); |
| if (model != null) { |
| try { |
| setModel(null); |
| |
| // get ModelProvideAdapter |
| IModelProvideAdapter adapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(IModelProvideAdapter.class); |
| if (adapter != null) |
| adapter.modelRemoved(model); |
| } |
| finally { |
| model.releaseFromRead(); |
| } |
| } |
| this.replaceModel = false; |
| } |
| |
| /** |
| */ |
| protected boolean isValidAttribute() { |
| Element element = getElement(); |
| if (element == null) |
| return false; |
| String rel = element.getAttribute("rel");//$NON-NLS-1$ |
| if (rel == null || !rel.equalsIgnoreCase("stylesheet"))//$NON-NLS-1$ |
| return false; |
| String type = element.getAttribute("type");//$NON-NLS-1$ |
| if (type != null && !type.equalsIgnoreCase("text/css"))//$NON-NLS-1$ |
| return false; |
| String href = element.getAttribute("href");//$NON-NLS-1$ |
| if (href == null || href.length() == 0) |
| return false; |
| return true; |
| } |
| |
| /** |
| */ |
| private ICSSModel retrieveModel() { |
| if (!isValidAttribute()) { |
| return null; |
| } |
| |
| // null,attr check is done in isValidAttribute() |
| Element element = getElement(); |
| String href = element.getAttribute("href");//$NON-NLS-1$ |
| |
| IDOMModel baseModel = ((IDOMNode) element).getModel(); |
| if (baseModel == null) |
| return null; |
| Object id = baseModel.getId(); |
| if (!(id instanceof String)) |
| return null; |
| //String base = (String)id; |
| |
| // get ModelProvideAdapter |
| IModelProvideAdapter adapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(ModelProvideAdapterClass); |
| |
| URLModelProvider provider = new URLModelProvider(); |
| try { |
| IStructuredModel newModel = provider.getModelForRead(baseModel, href); |
| if (newModel == null) |
| return null; |
| if (!(newModel instanceof ICSSModel)) { |
| newModel.releaseFromRead(); |
| return null; |
| } |
| |
| // notify adapter |
| if (adapter != null) |
| adapter.modelProvided(newModel); |
| |
| return (ICSSModel) newModel; |
| } |
| catch (UnsupportedEncodingException e) { |
| } |
| catch (IOException e) { |
| } |
| |
| return null; |
| } |
| |
| /** |
| */ |
| protected void setModel(ICSSModel model) { |
| ICSSModel oldModel = getExistingModel(); |
| if (model == oldModel) |
| return; |
| super.setModel(model); |
| if (this.replaceModel) |
| this.replaceModel = false; |
| if (oldModel != null) |
| oldModel.removeStyleListener(this); |
| if (model != null) |
| model.addStyleListener(this); |
| } |
| } |