blob: c20c184383f69bf53e11d19cd8a2b43c20724b47 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 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.ui.internal.hyperlink;
import java.io.File;
import java.net.URI;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverPlugin;
import org.eclipse.wst.css.core.internal.document.CSSRegionContainer;
import org.eclipse.wst.css.core.internal.provisional.document.ICSSNode;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.w3c.dom.css.CSSImportRule;
import org.w3c.dom.css.CSSPrimitiveValue;
/**
* Detects hyperlink regions within CSS documents. This includes url() methods as
* well as the resource referred to by @import
*
*/
public class CSSHyperlinkDetector extends AbstractHyperlinkDetector {
/* (non-Javadoc)
* @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion, boolean)
*/
public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
if (textViewer != null && region != null) {
final IDocument document = textViewer.getDocument();
final ICSSNode node = getNode(document, region);
if (node == null) {
return null;
}
String href = null;
switch (node.getNodeType()) {
case ICSSNode.PRIMITIVEVALUE_NODE:
if (((CSSPrimitiveValue)node).getPrimitiveType() == CSSPrimitiveValue.CSS_URI) {
href = ((CSSPrimitiveValue) node).getStringValue();
}
break;
case ICSSNode.IMPORTRULE_NODE:
href = ((CSSImportRule) node).getHref();
break;
}
if (href != null) {
final IHyperlink hyperlink = getHyperlink(node, href);
if (hyperlink != null) {
return new IHyperlink[] { hyperlink };
}
}
}
return null;
}
private ICSSNode getNode(IDocument document, IRegion region) {
if (!(document instanceof IStructuredDocument))
return null;
IStructuredModel model = null;
ICSSNode node = null;
try {
model = StructuredModelManager.getModelManager().getModelForRead((IStructuredDocument)document);
node = (ICSSNode) model.getIndexedRegion(region.getOffset());
}
finally {
if (model != null) {
model.releaseFromRead();
}
}
return node;
}
private IHyperlink getHyperlink(ICSSNode node, String href) {
IHyperlink hyperlink = null;
final String baseLocation = getBaseLocation(node.getOwnerDocument().getModel());
if (baseLocation != null) {
final String resolvedHref = URIResolverPlugin.createResolver().resolve(baseLocation, null, href);
if (resolvedHref != null && isValidURI(resolvedHref)) {
final IRegion hyperlinkRegion = getHyperlinkRegion(node, href);
hyperlink = createHyperlink(resolvedHref, hyperlinkRegion);
}
}
return hyperlink;
}
private IRegion getHyperlinkRegion(ICSSNode node, String href) {
CSSRegionContainer uriRegion = null;
switch (node.getNodeType()) {
case ICSSNode.PRIMITIVEVALUE_NODE:
uriRegion = (CSSRegionContainer) node;
break;
case ICSSNode.IMPORTRULE_NODE:
ICSSNode attribute = node.getAttributes().getNamedItem("href"); //$NON-NLS-1$
if (attribute instanceof CSSRegionContainer) {
uriRegion = (CSSRegionContainer) attribute;
}
break;
}
if (uriRegion != null) {
final int start = uriRegion.getStartOffset();
final int end = uriRegion.getEndOffset();
if (end > start)
return new Region(start, end - start);
}
return null;
}
private IHyperlink createHyperlink(String href, IRegion region) {
IHyperlink link = null;
// try to locate the file in the workspace
File systemFile = getFileFromUriString(href);
if (systemFile != null) {
String systemPath = systemFile.getPath();
IFile file = getFile(systemPath);
if (file != null) {
// this is a WorkspaceFileHyperlink since file exists in
// workspace
link = new WorkspaceFileHyperlink(region, file);
}
}
return link;
}
/**
* Returns an IFile from the given uri if possible, null if cannot find
* file from uri.
*
* @param fileString
* file system path
* @return returns IFile if fileString exists in the workspace
*/
private IFile getFile(String fileString) {
IFile file = null;
if (fileString != null) {
Path filePath = new Path(fileString);
if (filePath.segmentCount() > 1 && ResourcesPlugin.getWorkspace().getRoot().getFile(filePath).exists()) {
return ResourcesPlugin.getWorkspace().getRoot().getFile(filePath);
}
IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation(filePath);
for (int i = 0; (i < files.length) && (file == null); i++) {
if (files[i].exists()) {
file = files[i];
}
}
}
return file;
}
/**
* Checks whether the given uriString is really pointing to a file
*
* @param uriString
* @return boolean
*/
private boolean isValidURI(String uriString) {
boolean isValid = false;
File file = getFileFromUriString(uriString);
if (file != null) {
isValid = file.isFile();
}
return isValid;
}
/**
* Create a file from the given uri string
*
* @param uriString -
* assumes uriString is not http://
* @return File created from uriString if possible, null otherwise
*/
private File getFileFromUriString(String uriString) {
File file = null;
try {
// first just try to create a file directly from uriString as
// default in case create file from uri does not work
file = new File(uriString);
// try to create file from uri
URI uri = new URI(uriString);
file = new File(uri);
}
catch (Exception e) {
// if exception is thrown while trying to create File just ignore
// and file will be null
}
return file;
}
/**
* Get the base location from the current model (local file system)
*/
private String getBaseLocation(IStructuredModel model) {
String result = null;
// get the base location from the current model
if (model != null) {
result = model.getBaseLocation();
IPath path = new Path(result);
if (path.segmentCount() > 1) {
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
if (file.exists()) {
String baseLocation = null;
if (file.getLocation() != null) {
baseLocation = file.getLocation().toString();
}
if (baseLocation == null && file.getLocationURI() != null) {
baseLocation = file.getLocationURI().toString();
}
if (baseLocation == null) {
baseLocation = file.getFullPath().toString();
}
result = baseLocation;
}
}
}
return result;
}
}