[IFT] Java support extracted to its own module

GitOrigin-RevId: 71509fe1bb277185f98ac22029d58f946f774b13
This commit is contained in:
Alexey Merkulov
2020-11-05 23:45:06 +03:00
committed by intellij-monorepo-bot
parent 772df076b6
commit 7bc5561808
54 changed files with 1966 additions and 1 deletions

1
.idea/modules.xml generated
View File

@@ -534,6 +534,7 @@
<module fileurl="file://$PROJECT_DIR$/plugins/java-decompiler/engine/intellij.java.decompiler.engine.iml" filepath="$PROJECT_DIR$/plugins/java-decompiler/engine/intellij.java.decompiler.engine.iml" />
<module fileurl="file://$PROJECT_DIR$/java/execution/openapi/intellij.java.execution.iml" filepath="$PROJECT_DIR$/java/execution/openapi/intellij.java.execution.iml" />
<module fileurl="file://$PROJECT_DIR$/java/execution/impl/intellij.java.execution.impl.iml" filepath="$PROJECT_DIR$/java/execution/impl/intellij.java.execution.impl.iml" />
<module fileurl="file://$PROJECT_DIR$/java/java-features-trainer/intellij.java.featuresTrainer.iml" filepath="$PROJECT_DIR$/java/java-features-trainer/intellij.java.featuresTrainer.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/google-app-engine/intellij.java.googleAppEngine.iml" filepath="$PROJECT_DIR$/plugins/google-app-engine/intellij.java.googleAppEngine.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/google-app-engine/jps-plugin/intellij.java.googleAppEngine.jps.iml" filepath="$PROJECT_DIR$/plugins/google-app-engine/jps-plugin/intellij.java.googleAppEngine.jps.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/google-app-engine/runtime/intellij.java.googleAppEngine.runtime.iml" filepath="$PROJECT_DIR$/plugins/google-app-engine/runtime/intellij.java.googleAppEngine.runtime.iml" />

View File

