diff --git a/java/java-features-trainer/resources/messages/JavaLessonsBundle.properties b/java/java-features-trainer/resources/messages/JavaLessonsBundle.properties
index 8421eb79e92a..3ae7022c0bb0 100644
--- a/java/java-features-trainer/resources/messages/JavaLessonsBundle.properties
+++ b/java/java-features-trainer/resources/messages/JavaLessonsBundle.properties
@@ -1,6 +1,13 @@
#Need to translate in pair with action.EditorToggleCase.text key!
toggle.case.part=case
+java.missed.sdk.click.setup= cannot find JDK on your computer. The IDE needs JDK to run Java programs and provide code assistance to you. \
+ To configure JDK, click the highlighted {0} link.
+java.missed.sdk.show.options=Click to see available options
+java.missed.sdk.read.more.tip=Tip: you can read more about JDK in the documentation.
+java.missed.sdk.configure=Configure JDK by using one of the suggested options. You can download it or specify a path to the existing JDK home directory on your computer.
+java.missed.sdk.wait.installation=Please wait while the IDE installs JDK
+
java.onboarding.module.name=Onboarding tour
java.onboarding.module.description=A brief overview of the main features in {0}.
diff --git a/java/java-features-trainer/src/com/intellij/java/ift/JavaLangSupport.kt b/java/java-features-trainer/src/com/intellij/java/ift/JavaLangSupport.kt
index eaba8bbd3a32..f1beda9ee47a 100644
--- a/java/java-features-trainer/src/com/intellij/java/ift/JavaLangSupport.kt
+++ b/java/java-features-trainer/src/com/intellij/java/ift/JavaLangSupport.kt
@@ -1,8 +1,28 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.ift
+import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.progress.util.AbstractProgressIndicatorExBase
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.project.ProjectBundle
+import com.intellij.openapi.roots.OrderRootType
+import com.intellij.openapi.roots.ProjectRootManager
+import com.intellij.openapi.roots.ui.configuration.JdkComboBox
+import com.intellij.openapi.roots.ui.configuration.SdkListItem
+import com.intellij.openapi.roots.ui.configuration.projectRoot.SdkDownloadTracker
+import com.intellij.openapi.ui.popup.Balloon
+import com.intellij.ui.HyperlinkLabel
+import com.intellij.ui.components.panels.NonOpaquePanel
+import training.dsl.LearningBalloonConfig
+import training.dsl.LessonContext
+import training.dsl.LessonUtil
+import training.learn.course.KLesson
import training.project.ReadMeCreator
+import training.ui.LearningUiHighlightingManager
+import training.ui.LearningUiHighlightingManager.HighlightingOptions
+import training.ui.LearningUiUtil
import training.util.getFeedbackLink
+import javax.swing.JList
internal class JavaLangSupport : JavaBasedLangSupport() {
override val contentRootDirectoryName = "IdeaLearningProject"
@@ -20,4 +40,75 @@ internal class JavaLangSupport : JavaBasedLangSupport() {
get() = getFeedbackLink(this, false)
override val readMeCreator by lazy { ReadMeCreator() }
+
+ override val sdkConfigurationTasks: LessonContext.(lesson: KLesson) -> Unit = {
+ val setupSdkText = ProjectBundle.message("project.sdk.setup")
+
+ fun isJdkInstalled(project: Project) = JavaProjectUtil.getProjectJdk(project) != null
+
+ task {
+ if (isJdkInstalled(project)) return@task
+ triggerAndFullHighlight { usePulsation = true }.component { ui: HyperlinkLabel ->
+ ui.text == setupSdkText
+ }
+ }
+
+ task {
+ if (isJdkInstalled(project)) return@task
+
+ rehighlightPreviousUi = true
+ text(JavaLessonsBundle.message("java.missed.sdk.click.setup", strong(setupSdkText)))
+ text(JavaLessonsBundle.message("java.missed.sdk.show.options"), LearningBalloonConfig(Balloon.Position.below, 0))
+ text(JavaLessonsBundle.message("java.missed.sdk.read.more.tip", LessonUtil.getHelpLink("sdk.html#jdk")))
+ triggerAndBorderHighlight().component { list: JList<*> ->
+ val model = list.model
+ (0 until model.size).any {
+ model.getElementAt(it).let { item -> item is SdkListItem || item is JdkComboBox.JdkComboBoxItem }
+ }
+ }
+ }
+
+ task {
+ if (isJdkInstalled(project)) return@task
+
+ rehighlightPreviousUi = true
+ text(JavaLessonsBundle.message("java.missed.sdk.configure"))
+ var progressHighlightingStarted = false
+ var downloadingListenerAdded = false
+ timerCheck {
+ val jdk = JavaProjectUtil.getProjectJdk(project)
+
+ if (jdk != null && !progressHighlightingStarted) {
+ progressHighlightingStarted = true
+ invokeInBackground {
+ LearningUiUtil.findComponentOrNull(project, NonOpaquePanel::class.java) { panel ->
+ panel.javaClass.name.contains("InlineProgressPanel")
+ }?.let { panel ->
+ taskInvokeLater {
+ if (!disposed) {
+ LearningUiHighlightingManager.highlightComponent(panel, HighlightingOptions(highlightInside = false))
+ this@task.text(JavaLessonsBundle.message("java.missed.sdk.wait.installation"),
+ LearningBalloonConfig(Balloon.Position.above, width = 0, highlightingComponent = panel))
+ }
+ }
+ }
+ }
+ }
+
+ if (jdk != null && !downloadingListenerAdded) {
+ downloadingListenerAdded = SdkDownloadTracker.getInstance().tryRegisterDownloadingListener(jdk, taskDisposable,
+ AbstractProgressIndicatorExBase()) {
+ // todo: For some reason after the downloading JDK is not fully applied, imports are still red.
+ // So we need to trigger the indexing by setting the same JDK that already set just to call listeners of JDK update.
+ // Remove this hack when IDEA-244649 will be fixed.
+ runWriteAction {
+ ProjectRootManager.getInstance(project).projectSdk = JavaProjectUtil.getProjectJdk(project)
+ }
+ }
+ }
+
+ jdk != null && jdk.rootProvider.getFiles(OrderRootType.CLASSES).isNotEmpty()
+ }
+ }
+ }
}
diff --git a/java/java-features-trainer/src/com/intellij/java/ift/JavaProjectUtil.kt b/java/java-features-trainer/src/com/intellij/java/ift/JavaProjectUtil.kt
index 5a3a0025ea88..8889495d7b6d 100644
--- a/java/java-features-trainer/src/com/intellij/java/ift/JavaProjectUtil.kt
+++ b/java/java-features-trainer/src/com/intellij/java/ift/JavaProjectUtil.kt
@@ -1,9 +1,7 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.ift
-import com.intellij.openapi.application.invokeAndWaitIfNeeded
import com.intellij.openapi.module.ModuleManager
-import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.Sdk
@@ -11,43 +9,24 @@ import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.roots.ui.configuration.SdkLookup
import com.intellij.openapi.roots.ui.configuration.SdkLookupDecision
-import com.intellij.openapi.ui.Messages
import com.intellij.util.lang.JavaVersion
-import training.learn.LearnBundle
-import training.project.ProjectUtils
object JavaProjectUtil {
fun findJavaSdkAsync(project: Project, onSdkSearchCompleted: (Sdk?) -> Unit) {
val javaSdkType = JavaSdk.getInstance()
- val notification = ProjectUtils.createSdkDownloadingNotification()
SdkLookup.newLookupBuilder()
+ .withProject(project)
.withSdkType(javaSdkType)
.withVersionFilter {
JavaVersion.tryParse(it)?.isAtLeast(6) == true
}
- .onDownloadableSdkSuggested { sdkFix ->
- val userDecision = invokeAndWaitIfNeeded {
- Messages.showYesNoDialog(
- LearnBundle.message("learn.project.initializing.jdk.download.message", sdkFix.downloadDescription),
- LearnBundle.message("learn.project.initializing.jdk.download.title"),
- null
- )
- }
- if (userDecision == Messages.YES) {
- notification.notify(project)
- SdkLookupDecision.CONTINUE
- }
- else {
- onSdkSearchCompleted(null)
- SdkLookupDecision.STOP
- }
+ .onDownloadableSdkSuggested {
+ onSdkSearchCompleted(null)
+ SdkLookupDecision.STOP
}
.onSdkResolved { sdk ->
if (sdk != null && sdk.sdkType === javaSdkType) {
onSdkSearchCompleted(sdk)
- DumbService.getInstance(project).runWhenSmart {
- notification.expire()
- }
}
}
.executeLookup()
diff --git a/java/java-features-trainer/src/com/intellij/java/ift/lesson/essential/JavaOnboardingTourLesson.kt b/java/java-features-trainer/src/com/intellij/java/ift/lesson/essential/JavaOnboardingTourLesson.kt
index 2c8af73d7845..14c9a69c79fb 100644
--- a/java/java-features-trainer/src/com/intellij/java/ift/lesson/essential/JavaOnboardingTourLesson.kt
+++ b/java/java-features-trainer/src/com/intellij/java/ift/lesson/essential/JavaOnboardingTourLesson.kt
@@ -146,10 +146,12 @@ class JavaOnboardingTourLesson : KLesson("java.onboarding", JavaLessonsBundle.me
projectTasks()
- prepareSample(sample)
+ prepareSample(sample, checkSdkConfiguration = false)
openLearnToolwindow()
+ sdkConfigurationTasks()
+
waitIndexingTasks()
runTasks()
@@ -244,12 +246,13 @@ class JavaOnboardingTourLesson : KLesson("java.onboarding", JavaLessonsBundle.me
}
val currentJdk = JavaProjectUtil.getProjectJdk(project)
- val currentJdkVersion: @NlsSafe String = if (currentJdk != null) {
- JavaSdk.getInstance().getVersionString(currentJdk) ?: "none"
- }
- else "none"
+
+ @Suppress("HardCodedStringLiteral")
+ val currentJdkVersion: @NlsSafe String = currentJdk?.let { JavaSdk.getInstance().getVersionString(it) } ?: "none"
val module = ModuleManager.getInstance(project).modules.first()
+
+ @Suppress("HardCodedStringLiteral")
val currentLanguageLevel: @NlsSafe String = LanguageLevelUtil.getEffectiveLanguageLevel(module).name
primaryLanguage.onboardingFeedbackData = object : OnboardingFeedbackData("IDEA Onboarding Tour Feedback", lessonEndInfo) {
diff --git a/plugins/ide-features-trainer/res/messages/LearnBundle.properties b/plugins/ide-features-trainer/res/messages/LearnBundle.properties
index 6d16a8ba9369..eb5b3434c7d8 100755
--- a/plugins/ide-features-trainer/res/messages/LearnBundle.properties
+++ b/plugins/ide-features-trainer/res/messages/LearnBundle.properties
@@ -13,11 +13,6 @@ dialog.askToSwitchToLearnProject.message=This lesson/module should be open
Switch to the {0} project manually and start this lesson again.
learn.project.initializing.process=Prepare a Learning Project
-learn.project.initializing.jdk.download.title=JDK Not Found
-learn.project.initializing.jdk.download.message=Cannot find any installed JDK. Download and install {0}?
-learn.project.initializing.jdk.download.notification.title=Project initialization
-learn.project.initializing.jdk.download.notification.message={0} is downloading and configuring a project SDK. \
- The lesson will begin after the project initialization is completed.
learn.project.initializing.choose.place=Choose a Parent Directory for {0}
learn.project.initializing.cannot.create.message=Cannot create a learning demo project. See the LOG files for more details.
diff --git a/plugins/ide-features-trainer/src/training/dsl/TaskRuntimeContext.kt b/plugins/ide-features-trainer/src/training/dsl/TaskRuntimeContext.kt
index 040525d62535..e88ea9f36721 100644
--- a/plugins/ide-features-trainer/src/training/dsl/TaskRuntimeContext.kt
+++ b/plugins/ide-features-trainer/src/training/dsl/TaskRuntimeContext.kt
@@ -34,6 +34,7 @@ open class TaskRuntimeContext internal constructor(private val lessonExecutor: L
: this(base.lessonExecutor, base.actionsRecorder, base.restorePreviousTaskCallback, base.previousGetter)
val taskDisposable: Disposable = actionsRecorder
+ val disposed: Boolean get() = actionsRecorder.disposed
val editor: Editor get() = lessonExecutor.editor
val project: Project get() = lessonExecutor.project
diff --git a/plugins/ide-features-trainer/src/training/project/ProjectUtils.kt b/plugins/ide-features-trainer/src/training/project/ProjectUtils.kt
index 33c3d21679b7..642e8547f592 100644
--- a/plugins/ide-features-trainer/src/training/project/ProjectUtils.kt
+++ b/plugins/ide-features-trainer/src/training/project/ProjectUtils.kt
@@ -8,8 +8,6 @@ import com.intellij.ide.ReopenProjectAction
import com.intellij.ide.impl.OpenProjectTask
import com.intellij.ide.impl.TrustedPaths
import com.intellij.ide.util.PropertiesComponent
-import com.intellij.notification.Notification
-import com.intellij.notification.NotificationType
import com.intellij.openapi.application.*
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.fileChooser.FileChooserDescriptor
@@ -32,7 +30,6 @@ import training.lang.LangManager
import training.lang.LangSupport
import training.learn.LearnBundle
import training.util.featureTrainerVersion
-import training.util.iftNotificationGroup
import java.io.File
import java.io.FileFilter
import java.io.IOException
@@ -286,13 +283,6 @@ object ProjectUtils {
}
}
- fun createSdkDownloadingNotification(): Notification {
- return iftNotificationGroup.createNotification(LearnBundle.message("learn.project.initializing.jdk.download.notification.title"),
- LearnBundle.message("learn.project.initializing.jdk.download.notification.message",
- ApplicationNamesInfo.getInstance().fullProductName),
- NotificationType.INFORMATION)
- }
-
fun closeAllEditorsInProject(project: Project) {
FileEditorManagerEx.getInstanceEx(project).windows.forEach {
it.files.forEach { file -> it.closeFile(file) }