mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-21 17:52:27 +07:00
324 lines
11 KiB
Java
324 lines
11 KiB
Java
package com.intellij.jarFinder;
|
|
|
|
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix;
|
|
import com.intellij.codeInsight.hint.HintManager;
|
|
import com.intellij.codeInsight.intention.IntentionAction;
|
|
import com.intellij.ide.util.PropertiesComponent;
|
|
import com.intellij.openapi.application.AccessToken;
|
|
import com.intellij.openapi.application.WriteAction;
|
|
import com.intellij.openapi.diagnostic.Logger;
|
|
import com.intellij.openapi.editor.Editor;
|
|
import com.intellij.openapi.fileChooser.FileChooser;
|
|
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
|
import com.intellij.openapi.module.Module;
|
|
import com.intellij.openapi.module.ModuleUtil;
|
|
import com.intellij.openapi.progress.ProgressIndicator;
|
|
import com.intellij.openapi.progress.ProgressManager;
|
|
import com.intellij.openapi.progress.Task;
|
|
import com.intellij.openapi.project.Project;
|
|
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
|
import com.intellij.openapi.util.Iconable;
|
|
import com.intellij.openapi.vfs.LocalFileSystem;
|
|
import com.intellij.openapi.vfs.VirtualFile;
|
|
import com.intellij.psi.CommonClassNames;
|
|
import com.intellij.psi.JavaPsiFacade;
|
|
import com.intellij.psi.PsiElement;
|
|
import com.intellij.psi.PsiFile;
|
|
import com.intellij.psi.search.GlobalSearchScope;
|
|
import com.intellij.ui.components.JBList;
|
|
import com.intellij.util.IncorrectOperationException;
|
|
import com.intellij.util.NotNullFunction;
|
|
import com.intellij.util.PlatformIcons;
|
|
import com.intellij.util.download.DownloadableFileDescription;
|
|
import com.intellij.util.download.DownloadableFileService;
|
|
import org.cyberneko.html.parsers.DOMParser;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.w3c.dom.Document;
|
|
import org.w3c.dom.NamedNodeMap;
|
|
import org.w3c.dom.Node;
|
|
import org.w3c.dom.NodeList;
|
|
import org.xml.sax.SAXException;
|
|
|
|
import javax.swing.*;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.*;
|
|
|
|
/**
|
|
* @author Konstantin Bulenkov
|
|
*/
|
|
public abstract class FindJarFix<T extends PsiElement> implements IntentionAction, Iconable {
|
|
|
|
private static final Logger LOG = Logger.getInstance(FindJarFix.class);
|
|
|
|
private static final String CLASS_ROOT_URL = "http://findjar.com/class/";
|
|
private static final String CLASS_PAGE_EXT = ".html";
|
|
private static final String SERVICE_URL = "http://findjar.com";
|
|
private static final String LINK_TAG_NAME = "a";
|
|
private static final String LINK_ATTR_NAME = "href";
|
|
|
|
protected final T myRef;
|
|
protected final Module myModule;
|
|
protected JComponent myEditorComponent;
|
|
|
|
public FindJarFix(T ref) {
|
|
myRef = ref;
|
|
myModule = ModuleUtil.findModuleForPsiElement(ref);
|
|
}
|
|
|
|
@NotNull
|
|
@Override
|
|
public String getText() {
|
|
return "Find jar on web";
|
|
}
|
|
|
|
@NotNull
|
|
@Override
|
|
public String getFamilyName() {
|
|
return "Family name";
|
|
}
|
|
|
|
@Override
|
|
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
|
return myRef.isValid()
|
|
&& JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_OBJECT, file.getResolveScope()) != null
|
|
&& myModule != null
|
|
&& isFqnsOk(project, getPossibleFqns(myRef));
|
|
}
|
|
|
|
private static boolean isFqnsOk(Project project, List<String> fqns) {
|
|
if (fqns.isEmpty()) return false;
|
|
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
|
|
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
|
|
for (String fqn : fqns) {
|
|
if (facade.findClass(fqn, scope) != null) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void invoke(@NotNull Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
|
|
final List<String> fqns = getPossibleFqns(myRef);
|
|
myEditorComponent = editor.getComponent();
|
|
if (fqns.size() > 1) {
|
|
final JBList listOfFqns = new JBList(fqns);
|
|
JBPopupFactory.getInstance()
|
|
.createListPopupBuilder(listOfFqns)
|
|
.setTitle("Select Qualified Name")
|
|
.setItemChoosenCallback(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
final Object value = listOfFqns.getSelectedValue();
|
|
if (value instanceof String) {
|
|
findJarsForFqn(((String)value), editor);
|
|
}
|
|
}
|
|
}).createPopup().showInBestPositionFor(editor);
|
|
}
|
|
else if (fqns.size() == 1) {
|
|
findJarsForFqn(fqns.get(0), editor);
|
|
}
|
|
}
|
|
|
|
private void findJarsForFqn(final String fqn, final Editor editor) {
|
|
final Map<String, String> libs = new HashMap<String, String>();
|
|
|
|
final Runnable runnable = new Runnable() {
|
|
public void run() {
|
|
try {
|
|
final DOMParser parser = new DOMParser();
|
|
parser.parse(CLASS_ROOT_URL + fqn.replace('.', '/') + CLASS_PAGE_EXT);
|
|
final Document doc = parser.getDocument();
|
|
if (doc != null) {
|
|
final NodeList links = doc.getElementsByTagName(LINK_TAG_NAME);
|
|
for (int i = 0; i < links.getLength(); i++) {
|
|
final Node link = links.item(i);
|
|
final String libName = link.getTextContent();
|
|
final NamedNodeMap attributes = link.getAttributes();
|
|
if (attributes != null) {
|
|
final Node href = attributes.getNamedItem(LINK_ATTR_NAME);
|
|
if (href != null) {
|
|
final String pathToJar = href.getTextContent();
|
|
if (pathToJar != null && (pathToJar.startsWith("/jar/") || pathToJar.startsWith("/class/../"))) {
|
|
libs.put(libName, SERVICE_URL + pathToJar);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (IOException ignore) {//
|
|
}
|
|
catch (Exception e) {//
|
|
LOG.warn(e);
|
|
}
|
|
}
|
|
};
|
|
|
|
final Task.Modal task = new Task.Modal(editor.getProject(), "Looking for libraries", true) {
|
|
@Override
|
|
public void run(@NotNull ProgressIndicator indicator) {
|
|
indicator.setIndeterminate(true);
|
|
runUncanceledRunnableWithProgress(runnable, indicator);
|
|
}
|
|
|
|
@Override
|
|
public void onSuccess() {
|
|
super.onSuccess();
|
|
if (libs.isEmpty()) {
|
|
HintManager.getInstance().showInformationHint(editor, "No libraries found for '" + fqn + "'");
|
|
} else {
|
|
final ArrayList<String> variants = new ArrayList<String>(libs.keySet());
|
|
Collections.sort(variants, new Comparator<String>() {
|
|
@Override
|
|
public int compare(String o1, String o2) {
|
|
return o1.compareTo(o2);
|
|
}
|
|
});
|
|
final JBList libNames = new JBList(variants);
|
|
libNames.installCellRenderer(new NotNullFunction<Object, JComponent>() {
|
|
@NotNull
|
|
@Override
|
|
public JComponent fun(Object o) {
|
|
return new JLabel(o.toString(), PlatformIcons.JAR_ICON, SwingConstants.LEFT);
|
|
}
|
|
});
|
|
if (libs.size() == 1) {
|
|
final String jarName = libs.keySet().iterator().next();
|
|
final String url = libs.get(jarName);
|
|
initiateDownload(url, jarName);
|
|
} else {
|
|
JBPopupFactory.getInstance()
|
|
.createListPopupBuilder(libNames)
|
|
.setTitle("Select a jar file")
|
|
.setItemChoosenCallback(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
final Object value = libNames.getSelectedValue();
|
|
if (value instanceof String) {
|
|
final String jarName = (String)value;
|
|
final String url = libs.get(jarName);
|
|
if (url != null) {
|
|
initiateDownload(url, jarName);
|
|
}
|
|
}
|
|
}
|
|
})
|
|
.createPopup().showInBestPositionFor(editor);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
ProgressManager.getInstance().run(task);
|
|
}
|
|
|
|
private void initiateDownload(String url, String jarName) {
|
|
DOMParser parser = new DOMParser();
|
|
try {
|
|
parser.parse(url);
|
|
final Document doc = parser.getDocument();
|
|
if (doc != null) {
|
|
final NodeList links = doc.getElementsByTagName(LINK_TAG_NAME);
|
|
if (links != null) {
|
|
for (int i = 0; i < links.getLength(); i++) {
|
|
final Node item = links.item(i);
|
|
if (item != null) {
|
|
final NamedNodeMap attributes = item.getAttributes();
|
|
if (attributes != null) {
|
|
final Node link = attributes.getNamedItem(LINK_ATTR_NAME);
|
|
if (link != null) {
|
|
final String jarUrl = link.getTextContent();
|
|
if (jarUrl != null && jarUrl.endsWith(jarName)) {
|
|
downloadJar(jarUrl, jarName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (SAXException e) {//
|
|
}
|
|
catch (IOException e) {//
|
|
}
|
|
}
|
|
|
|
private static void runUncanceledRunnableWithProgress(Runnable run, ProgressIndicator indicator) {
|
|
Thread t = new Thread(run, "FindJar download thread");
|
|
t.setDaemon(true);
|
|
t.start();
|
|
|
|
try {
|
|
while (t.isAlive()) {
|
|
t.join(500);
|
|
indicator.checkCanceled();
|
|
}
|
|
}
|
|
catch (InterruptedException e) {
|
|
indicator.checkCanceled();
|
|
}
|
|
}
|
|
|
|
private void downloadJar(String jarUrl, String jarName) {
|
|
final Project project = myModule.getProject();
|
|
final String dirPath = PropertiesComponent.getInstance(project).getValue("findjar.last.used.dir");
|
|
VirtualFile toSelect = dirPath == null ? null : LocalFileSystem.getInstance().findFileByIoFile(new File(dirPath));
|
|
final VirtualFile file = FileChooser.chooseFile(FileChooserDescriptorFactory.createSingleFolderDescriptor(), project, toSelect);
|
|
if (file != null) {
|
|
PropertiesComponent.getInstance(project).setValue("findjar.last.used.dir", file.getPath());
|
|
final DownloadableFileService downloader = DownloadableFileService.getInstance();
|
|
final DownloadableFileDescription description = downloader.createFileDescription(jarUrl, jarName);
|
|
final List<VirtualFile> jars =
|
|
downloader.createDownloader(Arrays.asList(description), jarName)
|
|
.downloadFilesWithProgress(file.getPath(), project, myEditorComponent);
|
|
if (jars != null && jars.size() == 1) {
|
|
AccessToken token = WriteAction.start();
|
|
try {
|
|
OrderEntryFix.addJarToRoots(jars.get(0).getPresentableUrl(), myModule, myRef);
|
|
}
|
|
finally {
|
|
token.finish();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected abstract Collection<String> getFqns(@NotNull T ref);
|
|
|
|
protected List<String> getPossibleFqns(T ref) {
|
|
Collection<String> fqns = getFqns(ref);
|
|
|
|
List<String> res = new ArrayList<String>(fqns.size());
|
|
|
|
for (String fqn : fqns) {
|
|
if (fqn.startsWith("java.") || fqn.startsWith("javax.swing.")) {
|
|
continue;
|
|
}
|
|
final int index = fqn.lastIndexOf('.');
|
|
if (index == -1) {
|
|
continue;
|
|
}
|
|
final String className = fqn.substring(index + 1);
|
|
if (className.length() == 0 || Character.isLowerCase(className.charAt(0))) {
|
|
continue;
|
|
}
|
|
|
|
res.add(fqn);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
@Override
|
|
public boolean startInWriteAction() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public Icon getIcon(int flags) {
|
|
return PlatformIcons.WEB_ICON;
|
|
}
|
|
}
|