@@ -77,6 +77,7 @@ abstract class BaseIdeaProperties extends JetBrainsProductProperties {
"intellij.markdown",
"intellij.webp",
"intellij.grazie",
"intellij.featuresTrainer",
]
protected static final Map<String, String> CE_CLASS_VERSIONS = [
"" : "11",

View File

@@ -150,5 +150,6 @@
<orderEntry type="module" module-name="intellij.externalSystem.dependencyUpdater.tests" scope="TEST" />
<orderEntry type="module" module-name="intellij.gradle.dependencyUpdater" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.settingsRepository.tests" scope="TEST" />
<orderEntry type="module" module-name="intellij.java.featuresTrainer" scope="RUNTIME"/>
</component>
</module>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-stdlib-jdk8" level="project" />
<orderEntry type="module" module-name="intellij.java" />
<orderEntry type="module" module-name="intellij.java.impl" />
<orderEntry type="module" module-name="intellij.java.ui" />
<orderEntry type="module" module-name="intellij.featuresTrainer" />
<orderEntry type="module" module-name="intellij.platform.ide.impl" />
<orderEntry type="module" module-name="intellij.platform.debugger" />
<orderEntry type="module" module-name="intellij.platform.testGuiFramework" />
</component>
</module>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<idea-plugin>
<extensions defaultExtensionNs="training">
<ift.language.extension language="JAVA" implementationClass="com.intellij.java.ift.JavaLangSupport"/>
<ift.learning.course language="JAVA" implementationClass="com.intellij.java.ift.JavaLearningCourse"/>
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,19 @@
import java.util.List;
import java.util.Set;
import java.util.ArrayList;
class CodeFormatDemo{
final static int a_const = 10000;
final static int b_const = 500;
<select>public static void calc(){InnerCalc.process(a_const, b_const); }</select>
static class InnerCalc{
final static int some_const = 124136; public static int process(int a, int b){ return a * b + some_const;
}
}
}

View File

@@ -0,0 +1,23 @@
<caret>import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
class CodeAssistance {
public static final String EXT = "txt";
public static void main(String[] args) throws FileNotFoundException {
FileReader fileReader = new FileReader("input." + EXT);
BufferedReader reader = new BufferedReader(fileReader);
ArrayList<String> lines = new ArrayList<String>();
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
String[] array = lines.toArray(new String[lines.size()]);
Arrays.sort(array);
for (String s : array) System.out.println(s);
}
}

View File

@@ -0,0 +1,12 @@
import javax.swing.*;
class FrameDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("FrameDemo");
frame.setSize(<caret>);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

View File

@@ -0,0 +1,19 @@
import java.text.*;
class DecimalFormatDemo {
static public void main(String[] args) {
<caret>customFormat("###,###.###", 123456.789);
customFormat("###.##", 123456.789);
customFormat("000000.000", 123.78);
customFormat("$###,###.###", 12345.67);
}
/**
* Prints a double value formatted according to a given pattern.
*/
static public void customFormat(String pattern, double value) {
DecimalFormat myFormatter = new DecimalFormat(pattern);
String output = myFormatter.format(value);
System.out.println(value + " " + pattern + " " + output);
}
}

View File

@@ -0,0 +1,5 @@
class ActionsDemo {
public static void main(String[] args) {
System.out.println("Hello <caret>IDEA!");
}
}

View File

@@ -0,0 +1,19 @@
class SelectionDemo {
public int fib(int n) {
int a = 1;
int b = 1;
int tmp;
<caret>if (n < 2) return 1;
for (int i = 0; i < (n - 1); i++) {
tmp = b;
b = a;
a = a + tmp;
}
return a;
}
}

View File

@@ -0,0 +1,16 @@
import java.awt.Color;
class CommentDemo {
public static void main() {
float hue = 5;
float saturation = 10;
float brightness = 10;
int rgb = Color.HSBtoRGB(hue, saturation, brightness);
<caret>int red = (rgb >> 16) &0xFF;
int green = (rgb >> 8) &0xFF;
int blue = rgb &0xFF;
}
}

View File

@@ -0,0 +1,5 @@
class DuplicateDemo {
public static void main(String[] args){
<caret>System.out.println("Hello world!");
}
}

View File

@@ -0,0 +1,17 @@
class MoveDemo extends Thread {
boolean started = false;
private void printDebugMessage() {
System.out.println("Hello from a thread!");
}
public void run() {
<caret>started = true;
printDebugMessage();
}
public static void main(String args[]) {
(new MoveDemo()).start();
}
}

View File

@@ -0,0 +1,45 @@
import java.lang.Exception;
import java.lang.String;
class CollapseDemo{
String model;
Engine myEngine;
Wheel myWheel;
float fuelTank;
int passengerCapacity;
public<caret> CollapseDemo(String model, Engine engine, Wheel wheel){
this.model = model;
Engine myEngine = engine;
Wheel myWheel = wheel;
passengerCapacity = 4;
}
public void startEngine() throws CheckEngineException{
myEngine.callStarter();
}
public void rotateWheel(float angle){
if (angle > 0) {
myWheel.rotateClockwise(Math.abs(angle));
} else {
myWheel.rotateCounterClockwise(Math.abs(angle));
}
}
interface Engine{
void callStarter();
}
interface Wheel{
void rotateClockwise(float angle);
void rotateCounterClockwise(float angle);
}
class CheckEngineException extends Exception{
}
}

View File

@@ -0,0 +1,12 @@
class Demo {
public static void bubbleSort(int[] array) {
int length = array.length;
for (int j = 0; j < length - 1; j++)
for (int i = 0; i < length - j - 1; i++)
if (array[i] > array[<select>i + 1</select>]) {
int temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
}
}

View File

@@ -0,0 +1,45 @@
import java.io.InputStream;
import java.util.List;
class BufferedReader {
private InputStream inputStream;
private int maxBufferSize = 1024;
private byte[] buffer;
public BufferedReader(InputStream inputStream) {
this.inputStream = inputStream;
}
public BufferedReader(InputStream inputStream, int maxBufferSize) {
this.inputStream = inputStream;
this.maxBufferSize = maxBufferSize;
}
/**
* @return one byte from input stream
*/
public byte read() {
throw new IllegalStateException("Not implemented yet");
}
/**
* @return n bytes from input stream
*/
public byte[] read(int n) {
throw new IllegalStateException("Not implemented yet");
}
/**
* @return one line from input stream as String
*/
public String readLine() {
throw new IllegalStateException("Not implemented yet");
}
/**
* @return all lines from input stream as List of Strings
*/
public List<String> lines() {
throw new IllegalStateException("Not implemented yet");
}
}

View File

@@ -0,0 +1,19 @@
public class DerivedClass1 implements SomeInterface {
@Override
public void foo(FileStructureDemo demo) {
demo.boo();
}
}
class SecondLevelClassA extends DerivedClass1 {
@Override
public void foo(FileStructureDemo demo) {
demo.foo();
}
}
class SecondLevelClassB extends DerivedClass1 {
}

View File

@@ -0,0 +1,7 @@
public class DerivedClass2 implements SomeInterface {
@Override
public void foo(FileStructureDemo demo) {
demo.foo();
}
}

View File

@@ -0,0 +1,227 @@
public class FileStructureDemo {
public void helloWorld() {
System.out.println("Hello world!");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void welcome() {
System.out.println("JetBrains is aiming to create the best IDEs in the world!");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void printHippogryph() {
System.out.println("Hippogryph! Just another method to illustrate fast file structure search :)");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void hospitalInformation() {
System.out.println("Just another method to illustrate fast file structure search :)");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void printHomeDesign() {
System.out.println("Just another method to illustrate fast file structure search :)");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void printHomoNeanderthalensis() {
System.out.println("Homo Neanderthalensis is a parallel evolution branch of humans.");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void printHomoSapiens() {
System.out.println("Homo Sapiens is a biological name of modern humans.");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void printHomoErectus() {
System.out.println("Homo Erectus is most likely the ancestor of modern humans.");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void printSapphire() {
System.out.println("Just another method to illustrate fast file structure search :)");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void phoneDescription() {
System.out.println("Just another method to illustrate fast file structure search :)");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void foo() {
System.out.println("Just another method to illustrate fast file structure search :)");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void boo() {
System.out.println("Just another method to illustrate fast file structure search :)");
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
// A lot of code can be inside methods :)
}
public void animal() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void parrot() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void plain() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void air() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void aim() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void book() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void bank() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void boring() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void car() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void cancel() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void zoo() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void zero() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void first() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void second() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void direction() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void director() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public static class Internal {
public void anotherMethod1() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void anotherMethod2() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
public void homoHistory() {
System.out.println("Just another method to illustrate fast file structure search :)");
}
}
}

View File

@@ -0,0 +1,6 @@
public class InheritanceHierarchySample {
public static void someEntryPoint(SomeInterface base, FileStructureDemo demo) {
base.foo(demo);
}
}

View File

@@ -0,0 +1,19 @@
class QuadraticEquationsSolver {
public double discriminant(double a, double b, double c) {
return b * b - 4 * a * c;
}
public void solve(double a, double b, double c) {
double d = discriminant(a, b, c);
if(d < 0) {
System.out.println("No roots");
} else if(d > 0) {
double x1 = (-b + Math.sqrt(d)) / (2.0 * a);
double x2 = (-b - Math.sqrt(d)) / (2.0 * a);
System.out.println("x1 = " + x1 + ", x2 = " + x2);
} else {
System.out.println("x = " + ((-b) / (2.0 * a)));
}
}
}

View File

@@ -0,0 +1,5 @@
public class RecentFilesDemo {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

View File

@@ -0,0 +1,8 @@
interface SomeInterface {
void foo(FileStructureDemo demo);
}
interface SomeDerivedInterface extends SomeInterface {
}

View File

@@ -0,0 +1,74 @@
java.surround.and.unwrap.help.unwrapping.and.removing.statements=Working with code statements
java.basic.completion.choose.first=You can choose the first item from the Lookup menu by pressing {0}.
java.basic.completion.activate=To activate Basic Completion, press {0} and you will see the lookup menu again.
java.basic.completion.choose.item=Select {0} inside the lookup menu and press {1}.
java.basic.completion.complete=Press {0} to complete this statement.
java.basic.completion.deeper.level=Sometimes you need to see suggestions for static constants or methods. \
Press {0} twice to access extended Code Completion.
java.basic.completion.module.promotion=You will find more about refactorings in the {0} module.
java.run.configuration.lets.run=Any code marked with {0} can be run. Let''s run our simple example with {1}. \
Alternatively, you can click {0} and select the {2} item.
java.postfix.completion.apply=Postfix Completion helps reduce backward caret jumps as you write code. \
It lets you transform an already typed expression into another one based on the postfix you add, the type of expression, and its context. \
Type {0} after the parenthesis to see the list of postfix completion suggestions. \
Select {1} from the list, or type it in the editor, and then press {2} to complete the statement.
java.smart.type.completion.lesson.name=Smart type completion
java.smart.type.completion.apply=Smart Type Completion filters the list of suggestion to include only those types that are applicable \
within the current context. Press {0} to see the list of matching suggestions. Choose the first one by pressing {1}.
java.smart.type.completion.return=Smart Type Completion can also suggest code for a return statement. \
Press {0} twice to see the Lookup menu for a return. Choose the first one by pressing {1}
java.statement.completion.lesson.name=Statement completion
java.statement.completion.complete.for=Press {0} to complete the {1} statement.
java.statement.completion.complete.if=Type {0} and press {1} to generate the statement.
java.statement.completion.complete.condition=Add a condition inside parentheses {0} and press {1} to jump inside the {2} statement.
java.statement.completion.complete.finish.body=Type on one line: {0} and then press {1} to complete the entered statement and apply formatting.
java.rename.press.rename=Press {0} to rename field {1}.
java.rename.type.new.name=Type the new name for this field (e.g., {0}) and press {1}.
java.rename.confirm.accessors.rename=<ide/> is detecting corresponding getters/setters and proposes to rename them accordingly.\
Now just press {0} or click {1}
java.refactoring.menu.inline.variable=Now let''s inline variable {0} into the only use. \
You can press {1} and filter by <strong>iv</strong> (<strong>i</strong>nline <strong>v</strong>ariable). Or just press {2}.
java.refactoring.menu.introduce.constant=In the end, let''s extract extension from file name. \
Again, you can press {0} and filter by <strong>ic</strong> (<strong>i</strong>ntroduce <strong>c</strong>onstant). Or just press {1}.
java.refactoring.menu.confirm.constant=In this dialog you can choose the name, the parent and visibility for the new constant. \
You can leave proposed defaults and press {0} or click {1}.
java.inheritance.hierarchy.lesson.name=Inheritance hierarchy
java.inheritance.hierarchy.goto.implementation=Press {0} to look for implementations of {1}.
java.inheritance.hierarchy.choose.any.implementation=Choose any implementation and press {0} (or click it by mouse).
java.inheritance.hierarchy.navigate.to.base=You can navigate to a super method from derived. Press {0} or click icon {1} in the editor gutter.
java.inheritance.hierarchy.invoke.implementations.again=The declaration of the base method has its own gutter icon {0}. \
Click it or press {1} again.
java.inheritance.hierarchy.open.in.find.tool.window=For big hierarchies you may want to look for implementations in the {0} tool window. \
Click at {1}.
java.inheritance.hierarchy.hide.find.tool.window=Press {0} to hide the {1} tool window.
java.inheritance.hierarchy.open.method.hierarchy=You may want to explore the whole hierarchy for this method. Press {0}.
java.inheritance.hierarchy.hide.method.hierarchy=Let''s hide {0} also. Press {1} again.
java.inheritance.hierarchy.open.class.hierarchy=To overview the class hierarchy press {0}.
java.inheritance.hierarchy.last.note=<strong>Note:</strong> Actions {0} and {1} can be applied to classes also. \
Actions {2} and {3} may be used rarely but you always can find them with {4} by the {5} filter.
java.find.occurrences.lesson.name=Next/previous occurrences
java.find.occurrences.invoke.find=For this lesson, we selected {0}. Press {1} to start the textual search through the current file.
java.find.occurrences.find.previous=For previous occurrences, press {0}.
java.find.occurrences.find.next=<ide/> automatically copies the selected text into the search field. Let''s find the next occurrence. \
Press {0} or {1}.
java.find.occurrences.close.search.tool=With the search panel closed, you can still use these shortcuts to navigate between occurrences \
of the item being searched for earlier. Let''s close the search panel by pressing {0}.
java.find.occurrences.find.next.in.editor=Try to find the next occurrence with {0}.
java.find.occurrences.find.previous.in.editor=And {0} in a back way.
java.find.occurrences.note.about.cyclic=<strong>Note:</strong> The search is cyclic and pressing twice {0} at the last occurrence will set \
the selection for the last occurrence. {1} is cyclic also.
java.debug.workflow.rebuild=For big programs rerun can take much time. When you find some mistake in pure method you can just rebuild \
the project and apply <strong>Hot Swap</strong> JVM feature. Let''s build project: {0} or {1}.
java.debug.workflow.confirm.hot.swap=Confirm <strong>Hot Swap</strong> replacement.
java.debug.workflow.drop.frame=We patched our method, but right now we are still executing old obsolete {0} and it will throw the \
exception again. Let''s drop the frame and return to the state before {1} call. Click {2} at the debug panel or press {3}.

View File

@@ -0,0 +1,97 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift
import com.intellij.ide.impl.NewProjectUtil
import com.intellij.openapi.application.invokeAndWaitIfNeeded
import com.intellij.openapi.application.runInEdt
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.impl.LanguageLevelProjectExtensionImpl
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.pom.java.LanguageLevel
import com.intellij.util.lang.JavaVersion
import training.lang.AbstractLangSupport
import training.learn.LearnBundle
import java.nio.file.Path
class JavaLangSupport : AbstractLangSupport() {
override val primaryLanguage: String = "JAVA"
override val defaultProductName: String = "IDEA"
override val projectSandboxRelativePath: String = "Sample.java"
override fun installAndOpenLearningProject(projectPath: Path,
projectToClose: Project?,
postInitCallback: (learnProject: Project) -> Unit) {
super.installAndOpenLearningProject(projectPath, projectToClose) { project ->
findJavaSdkAsync { sdk ->
if (sdk != null) {
applyProjectSdk(sdk, project)
}
}
postInitCallback(project)
}
}
private fun findJavaSdkAsync(onSdkSearchCompleted: (Sdk?) -> Unit) {
val javaSdkType = JavaSdk.getInstance()
SdkLookup.newLookupBuilder()
.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) {
SdkLookupDecision.CONTINUE
}
else {
onSdkSearchCompleted(null)
SdkLookupDecision.STOP
}
}
.onSdkResolved { sdk ->
if (sdk != null && sdk.sdkType === javaSdkType) {
onSdkSearchCompleted(sdk)
}
}
.executeLookup()
}
override fun getSdkForProject(project: Project): Sdk? {
return null
}
override fun applyProjectSdk(sdk: Sdk, project: Project) {
val applySdkAction = {
runWriteAction { NewProjectUtil.applyJdkToProject(project, sdk) }
}
runInEdt {
CommandProcessor.getInstance().executeCommand(project, applySdkAction, null, null)
}
}
override fun applyToProjectAfterConfigure(): (Project) -> Unit = { newProject ->
//Set language level for LearnProject
LanguageLevelProjectExtensionImpl.getInstanceImpl(newProject).currentLevel = LanguageLevel.JDK_1_6
}
override fun checkSdk(sdk: Sdk?, project: Project) {}
companion object {
@JvmStatic
val lang: String = "JAVA"
}
}

View File

@@ -0,0 +1,112 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift
import com.intellij.java.ift.lesson.assistance.JavaEditorCodingAssistanceLesson
import com.intellij.java.ift.lesson.basic.JavaContextActionsLesson
import com.intellij.java.ift.lesson.basic.JavaSurroundAndUnwrapLesson
import com.intellij.java.ift.lesson.completion.*
import com.intellij.java.ift.lesson.navigation.*
import com.intellij.java.ift.lesson.refactorings.JavaExtractMethodCocktailSortLesson
import com.intellij.java.ift.lesson.refactorings.JavaRefactoringMenuLesson
import com.intellij.java.ift.lesson.refactorings.JavaRenameLesson
import com.intellij.java.ift.lesson.run.JavaDebugLesson
import com.intellij.java.ift.lesson.run.JavaRunConfigurationLesson
import com.intellij.lang.java.JavaLanguage
import training.learn.LearningModule
import training.learn.LessonsBundle
import training.learn.course.LearningCourseBase
import training.learn.interfaces.LessonType
import training.learn.lesson.general.*
import training.learn.lesson.general.assistance.CodeFormatLesson
import training.learn.lesson.general.assistance.ParameterInfoLesson
import training.learn.lesson.general.assistance.QuickPopupsLesson
import training.learn.lesson.general.refactorings.ExtractVariableFromBubbleLesson
import training.learn.lesson.kimpl.LessonUtil
class JavaLearningCourse : LearningCourseBase(JavaLanguage.INSTANCE.id) {
override fun modules() = listOf(
LearningModule(name = LessonsBundle.message("essential.module.name"),
description = LessonsBundle.message("essential.module.description", LessonUtil.productName),
primaryLanguage = langSupport,
moduleType = LessonType.SCRATCH) {
fun ls(sampleName: String) = loadSample("EditorBasics/$sampleName")
listOf(
JavaContextActionsLesson(it),
GotoActionLesson(it, lang, ls("00.Actions.java.sample"), firstLesson = false),
JavaSearchEverywhereLesson(it),
JavaBasicCompletionLesson(it),
)
},
LearningModule(name = LessonsBundle.message("editor.basics.module.name"),
description = LessonsBundle.message("editor.basics.module.description"),
primaryLanguage = langSupport,
moduleType = LessonType.SCRATCH) {
fun ls(sampleName: String) = loadSample("EditorBasics/$sampleName")
listOf(
SelectLesson(it, lang, ls("01.Select.java.sample")),
SingleLineCommentLesson(it, lang, ls("02.Comment.java.sample")),
DuplicateLesson(it, lang, ls("04.Duplicate.java.sample")),
MoveLesson(it, lang, ls("05.Move.java.sample")),
CollapseLesson(it, lang, ls("06.Collapse.java.sample")),
JavaSurroundAndUnwrapLesson(it),
MultipleSelectionHtmlLesson(it),
)
},
LearningModule(name = LessonsBundle.message("code.completion.module.name"),
description = LessonsBundle.message("code.completion.module.description"),
primaryLanguage = langSupport,
moduleType = LessonType.SCRATCH) {
listOf(
JavaSmartTypeCompletionLesson(it),
JavaPostfixCompletionLesson(it),
JavaStatementCompletionLesson(it),
JavaCompletionWithTabLesson(it),
)
},
LearningModule(name = LessonsBundle.message("refactorings.module.name"),
description = LessonsBundle.message("refactorings.module.description"),
primaryLanguage = langSupport,
moduleType = LessonType.PROJECT) {
fun ls(sampleName: String) = loadSample("Refactorings/$sampleName")
listOf(
JavaRenameLesson(it),
ExtractVariableFromBubbleLesson(it, lang, ls("ExtractVariable.java.sample")),
JavaExtractMethodCocktailSortLesson(it),
JavaRefactoringMenuLesson(it),
)
},
LearningModule(name = LessonsBundle.message("code.assistance.module.name"),
description = LessonsBundle.message("code.assistance.module.description"),
primaryLanguage = langSupport,
moduleType = LessonType.PROJECT) {
fun ls(sampleName: String) = loadSample("CodeAssistance/$sampleName")
listOf(
CodeFormatLesson(it, lang, ls("CodeFormat.java.sample")),
ParameterInfoLesson(it, lang, ls("ParameterInfo.java.sample")),
QuickPopupsLesson(it, lang, ls("QuickPopups.java.sample")),
JavaEditorCodingAssistanceLesson(it, lang, ls("EditorCodingAssistance.java.sample")),
)
},
LearningModule(name = LessonsBundle.message("navigation.module.name"),
description = LessonsBundle.message("navigation.module.description"),
primaryLanguage = langSupport,
moduleType = LessonType.PROJECT) {
listOf(
JavaFileStructureLesson(it),
JavaDeclarationAndUsagesLesson(it),
JavaInheritanceHierarchyLesson(it),
JavaRecentFilesLesson(it),
JavaOccurrencesLesson(it),
)
},
LearningModule(name = LessonsBundle.message("run.debug.module.name"),
description = LessonsBundle.message("run.debug.module.description"),
primaryLanguage = langSupport,
moduleType = LessonType.PROJECT) {
listOf(
JavaRunConfigurationLesson(it),
JavaDebugLesson(it),
)
},
)
}

View File

@@ -0,0 +1,15 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift
import com.intellij.DynamicBundle
import org.jetbrains.annotations.Nls
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
@NonNls
private const val BUNDLE = "messages.JavaLessonsBundle"
object JavaLessonsBundle : DynamicBundle(BUNDLE) {
@Nls
fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String = getMessage(key, *params)
}

View File

@@ -0,0 +1,24 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.assistance
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.testGuiFramework.fixtures.IdeFrameFixture
import com.intellij.testGuiFramework.impl.jList
import training.learn.interfaces.Module
import training.learn.lesson.general.assistance.EditorCodingAssistanceLesson
import training.learn.lesson.kimpl.LessonSample
class JavaEditorCodingAssistanceLesson(module: Module, lang: String, sample: LessonSample) :
EditorCodingAssistanceLesson(module, lang, sample) {
override fun IdeFrameFixture.simulateErrorFixing() {
jList(intentionDisplayName).clickItem(intentionDisplayName)
}
override val fixedText: String = "throws IOException"
override val intentionDisplayName: String
get() = QuickFixBundle.message("add.exception.to.throws.family")
override val variableNameToHighlight: String = "lines"
}

View File

@@ -0,0 +1,35 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.basic
import com.intellij.codeInsight.daemon.QuickFixBundle
import com.siyeh.IntentionPowerPackBundle
import training.learn.interfaces.Module
import training.learn.lesson.general.ContextActionsLesson
import training.learn.lesson.kimpl.LessonSample
import training.learn.lesson.kimpl.parseLessonSample
class JavaContextActionsLesson(module: Module) : ContextActionsLesson(module, "JAVA") {
override val sample: LessonSample = parseLessonSample("""
class Scratch {
public static void main(String[] args) {
methodWithUnusedParameter("first", "second");
methodWithUnusedParameter("used", "unused");
}
private static void methodWithUnusedParameter(String used, String redundant) {
System.err.println("It is used parameter: " + used);
}
public int intentionExample(boolean z, boolean a, boolean b) {
if (!(z ? a : b)) return 1;
return 2;
}
}
""".trimIndent())
override val warningQuickFix: String = QuickFixBundle.message("safe.delete.text", "redundant")
override val warningCaret: String = "redundant)"
override val generalIntention: String = IntentionPowerPackBundle.message("negate.conditional.intention.name")
override val generalIntentionCaret: String = "? a : b"
}

View File

@@ -0,0 +1,28 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.basic
import com.intellij.java.ift.JavaLessonsBundle
import training.learn.LessonsBundle
import training.learn.interfaces.Module
import training.learn.lesson.general.SurroundAndUnwrapLesson
import training.learn.lesson.kimpl.LessonSample
import training.learn.lesson.kimpl.parseLessonSample
class JavaSurroundAndUnwrapLesson(module: Module) : SurroundAndUnwrapLesson(module, "JAVA") {
override val sample: LessonSample = parseLessonSample("""
class SurroundAndUnwrapDemo {
public static void main(String[] args) {
<select>System.out.println("Surround and Unwrap me!");</select>
}
}
""".trimIndent())
override val surroundItems = arrayOf("try", "catch", "finally")
override val lineShiftBeforeUnwrap = -2
override val helpLinks: Map<String, String> = mapOf(
Pair(LessonsBundle.message("surround.and.unwrap.help.surround.code.fragments"), "https://www.jetbrains.com/help/idea/surrounding-blocks-of-code-with-language-constructs.html"),
Pair(JavaLessonsBundle.message("java.surround.and.unwrap.help.unwrapping.and.removing.statements"), "https://www.jetbrains.com/help/idea/working-with-source-code.html#editor_statement_select"),
)
}

View File

@@ -0,0 +1,61 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.completion
import com.intellij.java.ift.JavaLangSupport
import com.intellij.java.ift.JavaLessonsBundle
import training.learn.LessonsBundle
import training.learn.interfaces.Module
import training.learn.lesson.kimpl.KLesson
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.parseLessonSample
class JavaBasicCompletionLesson(module: Module)
: KLesson("Basic completion", LessonsBundle.message("basic.completion.lesson.name"), module, JavaLangSupport.lang) {
val sample = parseLessonSample("""
import java.lang.*;
import java.util.*;
class BasicCompletionDemo implements Runnable{
private int i = 0;
public void systemProcess(){
System.out.println(i++);
}
public BasicCompletionDemo() {
byte b = MAX_VALUE
}
@Override
public void run() {
Random random = new <caret>
}
}
""".trimIndent())
override val lessonContent: LessonContext.() -> Unit = {
prepareSample(sample)
actionTask("EditorChooseLookupItem") {
LessonsBundle.message("basic.completion.start.typing", code("Run")) +
" " + JavaLessonsBundle.message("java.basic.completion.choose.first", action(it))
}
caret(18, 36)
actionTask("CodeCompletion") {
JavaLessonsBundle.message("java.basic.completion.activate", action(it))
}
actionTask("EditorChooseLookupItem") {
JavaLessonsBundle.message("java.basic.completion.choose.item", code("i"), action(it))
}
actionTask("EditorCompleteStatement") {
JavaLessonsBundle.message("java.basic.completion.complete", action(it))
}
task("CodeCompletion") {
caret(13, 27)
text(JavaLessonsBundle.message("java.basic.completion.deeper.level", action(it)))
triggers(it, it)
}
text(JavaLessonsBundle.message("java.basic.completion.module.promotion", strong(LessonsBundle.message("refactorings.module.name"))))
}
}

View File

@@ -0,0 +1,23 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.completion
import com.intellij.java.ift.JavaLangSupport
import training.learn.interfaces.Module
import training.learn.lesson.general.CompletionWithTabLesson
import training.learn.lesson.kimpl.parseLessonSample
class JavaCompletionWithTabLesson(module: Module) :
CompletionWithTabLesson(module, JavaLangSupport.lang, "DO_NOTHING_ON_CLOSE") {
override val sample = parseLessonSample("""import javax.swing.*;
class FrameDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("FrameDemo");
frame.setSize(175, 100);
frame.setDefaultCloseOperation(WindowConstants.<caret>DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}""".trimIndent())
}

View File

@@ -0,0 +1,30 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.completion
import com.intellij.java.ift.JavaLangSupport
import com.intellij.java.ift.JavaLessonsBundle
import training.learn.LessonsBundle
import training.learn.interfaces.Module
import training.learn.lesson.kimpl.KLesson
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.parseLessonSample
class JavaPostfixCompletionLesson(module: Module)
: KLesson("Postfix completion", LessonsBundle.message("postfix.completion.lesson.name"), module, JavaLangSupport.lang) {
val sample = parseLessonSample("""
class PostfixCompletionDemo{
public void demonstrate(int show_times){
(show_times == 10)
}
}
""".trimIndent())
override val lessonContent: LessonContext.() -> Unit = {
prepareSample(sample)
caret(4, 27)
actionTask("EditorChooseLookupItem") {
JavaLessonsBundle.message("java.postfix.completion.apply", code("."), code("if"), action("EditorChooseLookupItem"))
}
}
}

View File

@@ -0,0 +1,55 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.completion
import com.intellij.java.ift.JavaLangSupport
import com.intellij.java.ift.JavaLessonsBundle
import training.learn.interfaces.Module
import training.learn.lesson.kimpl.KLesson
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.parseLessonSample
class JavaSmartTypeCompletionLesson(module: Module)
: KLesson("Smart type completion", JavaLessonsBundle.message("java.smart.type.completion.lesson.name"), module, JavaLangSupport.lang) {
val sample = parseLessonSample("""
import java.lang.String;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
class SmartCompletionDemo{
private Queue<String> strings;
private ArrayBlockingQueue<String> arrayBlockingQueue;
public SmartCompletionDemo(LinkedList<String> linkedList, HashSet<String> hashSet) {
strings =
arrayBlockingQueue = new ArrayBlockingQueue<String>(hashSet.size());
for (String s : hashSet)
arrayBlockingQueue.add(s);
}
private String[] toArray() {
return <caret>
}
}
""".trimIndent())
override val lessonContent: LessonContext.() -> Unit = {
prepareSample(sample)
task {
caret(13, 19)
text(JavaLessonsBundle.message("java.smart.type.completion.apply", action("SmartTypeCompletion"), action("EditorChooseLookupItem")))
trigger("SmartTypeCompletion")
trigger("EditorChooseLookupItem")
}
task {
caret(20, 16)
text(JavaLessonsBundle.message("java.smart.type.completion.return", action("SmartTypeCompletion"), action("EditorChooseLookupItem")))
triggers("SmartTypeCompletion", "SmartTypeCompletion")
trigger("EditorChooseLookupItem")
}
}
}

View File

@@ -0,0 +1,68 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.completion
import com.intellij.java.ift.JavaLangSupport
import com.intellij.java.ift.JavaLessonsBundle
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiForStatement
import com.intellij.psi.util.PsiTreeUtil
import training.commands.kotlin.TaskRuntimeContext
import training.learn.interfaces.Module
import training.learn.lesson.kimpl.KLesson
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.parseLessonSample
class JavaStatementCompletionLesson(module: Module)
: KLesson("Statement completion", JavaLessonsBundle.message("java.statement.completion.lesson.name"), module, JavaLangSupport.lang) {
val sample = parseLessonSample("""
class PrimeNumbers {
public static void main(String[] args) {
System.out.println("Prime numbers between 1 and 100");
for (int i = 2; i < 100; i++) {
boolean isPrime = true;
for (int j = 2; j < i; j++)
if (isPrime) {
System.out.print(i + " ");
}
}
}
}
""".trimIndent())
override val lessonContent: LessonContext.() -> Unit = {
prepareSample(sample)
caret(8, 40)
actionTask("EditorCompleteStatement") {
JavaLessonsBundle.message("java.statement.completion.complete.for", action(it), code("for"))
}
task("EditorCompleteStatement") {
text(JavaLessonsBundle.message("java.statement.completion.complete.if", code("if"), action(it)))
stateCheck {
return@stateCheck checkIfAppended()
}
}
actionTask("EditorCompleteStatement") {
JavaLessonsBundle.message("java.statement.completion.complete.condition", code("i % j == 0"), action(it), code("if"))
}
actionTask("EditorCompleteStatement") {
JavaLessonsBundle.message("java.statement.completion.complete.finish.body", code("isPrime = false; break"), action(it))
}
}
private fun TaskRuntimeContext.checkIfAppended(): Boolean {
val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.document)
val psiForStatements = PsiTreeUtil.findChildrenOfType(psiFile, PsiForStatement::class.java).toTypedArray()
if (psiForStatements.size < 2) return false
val psiForStatement = psiForStatements[1] as PsiForStatement
val text = psiForStatement.body!!.text
val trimmedText = text.replace("\\s+".toRegex(), "")
return trimmedText == "{if(){}}"
}
}

View File

@@ -0,0 +1,11 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.navigation
import training.learn.interfaces.Module
import training.learn.lesson.general.navigation.DeclarationAndUsagesLesson
import training.learn.lesson.kimpl.LessonContext
class JavaDeclarationAndUsagesLesson(module: Module) : DeclarationAndUsagesLesson(module, "JAVA") {
override fun LessonContext.setInitialPosition() = caret("foo()")
override val existedFile: String get() = "src/DerivedClass2.java"
}

View File

@@ -0,0 +1,12 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.navigation
import training.learn.interfaces.Module
import training.learn.lesson.general.navigation.FileStructureLesson
class JavaFileStructureLesson(module: Module) : FileStructureLesson(module, "JAVA") {
override val searchSubstring: String = "hosa"
override val firstWord: String = "homo"
override val secondWord: String = "sapience"
override val existedFile: String = "src/FileStructureDemo.java"
}

View File

@@ -0,0 +1,119 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.navigation
import com.intellij.codeInsight.CodeInsightBundle
import com.intellij.icons.AllIcons
import com.intellij.ide.IdeBundle
import com.intellij.java.analysis.JavaAnalysisBundle
import com.intellij.java.ift.JavaLessonsBundle
import com.intellij.openapi.wm.ToolWindowId
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.openapi.wm.impl.content.BaseLabel
import com.intellij.testGuiFramework.framework.GuiTestUtil
import com.intellij.testGuiFramework.util.Key
import com.intellij.ui.InplaceButton
import com.intellij.ui.UIBundle
import training.commands.kotlin.TaskContext
import training.commands.kotlin.TaskRuntimeContext
import training.learn.interfaces.Module
import training.learn.lesson.kimpl.KLesson
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.LessonUtil
import training.learn.lesson.kimpl.closeAllFindTabs
class JavaInheritanceHierarchyLesson(module: Module)
: KLesson("java.inheritance.hierarchy.lesson", JavaLessonsBundle.message("java.inheritance.hierarchy.lesson.name"), module, "JAVA") {
override val existedFile: String = "src/InheritanceHierarchySample.java"
override val lessonContent: LessonContext.() -> Unit = {
caret("foo(demo)")
actionTask("GotoImplementation") {
JavaLessonsBundle.message("java.inheritance.hierarchy.goto.implementation", action(it), code("SomeInterface#foo"))
}
task {
text(JavaLessonsBundle.message("java.inheritance.hierarchy.choose.any.implementation", LessonUtil.rawEnter()))
stateCheck {
(virtualFile.name == "DerivedClass1.java" || virtualFile.name == "DerivedClass2.java") && atDeclarationPosition()
}
test {
Thread.sleep(1000)
GuiTestUtil.shortcut(Key.ENTER)
}
}
task("GotoSuperMethod") {
text(JavaLessonsBundle.message("java.inheritance.hierarchy.navigate.to.base", action(it), icon(AllIcons.Gutter.ImplementingMethod)))
stateCheck {
virtualFile.name == "SomeInterface.java" && atDeclarationPosition()
}
test { actions(it) }
}
task("GotoImplementation") {
text(JavaLessonsBundle.message("java.inheritance.hierarchy.invoke.implementations.again", icon(AllIcons.Gutter.ImplementedMethod),
action(it)))
triggerByUiComponentAndHighlight { ui: InplaceButton ->
ui.toolTipText == IdeBundle.message("show.in.find.window.button.name")
}
test { actions(it) }
}
task {
before {
closeAllFindTabs()
}
text(JavaLessonsBundle.message("java.inheritance.hierarchy.open.in.find.tool.window", findToolWindow(),
icon(ToolWindowManager.getInstance(project).getLocationIcon(ToolWindowId.FIND, AllIcons.General.Pin_tab))))
triggerByUiComponentAndHighlight(highlightBorder = false, highlightInside = false) { ui: BaseLabel ->
ui.text == (CodeInsightBundle.message("goto.implementation.findUsages.title", "foo")) ||
ui.text == (JavaAnalysisBundle.message("navigate.to.overridden.methods.title", "foo"))
}
test {
ideFrame {
val target = previous.ui!!
jComponent(target).click()
jComponent(target).click() // for some magic reason one click sometimes doesn't work :(
}
}
}
actionTask("HideActiveWindow") {
JavaLessonsBundle.message("java.inheritance.hierarchy.hide.find.tool.window", action(it), findToolWindow())
}
actionTask("MethodHierarchy") {
JavaLessonsBundle.message("java.inheritance.hierarchy.open.method.hierarchy", action(it))
}
actionTask("HideActiveWindow") {
JavaLessonsBundle.message("java.inheritance.hierarchy.hide.method.hierarchy", hierarchyToolWindow(), action(it))
}
actionTask("TypeHierarchy") {
JavaLessonsBundle.message("java.inheritance.hierarchy.open.class.hierarchy", action(it))
}
text(JavaLessonsBundle.message("java.inheritance.hierarchy.last.note",
action("GotoImplementation"),
action("GotoSuperMethod"),
action("MethodHierarchy"),
action("TypeHierarchy"),
action("GotoAction"),
strong("hierarchy")))
}
private fun TaskRuntimeContext.atDeclarationPosition(): Boolean {
return editor.document.charsSequence.let {
it.subSequence(editor.caretModel.currentCaret.offset, it.length).startsWith("foo(FileStructureDemo demo)")
}
}
private fun TaskContext.findToolWindow() = strong(UIBundle.message("tool.window.name.find"))
private fun TaskContext.hierarchyToolWindow() = strong(UIBundle.message("tool.window.name.hierarchy"))
}

View File

@@ -0,0 +1,95 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.navigation
import com.intellij.java.ift.JavaLessonsBundle
import com.intellij.testGuiFramework.framework.GuiTestUtil
import com.intellij.testGuiFramework.impl.actionButton
import com.intellij.testGuiFramework.util.Key
import com.intellij.usageView.UsageViewBundle
import training.learn.interfaces.Module
import training.learn.lesson.kimpl.KLesson
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.LessonUtil
import training.learn.lesson.kimpl.parseLessonSample
class JavaOccurrencesLesson(module: Module)
: KLesson("java.occurrences.lesson", JavaLessonsBundle.message("java.find.occurrences.lesson.name"), module, "JAVA") {
val sample = parseLessonSample("""
class OccurrencesDemo {
final private String DATABASE = "MyDataBase";
DataEntry myPerson;
OccurrencesDemo(String name, int age, String <select>cellphone</select>){
myPerson = new Person(name, age, "Cellphone: " + cellphone);
}
interface DataEntry{
String getCellphone();
String getName();
}
class Person implements DataEntry {
public Person(String name, int age, String cellphone) {
this.name = name;
this.age = age;
this.cellphone = cellphone;
}
private String name;
private int age;
private String cellphone;
public String getCellphone() {
return cellphone;
}
public String getName() {
return name;
}
}
}
""".trimIndent())
override val lessonContent: LessonContext.() -> Unit = {
prepareSample(sample)
actionTask("Find") {
JavaLessonsBundle.message("java.find.occurrences.invoke.find", code("cellphone"), action(it))
}
task("FindNext") {
trigger("com.intellij.find.editorHeaderActions.NextOccurrenceAction")
text(JavaLessonsBundle.message("java.find.occurrences.find.next", LessonUtil.rawEnter(), action(it)))
test {
ideFrame {
actionButton(UsageViewBundle.message("action.next.occurrence")).click()
}
}
}
task("FindPrevious") {
trigger("com.intellij.find.editorHeaderActions.PrevOccurrenceAction")
text(JavaLessonsBundle.message("java.find.occurrences.find.previous", action("FindPrevious")))
test {
ideFrame {
actionButton(UsageViewBundle.message("action.previous.occurrence")).click()
}
}
}
task("EditorEscape") {
text(JavaLessonsBundle.message("java.find.occurrences.close.search.tool", action(it)))
stateCheck {
editor.headerComponent == null
}
test { GuiTestUtil.shortcut(Key.ESCAPE) }
}
actionTask("FindNext") {
JavaLessonsBundle.message("java.find.occurrences.find.next.in.editor", action(it))
}
actionTask("FindPrevious") {
JavaLessonsBundle.message("java.find.occurrences.find.previous.in.editor", action(it))
}
text(JavaLessonsBundle.message("java.find.occurrences.note.about.cyclic", action("FindNext"), action("FindPrevious")))
}
}

View File

@@ -0,0 +1,16 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.navigation
import training.learn.interfaces.Module
import training.learn.lesson.general.navigation.RecentFilesLesson
import training.learn.lesson.kimpl.LessonContext
class JavaRecentFilesLesson(module: Module) : RecentFilesLesson(module, "JAVA") {
override val existedFile: String = "src/RecentFilesDemo.java"
override val transitionMethodName: String = "println"
override val transitionFileName: String = "PrintStream"
override val stringForRecentFilesSearch: String = "print"
override fun LessonContext.setInitialPosition() = caret("println")
}

View File

@@ -0,0 +1,16 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.navigation
import training.learn.LessonsBundle
import training.learn.interfaces.Module
import training.learn.lesson.general.navigation.SearchEverywhereLesson
import training.learn.lesson.kimpl.LessonContext
class JavaSearchEverywhereLesson(module: Module) : SearchEverywhereLesson(module, "JAVA") {
override val existedFile = "src/RecentFilesDemo.java"
override val resultFileName: String = "QuadraticEquationsSolver.java"
override fun LessonContext.epilogue() {
text(LessonsBundle.message("search.everywhere.navigation.promotion", strong(LessonsBundle.message("navigation.module.name"))))
}
}

View File

@@ -0,0 +1,113 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.refactorings
import com.intellij.java.refactoring.JavaRefactoringBundle
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.extractMethod.ExtractMethodHandler
import com.intellij.testGuiFramework.impl.button
import com.intellij.ui.UIBundle
import training.commands.kotlin.TaskTestContext
import training.learn.LessonsBundle
import training.learn.interfaces.Module
import training.learn.lesson.kimpl.KLesson
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.dropMnemonic
import training.learn.lesson.kimpl.parseLessonSample
import javax.swing.JDialog
class JavaExtractMethodCocktailSortLesson(module: Module)
: KLesson("Refactorings.ExtractMethod", LessonsBundle.message("extract.method.lesson.name"), module, "JAVA") {
override val lessonContent: LessonContext.() -> Unit
get() = {
prepareSample(javaSortSample)
actionTask("ExtractMethod") {
LessonsBundle.message("extract.method.invoke.action", action(it))
}
// Now will be open the first dialog
val processDuplicatesTitle = JavaRefactoringBundle.message("process.duplicates.title")
task {
val refactorButtonText = RefactoringBundle.message("refactor.button").dropMnemonic()
text(LessonsBundle.message("extract.method.start.refactoring", strong(refactorButtonText)))
// Wait until the second dialog
triggerByUiComponentAndHighlight(highlightBorder = false, highlightInside = false) { dialog : JDialog ->
dialog.title == processDuplicatesTitle
}
var needRestore = false
restoreState {
val insideDialog = Thread.currentThread().stackTrace.any {
it.className.contains(ExtractMethodHandler::class.simpleName!!)
}
(needRestore && !insideDialog).also { needRestore = insideDialog }
}
test {
with(TaskTestContext.guiTestCase) {
dialog(RefactoringBundle.message("extract.method.title"), needToKeepDialog=true) {
button(refactorButtonText).click()
}
}
}
}
val replaceButtonText = UIBundle.message("replace.prompt.replace.button").dropMnemonic()
task {
text(LessonsBundle.message("extract.method.confirm.several.replaces", strong(replaceButtonText)))
stateCheck {
previous.ui?.isShowing?.not() ?: true
}
test {
with(TaskTestContext.guiTestCase) {
dialog(processDuplicatesTitle) {
button(replaceButtonText).click()
}
}
}
}
}
}
private val javaSortSample = parseLessonSample("""
class Demo {
public static void cocktailSort(int[] a) {
boolean swapped = true;
int start = 0;
int end = a.length;
while (swapped) {
swapped = false;
for (int i = start; i < end - 1; ++i) {
<select> if (a[i] > a[i + 1]) {
int temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
swapped = true;
}
</select> }
if (!swapped)
break;
swapped = false;
end = end - 1;
for (int i = end - 1; i >= start; i--) {
if (a[i] > a[i + 1]) {
int temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
swapped = true;
}
}
start = start + 1;
}
}
}
""".trimIndent())

View File

@@ -0,0 +1,98 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.refactorings
import com.intellij.CommonBundle
import com.intellij.java.ift.JavaLessonsBundle
import com.intellij.refactoring.RefactoringBundle
import com.intellij.testGuiFramework.framework.GuiTestUtil
import com.intellij.testGuiFramework.util.Key
import com.intellij.util.ui.UIUtil
import training.commands.kotlin.TaskRuntimeContext
import training.learn.interfaces.Module
import training.learn.lesson.general.refactorings.RefactoringMenuLessonBase
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.LessonUtil
import training.learn.lesson.kimpl.parseLessonSample
import javax.swing.JDialog
class JavaRefactoringMenuLesson(module: Module) : RefactoringMenuLessonBase("java.refactoring.menu", module, "JAVA") {
private val sample = parseLessonSample("""
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
class Refactorings {
public static void main(String[] args) throws IOException {
List<String> array = readStrings();
List<String> filtered = array.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
for (String s : filtered) {
System.out.println(s);
}
}
private static List<String> readStrings() throws IOException {
try(BufferedReader reader = new BufferedReader(<select>new FileReader("input.txt")</select>)) {
ArrayList<String> lines = new ArrayList<>();
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
return lines;
}
}
}
""".trimIndent())
override val lessonContent: LessonContext.() -> Unit = {
prepareSample(sample)
extractParameterTasks()
moreRefactoringsTasks()
}
private fun LessonContext.moreRefactoringsTasks() {
waitBeforeContinue(300)
val inlineVariableName = "array"
caret(inlineVariableName)
actionTask("Inline") {
JavaLessonsBundle.message("java.refactoring.menu.inline.variable",
code(inlineVariableName), action("Refactorings.QuickListPopupAction"), action(it))
}
task {
stateCheck {
!editor.document.charsSequence.contains(inlineVariableName)
}
}
caret("txt", true)
actionTask("IntroduceConstant") {
JavaLessonsBundle.message("java.refactoring.menu.introduce.constant",
action("Refactorings.QuickListPopupAction"), action(it))
}
task {
stateCheck {
extractConstantDialogShowing()
}
}
task {
text(JavaLessonsBundle.message("java.refactoring.menu.confirm.constant",
LessonUtil.rawEnter(), strong(CommonBundle.getOkButtonText())))
stateCheck {
!extractConstantDialogShowing()
}
test {
GuiTestUtil.shortcut(Key.ENTER)
}
}
}
private fun TaskRuntimeContext.extractConstantDialogShowing() =
focusOwner?.let { fo -> UIUtil.getParentOfType(JDialog::class.java, fo) }?.title ==
RefactoringBundle.message("introduce.constant.title")
}

View File

@@ -0,0 +1,133 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.refactorings
import com.intellij.CommonBundle
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
import com.intellij.java.ift.JavaLessonsBundle
import com.intellij.java.refactoring.JavaRefactoringBundle
import com.intellij.refactoring.rename.RenameProcessor
import com.intellij.testGuiFramework.impl.button
import com.intellij.util.ui.UIUtil
import training.commands.kotlin.TaskContext
import training.commands.kotlin.TaskRuntimeContext
import training.learn.LessonsBundle
import training.learn.interfaces.Module
import training.learn.lesson.kimpl.*
import training.learn.lesson.kimpl.LessonUtil.checkExpectedStateOfEditor
import javax.swing.JDialog
class JavaRenameLesson(module: Module)
: KLesson("Refactorings.Rename", LessonsBundle.message("rename.lesson.name"), module, "JAVA") {
private val initialName = "stylus"
private val template = """
import java.lang.String;
class Rename {
private String <caret id=2/><name>;
private String deviceName;
public void touchDevice(int x, int y, float strength, Device device) {
device.touchByStylus(<caret><name>, x, y, strength);
}
public boolean checkIPad() {
if (deviceName.equals("iPad")) return true;
return false;
}
public String get<name2>() {
return <name>;
}
interface Device {
void touchByStylus(String stylus, int x, int y, float strength);
}
}
class Derived extends Rename {
@Override
public String get<name2>() {
System.err.println("Derived method applied");
return super.get<name2>();
}
}
""".trimIndent() + '\n'
private val sample = parseLessonSample(replaceTemplate(initialName))
private fun replaceTemplate(name: String) =
template.replace("<name>", name)
.replace("<name2>", name.capitalize())
override val lessonContent: LessonContext.() -> Unit = {
val newNameExample = "pencil"
prepareSample(sample)
lateinit var startId: TaskContext.TaskId
task("RenameElement") {
startId = taskId
text(JavaLessonsBundle.message("java.rename.press.rename", action(it), code(initialName)))
triggers(it)
proposeRestore {
checkExpectedStateOfEditor(sample, false)
}
test {
actions(it)
}
}
task("NextTemplateVariable") {
triggers(it)
text(JavaLessonsBundle.message("java.rename.type.new.name", code(newNameExample), LessonUtil.rawEnter()))
restoreAfterStateBecomeFalse {
TemplateManagerImpl.getTemplateState(editor) == null
}
test {
type(newNameExample)
actions(it)
}
}
task {
// wait until dialog will be showed
// It is not necessary step: just don't go further until correct name is chosen (name correctness is checking by rename handler)
stateCheck {
focusOwner?.let { fo -> UIUtil.getParentOfType(JDialog::class.java, fo) }?.title ==
JavaRefactoringBundle.message("rename.accessors.title")
}
}
task {
val okButtonText = CommonBundle.getOkButtonText()
text(JavaLessonsBundle.message("java.rename.confirm.accessors.rename",
LessonUtil.rawEnter(), strong(okButtonText)))
stateCheck {
val fieldName = getFieldName()
val shouldBe = fieldName?.let { replaceTemplate(it).replace("<caret>", "").replace("<caret id=2/>", "") }
fieldName != initialName && editor.document.text == shouldBe
}
restoreAfterStateBecomeFalse(startId) {
!Thread.currentThread().stackTrace.any {
it.className.contains(RenameProcessor::class.simpleName!!)
}
}
test {
ideFrame {
button(okButtonText).click()
}
}
}
}
private fun TaskRuntimeContext.getFieldName(): String? {
val charsSequence = editor.document.charsSequence
// get position of declaration because it should not shifted after rename
val start = sample.getPosition(2).startOffset
val end = charsSequence.indexOf(';', start).takeIf { it > 0 } ?: return null
val newName = charsSequence.subSequence(start, end)
if (newName.isEmpty()) return null
if (!Character.isJavaIdentifierStart(newName[0]) || newName.any { !Character.isJavaIdentifierPart(it) }) return null
return newName.toString()
}
}

View File

@@ -0,0 +1,70 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.run
import com.intellij.icons.AllIcons
import com.intellij.java.ift.JavaLessonsBundle
import com.intellij.testGuiFramework.impl.button
import training.commands.kotlin.TaskTestContext
import training.learn.interfaces.Module
import training.learn.lesson.general.run.CommonDebugLesson
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.highlightButtonById
class JavaDebugLesson(module: Module) : CommonDebugLesson(module, "java.debug.workflow", "JAVA") {
private val demoClassName = JavaRunLessonsUtils.demoClassName
override val configurationName: String = demoClassName
override val sample = JavaRunLessonsUtils.demoSample
override val confNameForWatches: String = "Application"
override val quickEvaluationArgument = "Integer.parseInt"
override val expressionToBeEvaluated = "result/input.length"
override val debuggingMethodName = "findAverage"
override val methodForStepInto: String = "extractNumber"
override val stepIntoDirection = ""
override fun LessonContext.applyProgramChangeTasks() {
highlightButtonById("CompileDirty")
task("CompileDirty") {
text(JavaLessonsBundle.message("java.debug.workflow.rebuild", action(it), icon(AllIcons.Actions.Compile)))
stateCheck {
inHotSwapDialog()
}
proposeModificationRestore(afterFixText)
test { actions(it) }
}
task {
text(JavaLessonsBundle.message("java.debug.workflow.confirm.hot.swap"))
stateCheck {
!inHotSwapDialog()
}
proposeModificationRestore(afterFixText)
test {
with(TaskTestContext.guiTestCase) {
dialog(null, needToKeepDialog = true) {
button("Yes").click()
}
}
}
}
highlightButtonById("Debugger.PopFrame")
actionTask("Debugger.PopFrame") {
proposeModificationRestore(afterFixText)
JavaLessonsBundle.message("java.debug.workflow.drop.frame", code("extractNumber"), code("extractNumber"), icon(AllIcons.Actions.PopFrame), action(it))
}
}
private fun inHotSwapDialog(): Boolean {
return Thread.currentThread().stackTrace.any { traceElement ->
traceElement.className.contains("HotSwapUIImpl")
}
}
override val testScriptProperties: TaskTestContext.TestScriptProperties
get() = TaskTestContext.TestScriptProperties(duration = 20)
override val fileName: String = "$demoClassName.java"
}

View File

@@ -0,0 +1,46 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.run
import com.intellij.execution.ExecutionBundle
import com.intellij.icons.AllIcons
import com.intellij.java.ift.JavaLessonsBundle
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataProvider
import com.intellij.openapi.editor.ex.EditorGutterComponentEx
import training.learn.interfaces.Module
import training.learn.lesson.general.run.CommonRunConfigurationLesson
import training.learn.lesson.kimpl.LessonContext
import training.learn.lesson.kimpl.LessonSample
import training.learn.lesson.kimpl.dropMnemonic
import training.learn.lesson.kimpl.toolWindowShowed
import java.awt.Rectangle
class JavaRunConfigurationLesson(module: Module) : CommonRunConfigurationLesson(module, "java.run.configuration", "JAVA") {
override val sample: LessonSample = JavaRunLessonsUtils.demoSample
override val demoConfigurationName: String = JavaRunLessonsUtils.demoClassName
override fun LessonContext.runTask() {
task {
triggerByPartOfComponent<EditorGutterComponentEx> l@{ ui ->
if (CommonDataKeys.EDITOR.getData(ui as DataProvider) != editor) return@l null
val y = editor.visualLineToY(0)
return@l Rectangle(25, y, ui.width - 40, editor.lineHeight * 2)
}
}
task("RunClass") {
text(JavaLessonsBundle.message("java.run.configuration.lets.run", icon(AllIcons.Actions.Execute), action(it),
strong(ExecutionBundle.message("default.runner.start.action.text").dropMnemonic())))
//Wait toolwindow
toolWindowShowed("Run")
stateCheck {
configurations().isNotEmpty()
}
test {
actions(it)
}
}
}
override val fileName: String = "${JavaRunLessonsUtils.demoClassName}.java"
}

View File

@@ -0,0 +1,53 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.ift.lesson.run
import training.learn.lesson.kimpl.parseLessonSample
object JavaRunLessonsUtils {
const val demoClassName = "Sample"
val demoSample = parseLessonSample("""
public class $demoClassName {
public static void main(String[] args) {
double average = findAverage(prepareValues());
System.out.println("The average is " + average);
}
private static double findAverage(String[] input) {
checkInput(input);
double result = 0;
for (String s : input) {
<caret>result += <select id=1>validateNumber(extractNumber(removeQuotes(s)))</select>;
}
<caret id=3/>return result;
}
private static String[] prepareValues() {
return new String[] {"'apple 1'", "orange 2", "'tomato 3'"};
}
private static int extractNumber(String s) {
return Integer.parseInt(<select id=2>s.split(" ")[0]</select>);
}
private static void checkInput(String[] input) {
if (input == null || input.length == 0) {
throw new IllegalArgumentException("Invalid input");
}
}
private static String removeQuotes(String s) {
if (s.startsWith("'") && s.endsWith("'") && s.length() > 1) {
return s.substring(1, s.length() - 1);
}
return s;
}
private static int validateNumber(int number) {
if (number < 0) throw new IllegalArgumentException("Invalid number: " + number);
return number;
}
}
""".trimIndent())
}

View File

@@ -30,6 +30,7 @@
<depends optional="true" config-file="structuralsearch-java.xml">com.intellij.modules.structuralsearch</depends>
<depends optional="true" config-file="RemoteServersJava.xml">com.intellij.modules.remoteServers</depends>
<depends optional="true" config-file="JavaCMakeActionPatcher.xml">com.intellij.modules.clion.cmake</depends> <!-- a workaround for IDEA-209728 -->
<depends optional="true" config-file="java-features-trainer.xml">training</depends>
<extensions defaultExtensionNs="com.intellij">
<moduleType id="JAVA_MODULE" classpathProvider="true" implementationClass="com.intellij.openapi.module.JavaModuleType"/>

View File

@@ -66,7 +66,8 @@ class JavaPluginLayout {
"intellij.jsp.spi",
"intellij.java.uast",
"intellij.java.structuralSearch",
"intellij.java.typeMigration"
"intellij.java.typeMigration",
"intellij.java.featuresTrainer",
].each {
withModule(it, "java-impl.jar", "java_resources_en.jar")
}