/*******************************************************************************
* Copyright (c) 2005, 2007 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
*
*******************************************************************************/
package org.eclipse.vjet.eclipse.internal.ui.text.completion;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.dltk.mod.core.DLTKCore;
import org.eclipse.dltk.mod.core.IModelElement;
import org.eclipse.dltk.mod.internal.core.Member;
import org.eclipse.dltk.mod.internal.core.VjoSourceModule;
import org.eclipse.dltk.mod.internal.core.VjoSourceType;
import org.eclipse.dltk.mod.ui.text.completion.HTMLPrinter;
import org.eclipse.dltk.mod.ui.text.completion.ScriptCompletionProposal;
import org.eclipse.dltk.mod.ui.text.completion.TypeProposalInfo;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension4;
import org.eclipse.osgi.service.datalocation.Location;
import org.eclipse.swt.graphics.Image;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.vjet.dsf.jst.BaseJstNode;
import org.eclipse.vjet.dsf.jst.IJstMethod;
import org.eclipse.vjet.dsf.jst.IJstProperty;
import org.eclipse.vjet.dsf.jst.IJstType;
import org.eclipse.vjet.dsf.jst.declaration.JstArg;
import org.eclipse.vjet.dsf.jst.declaration.JstModifiers;
import org.eclipse.vjet.eclipse.internal.ui.scriptdoc.JavaDoc2HTMLTextReader;
import org.eclipse.vjet.eclipse.ui.VjetUIPlugin;
import org.eclipse.vjet.vjo.tool.typespace.TypeSpaceMgr;
public class VjoCompletionProposal extends ScriptCompletionProposal implements
ICompletionProposalExtension4 {
private boolean m_isAutoInsert;
private ImportRewriter needsRewriter = new ImportRewriter();
private Object extraInfo;
public VjoCompletionProposal(String replacementString,
int replacementOffset, int replacementLength, Image image,
String displayString, int relevance) {
super(replacementString, replacementOffset, replacementLength, image,
displayString, relevance);
setContextInformation(null);
// ProposalInfo proposalInfo = new ProposalInfo(null);
// this.setProposalInfo(proposalInfo);
}
public VjoCompletionProposal(String replacementString,
int replacementOffset, int replacementLength, Image image,
String displayString, int relevance, boolean isInDoc) {
super(replacementString, replacementOffset, replacementLength, image,
displayString, relevance, isInDoc);
setContextInformation(null);
// ProposalInfo proposalInfo = new ProposalInfo(null);
// this.setProposalInfo(proposalInfo);
}
@Override
protected boolean isSmartTrigger(char trigger) {
if (trigger == '$') {
return true;
}
return false;
}
@Override
protected boolean isValidPrefix(String prefix) {
if ((getProposalInfo() instanceof TypeProposalInfo)
&& prefix.contains(".")) {
return isPrefix(prefix.substring(prefix.lastIndexOf('.') + 1),
getDisplayString());
}
return isPrefix(prefix, getDisplayString());
}
public void setAutoInsert(boolean isAutoInsert) {
m_isAutoInsert = isAutoInsert;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension4#isAutoInsertable()
*/
public boolean isAutoInsertable() {
return m_isAutoInsert;
}
@Override
public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
IModelElement element = getModelElement();
String info = getAdditionalPropesalInfo(element, getCSSStyles());
return info;
}
private static final String PERS_FOLDER = "org.eclipse.vjet.eclipse.ui"; //$NON-NLS-1$
private static final String PERS_FILENAME = "additionalCompletionTemplate.html"; //$NON-NLS-1$
/**
* @param baseUrl
* @param create
*/
private static void generateTempFolder(URL baseUrl, boolean create) {
if (baseUrl == null) {
return;
}
try {
// make sure the directory exists
URL url = new URL(baseUrl, PERS_FOLDER);
File dir = new File(url.getFile());
if (!dir.exists() && create) {
dir.mkdir();
}
} catch (IOException e) {
}
}
public static String getAdditionalPropesalInfo(IModelElement element,
String css) {
String info = null;
if (element != null) {
VjoSourceModule module = null;
if (element instanceof Member) {
try {
if (element.getParent() instanceof VjoSourceModule) {
module = (VjoSourceModule) element.getParent();
} else if (element.getParent().getParent() instanceof VjoSourceModule) {
module = (VjoSourceModule) element.getParent()
.getParent();
}
} catch (Exception e) {
DLTKCore.warn(e.toString(), e);
return null;
}
}
if (module == null) {
return info;
}
String name = element.getElementName();
TypeSpaceMgr mgr = TypeSpaceMgr.getInstance();
IJstType type = mgr.findType(module.getTypeName());
if (type == null) {
return "";
}
IJstProperty property = type.getProperty(name);
IJstMethod method = type.getMethod(name);
List allSupportedExplorers = new ArrayList();
String briefInfo = "";
if (property != null && property.getDoc() != null) {
info = property.getDoc().getComment();
briefInfo = getElementBriefDesc(property);
fillAllSupportedExplorer(property, allSupportedExplorers);
} else {
if ((method != null) && (method.getDoc() != null)) {
info = method.getDoc().getComment();
briefInfo = getElementBriefDesc(method);
fillAllSupportedExplorer(method, allSupportedExplorers);
}
}
if (info != null) {
try {
copyHtmlTemplateFromBundleToTemp();
copyIconsFromBundleToTemp();
// Replace the invalid character.
info = info.replace("/", "");
info = info.replace("*", "");
Location configLoc = Platform.getConfigurationLocation();
URL url;
File persFile = null;
try {
url = new URL(configLoc.getURL(), PERS_FOLDER);
File dir = new File(url.getFile());
url = new URL(dir.toURL(), PERS_FILENAME);
persFile = new File(url.getFile());
if (persFile != null) {
FileReader readerSuc = new FileReader(persFile);
JavaDoc2HTMLTextReader reader2 = new JavaDoc2HTMLTextReader(
readerSuc);
String wholeInfo = getString(reader2);
wholeInfo = wholeInfo.replace(
"<%=browserSupported%>",
getSupportedTypesStirng(
allSupportedExplorers,
"BrowserType."));
String domLevel = getSupportedTypesStirng(
allSupportedExplorers, "DomLevel.");
if (domLevel.length() > 0) {
wholeInfo = wholeInfo.replace("<%=DOMLevel%>",
"<b>DOM level</b><br>"
+ getSupportedTypesStirng(
allSupportedExplorers,
"DomLevel.") + "<br>");
}
wholeInfo = wholeInfo
.replace(
"<%=MinJSVersion%>",
translateCharacterToNumber(getSupportedTypesStirng(
allSupportedExplorers,
"JsVersion.")));
wholeInfo = wholeInfo.replace("<%=briefInfo%>",
briefInfo);
wholeInfo = wholeInfo.replace("<%=images%>",
getIcon(allSupportedExplorers));
wholeInfo = wholeInfo.replace("<%=description%>",
info);
// Add the css and HTML tags at the beginning and
// end.
StringBuffer buffer = new StringBuffer();
HTMLPrinter.insertPageProlog(buffer, 0, css);
buffer.append(wholeInfo);
HTMLPrinter.addPageEpilog(buffer);
wholeInfo = buffer.toString();
return wholeInfo;
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return info;
}
private static String getSupportedTypesStirng(List supportedTypes,
String type) {
String imageLine = "";
String comma = "";
int i = 0;
for (Object oneType : supportedTypes) {
if (((String) oneType).startsWith(type)) {
if (i != 0) {
comma = ", ";
}
imageLine += comma
+ ((String) oneType).substring(type.length());
i++;
}
}
boolean noBrowserInfo = noBrowserInfo(supportedTypes);
if (noBrowserInfo && "BrowserType.".equals(type)) {
//imageLine = "FIREFOX,IE,OPERA,SAFARI,CHROME";
}
return imageLine;
}
/**
* @param supportedTypes
* @return
*/
private static String getIcon(List supportedTypes) {
String imageLine = "";
String path = "";
try {
URL url = new URL(Platform.getConfigurationLocation().getURL(),
PERS_FOLDER);
path = url.getPath();
path = path.substring(1);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
boolean noBrowserInfo = noBrowserInfo(supportedTypes);
if (getDescOfSupport(supportedTypes, "FIREFOX").trim().length() > 0
|| noBrowserInfo) {
imageLine += "<img aligh=\"right\" src=\""
+ path
+ "/firefox.gif\" height=\"25\" width=\"25\" border=\"0\" title=\""
+ getDescOfSupport(supportedTypes, "MOZILLA") + "\">";
}
if (getDescOfSupport(supportedTypes, "IE").trim().length() > 0
|| noBrowserInfo) {
imageLine += "<img aligh=\"right\" src=\""
+ path
+ "/ie.gif\" height=\"25\" width=\"25\" border=\"0\" title=\""
+ getDescOfSupport(supportedTypes, "IE") + "\">";
}
if (getDescOfSupport(supportedTypes, "OPERA").trim().length() > 0
|| noBrowserInfo) {
imageLine += "<img aligh=\"right\" src=\""
+ path
+ "/opera.gif\" height=\"25\" width=\"25\" border=\"0\" title=\""
+ getDescOfSupport(supportedTypes, "OPERA") + "\">";
}
if (getDescOfSupport(supportedTypes, "SAFARI").trim().length() > 0
|| noBrowserInfo) {
imageLine += "<img aligh=\"right\" src=\""
+ path
+ "/safari.gif\" height=\"25\" width=\"25\" border=\"0\" title=\""
+ getDescOfSupport(supportedTypes, "SAFARI") + "\">";
}
if (getDescOfSupport(supportedTypes, "CHROME").trim().length() > 0
|| noBrowserInfo) {
imageLine += "<img aligh=\"right\" src=\""
+ path
+ "/chrome.gif\" height=\"25\" width=\"25\" border=\"0\" title=\""
+ getDescOfSupport(supportedTypes, "CHROME") + "\">";
}
return imageLine;
}
/**
* @param supportedTypes
* @return
*/
private static boolean noBrowserInfo(List supportedTypes) {
boolean noBrowserInfo = true;
for (Object type : supportedTypes) {
if (((String) type).contains("BrowserType.")) {
noBrowserInfo = false;
break;
}
}
return noBrowserInfo;
}
/**
* @param jstElement
* @return
*/
private static List fillAllSupportedExplorer(Object jstElement,
List allSupportedExplorers) {
if (jstElement instanceof IJstProperty) {
List annotations = ((IJstProperty) jstElement).getAnnotations();
getExplorerInfoFromAnnotation(allSupportedExplorers, annotations);
if (annotations.size() == 0) {
fillAllSupportedExplorer(((IJstProperty) jstElement)
.getOwnerType(), allSupportedExplorers);
}
} else if (jstElement instanceof IJstMethod) {
List annotations = ((IJstMethod) jstElement).getAnnotations();
getExplorerInfoFromAnnotation(allSupportedExplorers, annotations);
if (annotations.size() == 0) {
fillAllSupportedExplorer(((IJstMethod) jstElement)
.getOwnerType(), allSupportedExplorers);
}
} else if (jstElement instanceof IJstType) {
List annotations = ((IJstType) jstElement).getAnnotations();
getExplorerInfoFromAnnotation(allSupportedExplorers, annotations);
}
return allSupportedExplorers;
}
/**
* @param allSupportedExplorers
* @param annotations
*/
private static void getExplorerInfoFromAnnotation(
List allSupportedExplorers, List annotations) {
VjoProposalAditionalInfoGenerator.getExplorerInfoFromAnnotation(allSupportedExplorers, annotations);
}
/**
* Copy the html template to temporary folder.
*/
private static void copyHtmlTemplateFromBundleToTemp() {
String[] htmlFiles = new String[] { PERS_FILENAME };
for (String file : htmlFiles) {
copyFileFromBundleToTemp("templates", file);
}
}
/**
* Copy current icons to temporary folder.
*/
private static void copyIconsFromBundleToTemp() {
String[] icons = new String[] { "chrome.gif", "firefox.gif", "ie.gif",
"opera.gif", "safari.gif" };
for (String icon : icons) {
copyFileFromBundleToTemp("icons", icon);
}
}
/**
* Copy specified icon to temporary folder.
*
* @param folderName
* TODO
*/
private static void copyFileFromBundleToTemp(String folderName,
String fileName) {
try {
Location configLoc = Platform.getConfigurationLocation();
// First check whether we have the temporary folder.
generateTempFolder(new URL(configLoc.getURL(), PERS_FOLDER), true);
URL url = new URL(configLoc.getURL(), PERS_FOLDER + "//" + fileName);
File persFile = new File(url.getFile());
if (persFile.exists()) {
return;
} else {
persFile.createNewFile();
}
InputStream stream = VjetUIPlugin.getDefault().getBundle()
.getEntry("//" + folderName + "//" + fileName).openStream();
byte[] bs = new byte[stream.available()];
stream.read(bs);
FileOutputStream fop = new FileOutputStream(persFile);
if (persFile.exists()) {
fop.write(bs);
fop.flush();
fop.close();
}
} catch (IOException e) {
}
}
/**
* @param supportedTypes
* @param type
* @return
*/
private static String getDescOfSupport(List<String> supportedTypes,
String type) {
for (String everyType : supportedTypes) {
if (everyType.contains(type)) {
return everyType;
}
}
return "";
}
/**
* @param desc
* @return
*/
private static String translateCharacterToNumber(String desc) {
if (desc != null) {
String[] numbers = { "_ZERO", "_ONE", "_TWO", "_THREE", "_FOUR",
"_FIVE", "_SIX", "_SEVEN", "_EIGHT", "_NINE" };
for (int i = 0; i < numbers.length; i++) {
if (desc.contains(numbers[i])) {
desc = desc.replace(numbers[i], String.valueOf(i));
}
}
if (desc.contains("_DOT")) {
desc = desc.replace("_DOT", ".");
}
}
return desc;
}
public static String getElementBriefDesc(IJstProperty property) {
StringBuffer buffer = new StringBuffer();
buffer.append(property.getOwnerType().getName() + "\n");
// buffer.append("<dl><dt>");
buffer.append(getModifierListStr(property.getModifiers()) + " <b>");
buffer.append(property.getName() + "</b> ");
// buffer.append("</dt><dd></dd></dl>");
return buffer.toString();
}
public static String getModifierListStr(JstModifiers jstModifiers) {
List<BaseJstNode> list = jstModifiers.getChildren();
if (list == null || list.isEmpty()) {
return "";
}
StringBuffer buffer = new StringBuffer();
Iterator<BaseJstNode> it = list.iterator();
while (it.hasNext()) {
BaseJstNode node = it.next();
buffer.append("");
}
return buffer.toString();
}
public static String getElementBriefDesc(IJstMethod method) {
StringBuffer buffer = new StringBuffer();
// buffer.append("<dl><dt>");
buffer.append(getModifierListStr(method.getModifiers()) + " "
+ method.getRtnType().getName() + " <b>");
buffer.append(method.getName() + "</b> ");
// buffer.append("</dt></dl>");
buffer.append("(" + combineParameters(method) + ")");
return buffer.toString();
}
/**
* @param method
* @return
*/
private static String combineParameters(IJstMethod method) {
String par = "";
if (method != null) {
List<JstArg> args = method.getArgs();
String comma = "";
int i = 0;
for (JstArg arg : args) {
if (i != 0) {
comma = ", ";
}
par += comma + arg.getType().getSimpleName() + " "
+ arg.getName();
i++;
}
}
return par;
}
/**
* Gets the reader content as a String
*/
private static String getString(Reader reader) {
StringBuffer buf = new StringBuffer();
char[] buffer = new char[1024];
int count;
try {
while ((count = reader.read(buffer)) != -1)
buf.append(buffer, 0, count);
} catch (IOException e) {
try {
reader.close();
} catch (IOException e1) {
}
return null;
}
try {
reader.close();
} catch (IOException e) {
}
return buf.toString();
}
@Override
public void apply(IDocument document, char trigger, int offset) {
super.apply(document, trigger, offset);
if (isTypeProposal()) {
VjoSourceType type = (VjoSourceType) getModelElement();
IJstType jstType = (IJstType) extraInfo;
MultiTextEdit edit = needsRewriter.rewrite(type, jstType);
applyNeeds(document, edit);
// super.apply(document);
}
}
private void applyNeeds(IDocument document, MultiTextEdit edit) {
int oldLen = document.getLength();
try {
edit.apply(document, TextEdit.UPDATE_REGIONS);
setReplacementOffset(getReplacementOffset() + document.getLength()
- oldLen);
} catch (Exception e) {
DLTKCore.error(e.getMessage(), e);
}
}
private boolean isTypeProposal() {
return getModelElement() instanceof VjoSourceType
&& extraInfo instanceof IJstType;
}
public void setExtraInfo(Object extraInfo) {
this.extraInfo = extraInfo;
}
}