diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 4daa746906a..498d91b9c10 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -78,6 +78,7 @@
+
diff --git a/idea/src/org/jetbrains/jet/plugin/JetPluginUtil.java b/idea/src/org/jetbrains/jet/plugin/JetPluginUtil.java
index ecd90784c69..dd7fae4c3f4 100644
--- a/idea/src/org/jetbrains/jet/plugin/JetPluginUtil.java
+++ b/idea/src/org/jetbrains/jet/plugin/JetPluginUtil.java
@@ -17,8 +17,14 @@
package org.jetbrains.jet.plugin;
import com.google.common.collect.Lists;
+import com.intellij.openapi.compiler.CompilerManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
@@ -77,4 +83,24 @@ public class JetPluginUtil {
}
return libraryScope == ((NamespaceDescriptor) declaration).getMemberScope();
}
+
+ @Nullable
+ public static Module getModuleForKotlinFile(@NotNull final VirtualFile file, @NotNull final Project project) {
+ if (file.getFileType() != JetFileType.INSTANCE) return null;
+ if (CompilerManager.getInstance(project).isExcludedFromCompilation(file)) return null;
+
+ final Module module = ModuleUtil.findModuleForFile(file, project);
+ if (module == null || isMavenModule(module)) return null;
+
+ return module;
+ }
+
+ private static boolean isMavenModule(@NotNull final Module module) {
+ for (final VirtualFile root : ModuleRootManager.getInstance(module).getContentRoots()) {
+ if (root.findChild("pom.xml") != null) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ConfigureKotlinLibraryNotificationProvider.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ConfigureKotlinLibraryNotificationProvider.java
index b5b1ab1fe9c..516a7f8a423 100644
--- a/idea/src/org/jetbrains/jet/plugin/quickfix/ConfigureKotlinLibraryNotificationProvider.java
+++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ConfigureKotlinLibraryNotificationProvider.java
@@ -20,13 +20,11 @@
package org.jetbrains.jet.plugin.quickfix;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.fileChooser.FileTextField;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
@@ -55,7 +53,7 @@ import com.intellij.ui.EditorNotificationPanel;
import com.intellij.ui.EditorNotifications;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.jet.plugin.JetFileType;
+import org.jetbrains.jet.plugin.JetPluginUtil;
import org.jetbrains.jet.utils.PathUtil;
import javax.swing.*;
@@ -83,15 +81,9 @@ public class ConfigureKotlinLibraryNotificationProvider implements EditorNotific
@Override
public EditorNotificationPanel createNotificationPanel(VirtualFile file) {
try {
- if (file.getFileType() != JetFileType.INSTANCE) return null;
-
- if (CompilerManager.getInstance(myProject).isExcludedFromCompilation(file)) return null;
-
- final Module module = ModuleUtil.findModuleForFile(file, myProject);
+ final Module module = JetPluginUtil.getModuleForKotlinFile(file, myProject);
if (module == null) return null;
- if (isMavenModule(module)) return null;
-
if (isJsModule(module)) return null;
GlobalSearchScope scope = module.getModuleWithDependenciesAndLibrariesScope(false);
@@ -251,14 +243,6 @@ public class ConfigureKotlinLibraryNotificationProvider implements EditorNotific
});
}
- private static boolean isMavenModule(@NotNull Module module) {
- for (VirtualFile root : ModuleRootManager.getInstance(module).getContentRoots()) {
- if (root.findChild("pom.xml") != null) return true;
- }
-
- return false;
- }
-
private static class ChoosePathDialog extends DialogWrapper {
private final Project myProject;
private TextFieldWithBrowseButton myPathField;
diff --git a/idea/src/org/jetbrains/jet/plugin/sdk/KotlinSdkNotConfiguredNotificationProvider.java b/idea/src/org/jetbrains/jet/plugin/sdk/KotlinSdkNotConfiguredNotificationProvider.java
new file mode 100644
index 00000000000..b04ac9280a6
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/sdk/KotlinSdkNotConfiguredNotificationProvider.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2010-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.jet.plugin.sdk;
+
+import com.intellij.ProjectTopics;
+import com.intellij.ide.util.frameworkSupport.AddFrameworkSupportDialog;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.project.IndexNotReadyException;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModuleRootEvent;
+import com.intellij.openapi.roots.ModuleRootListener;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.search.FilenameIndex;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.ui.EditorNotificationPanel;
+import com.intellij.ui.EditorNotifications;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.plugin.JetPluginUtil;
+
+import java.io.File;
+import java.util.Collection;
+
+/**
+ * @author Maxim.Manuylov
+ * Date: 19.05.12
+ */
+public class KotlinSdkNotConfiguredNotificationProvider implements EditorNotifications.Provider {
+ @NotNull private static final Key KEY = Key.create("configure.kotlin.sdk");
+
+ @NotNull private final Project myProject;
+
+ public KotlinSdkNotConfiguredNotificationProvider(@NotNull final Project project, @NotNull final EditorNotifications notifications) {
+ myProject = project;
+ project.getMessageBus().connect(project).subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() {
+ @Override
+ public void beforeRootsChange(final ModuleRootEvent event) {}
+
+ @Override
+ public void rootsChanged(final ModuleRootEvent event) {
+ notifications.updateAllNotifications();
+ }
+ });
+ }
+
+ @NotNull
+ @Override
+ public Key getKey() {
+ return KEY;
+ }
+
+ @Nullable
+ @Override
+ public EditorNotificationPanel createNotificationPanel(@NotNull final VirtualFile file) {
+ try {
+ final Module module = JetPluginUtil.getModuleForKotlinFile(file, myProject);
+ if (module == null) return null;
+
+ final GlobalSearchScope scope = module.getModuleWithDependenciesAndLibrariesScope(false);
+ if (!containsKotlinCompilerJar(FilenameIndex.getVirtualFilesByName(myProject, KotlinSdkUtil.KOTLIN_COMPILER_JAR, scope))) {
+ return createNotificationPanel(module);
+ }
+ }
+ catch (final ProcessCanceledException ignore) {}
+ catch (final IndexNotReadyException ignore) {}
+
+ return null;
+ }
+
+ private static boolean containsKotlinCompilerJar(@NotNull final Collection jars) {
+ for (final VirtualFile jar : jars) {
+ if (KotlinSdkUtil.isKotlinCompilerJar(new File(jar.getPath()))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @NotNull
+ private static EditorNotificationPanel createNotificationPanel(@NotNull final Module module) {
+ final EditorNotificationPanel panel = new EditorNotificationPanel();
+ panel.setText("Kotlin SDK is not configured for module \"" + module.getName() + "\"");
+ panel.createActionLabel("Configure Kotlin SDK", new Runnable() {
+ @Override
+ public void run() {
+ final AddFrameworkSupportDialog dialog = AddFrameworkSupportDialog.createDialog(module);
+ if (dialog != null) {
+ dialog.show();
+ }
+ }
+ });
+ return panel;
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/sdk/KotlinSdkUtil.java b/idea/src/org/jetbrains/jet/plugin/sdk/KotlinSdkUtil.java
index 897b016a0fc..6fb28a52980 100644
--- a/idea/src/org/jetbrains/jet/plugin/sdk/KotlinSdkUtil.java
+++ b/idea/src/org/jetbrains/jet/plugin/sdk/KotlinSdkUtil.java
@@ -25,6 +25,9 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
/**
* @author Maxim.Manuylov
@@ -39,7 +42,11 @@ public class KotlinSdkUtil {
return new KotlinSdkProperties("");
}
};
- @NotNull private static final String KOTLIN_COMPILER_JAR = "kotlin-compiler.jar";
+ @NotNull public static final String KOTLIN_COMPILER_JAR = "kotlin-compiler.jar";
+ @NotNull private static final String[] KOTLIN_COMPILER_JAR_ENTRY_NAMES = {
+ "org/jetbrains/jet/cli/KotlinCompiler.class",
+ "org/jetbrains/jet/cli/jvm/K2JVMCompiler.class"
+ };
private KotlinSdkUtil() {}
@@ -48,7 +55,7 @@ public class KotlinSdkUtil {
}
private static boolean isSDKHome(@NotNull final File dir) {
- return dir.isDirectory() && new File(new File(dir, "lib"), KOTLIN_COMPILER_JAR).isFile();
+ return dir.isDirectory() && isKotlinCompilerJar(getKotlinCompilerJar(dir));
}
@Nullable
@@ -57,14 +64,36 @@ public class KotlinSdkUtil {
return FileUtil.loadFile(new File(sdkHomePath, "build.txt")).trim();
}
catch (final IOException e) {
- return null;
+ try {
+ return getJarImplementationVersion(getKotlinCompilerJar(new File(sdkHomePath)));
+ }
+ catch (final IOException e1) {
+ return null;
+ }
}
}
+ @Nullable
+ private static String getJarImplementationVersion(@NotNull final File jar) throws IOException {
+ final JarFile jarFile = new JarFile(jar);
+ try {
+ final Manifest manifest = jarFile.getManifest();
+ return manifest == null ? null : manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+ }
+ finally {
+ jarFile.close();
+ }
+ }
+
+ @NotNull
+ private static File getKotlinCompilerJar(@NotNull final File sdkHome) {
+ return new File(new File(sdkHome, "lib"), KOTLIN_COMPILER_JAR);
+ }
+
@Nullable
public static String detectSDKVersion(@NotNull final List jars) {
for (final VirtualFile jar : jars) {
- if (jar.getName().equals(KOTLIN_COMPILER_JAR)) {
+ if (jar.getName().equals(KOTLIN_COMPILER_JAR) && isKotlinCompilerJar(new File(jar.getPath()))) {
final VirtualFile libDir = jar.getParent();
if (libDir != null) {
final VirtualFile sdkHomeDir = libDir.getParent();
@@ -77,6 +106,30 @@ public class KotlinSdkUtil {
return null;
}
+ public static boolean isKotlinCompilerJar(@NotNull final File jar) {
+ try {
+ return doIsKotlinCompilerJar(jar);
+ }
+ catch (final IOException e) {
+ return false;
+ }
+ }
+
+ private static boolean doIsKotlinCompilerJar(@NotNull final File jar) throws IOException {
+ final JarFile jarFile = new JarFile(jar);
+ try {
+ for (final String entryName : KOTLIN_COMPILER_JAR_ENTRY_NAMES) {
+ if (jarFile.getJarEntry(entryName) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+ finally {
+ jarFile.close();
+ }
+ }
+
@NotNull
public static String getSDKName(@NotNull final String version) {
return "Kotlin " + version;