blob: 48f34ec4cba2c325f2d510807804295201e6beec [file] [log] [blame]
/*******************************************************************************
* 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;
try {
model = retrieveModel();
setModel(model);
// release old model
if (oldModel != null) {
// get ModelProvideAdapter
IModelProvideAdapter adapter = (IModelProvideAdapter) ((INodeNotifier) getElement()).getAdapterFor(IModelProvideAdapter.class);
if (adapter != null)
adapter.modelRemoved(oldModel);
}
}
finally {
if (oldModel != null)
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);
}
}