Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2015-07-16 14:50:08 +03:00
22 changed files with 471 additions and 702 deletions
@@ -30,7 +30,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @author peter
*/
public class DefaultLightProjectDescriptor implements LightProjectDescriptor {
public class DefaultLightProjectDescriptor extends LightProjectDescriptor {
@NotNull
@Override
public ModuleType getModuleType() {
@@ -53,7 +53,6 @@ import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl;
import com.intellij.openapi.module.EmptyModuleType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.project.ModuleAdapter;
import com.intellij.openapi.project.Project;
@@ -61,18 +60,19 @@ import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.encoding.EncodingManagerImpl;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl;
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl;
@@ -92,19 +92,17 @@ import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl;
import com.intellij.psi.templateLanguages.TemplateDataLanguageMappings;
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
import com.intellij.util.Consumer;
import com.intellij.util.GCUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.IndexableFileSet;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import gnu.trove.THashMap;
import junit.framework.TestCase;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
@@ -119,8 +117,6 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import static com.intellij.openapi.roots.ModuleRootModificationUtil.updateModel;
/**
* @author yole
*/
@@ -228,11 +224,6 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
((PersistentFSImpl)PersistentFS.getInstance()).cleanPersistedContents();
}
public static boolean isLight(@NotNull Project project) {
String creationPlace = project.getUserData(CREATION_PLACE);
return creationPlace != null && StringUtil.startsWith(creationPlace, LIGHT_PROJECT_MARK);
}
private static void initProject(@NotNull final LightProjectDescriptor descriptor) throws Exception {
ourProjectDescriptor = descriptor;
@@ -261,78 +252,10 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
registerShutdownHook();
}
ourPsiManager = null;
ourModule = createMainModule(descriptor.getModuleType());
if (descriptor instanceof LightProjectDescriptorEx) {
((LightProjectDescriptorEx)descriptor).setupModule(ourModule);
if(!((LightProjectDescriptorEx)descriptor).shouldConfigureModule()) return;
}
VirtualFile dummyRoot = VirtualFileManager.getInstance().findFileByUrl("temp:///");
assert dummyRoot != null;
dummyRoot.refresh(false, false);
try {
ourSourceRoot = dummyRoot.createChildDirectory(this, "src");
cleanSourceRoot();
}
catch (IOException e) {
throw new RuntimeException(e);
}
final IndexableFileSet indexableFileSet = new IndexableFileSet() {
@Override
public boolean isInSet(@NotNull final VirtualFile file) {
return ourSourceRoot != null &&
file.getFileSystem() == ourSourceRoot.getFileSystem() &&
ourProject != null &&
ourProject.isOpen();
}
@Override
public void iterateIndexableFilesIn(@NotNull final VirtualFile file, @NotNull final ContentIterator iterator) {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
iterator.processFile(file);
return true;
}
});
}
};
FileBasedIndex.getInstance().registerIndexableSet(indexableFileSet, null);
Disposer.register(ourProject, new Disposable() {
@Override
public void dispose() {
FileBasedIndex.getInstance().removeIndexableSet(indexableFileSet);
}
});
updateModel(ourModule, new Consumer<ModifiableRootModel>() {
@Override
public void consume(ModifiableRootModel model) {
final Sdk sdk = descriptor.getSdk();
if (sdk != null) {
model.setSdk(sdk);
}
ContentEntry contentEntry = model.addContentEntry(ourSourceRoot);
contentEntry.addSourceFolder(ourSourceRoot, false);
descriptor.configureModule(ourModule, model, contentEntry);
}
});
}
private void cleanSourceRoot() throws IOException {
TempFileSystem tempFs = (TempFileSystem)ourSourceRoot.getFileSystem();
for (VirtualFile child : ourSourceRoot.getChildren()) {
if (!tempFs.exists(child)) {
tempFs.createChildFile(this, ourSourceRoot, child.getName());
}
child.delete(this);
}
LightProjectDescriptor.ProjectInfo projectInfo = ourProjectDescriptor.setUpProject(ourProject);
ourModule = projectInfo.module;
ourSourceRoot = projectInfo.moduleSourcesRoot;
}
}.execute().throwException();
@@ -340,15 +263,6 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).storePointers();
}
@NotNull
protected static Module createMainModule(@NotNull final ModuleType moduleType) {
return ApplicationManager.getApplication().runWriteAction(new Computable<Module>() {
@Override
public Module compute() {
return ModuleManager.getInstance(ourProject).newModule("light_idea_test_case.iml", moduleType.getId());
}
});
}
/**
* @return The only source root
@@ -838,11 +752,11 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
});
}
private static class SimpleLightProjectDescriptor implements LightProjectDescriptor {
private static class SimpleLightProjectDescriptor extends LightProjectDescriptor {
@NotNull private final ModuleType myModuleType;
private final Sdk mySdk;
@Nullable private final Sdk mySdk;
SimpleLightProjectDescriptor(@NotNull ModuleType moduleType, Sdk sdk) {
SimpleLightProjectDescriptor(@NotNull ModuleType moduleType, @Nullable Sdk sdk) {
myModuleType = moduleType;
mySdk = sdk;
}
@@ -853,15 +767,12 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da
return myModuleType;
}
@Nullable
@Override
public Sdk getSdk() {
return mySdk;
}
@Override
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -15,39 +15,144 @@
*/
package com.intellij.testFramework;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.EmptyModuleType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
import com.intellij.util.Consumer;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.IndexableFileSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import static com.intellij.openapi.roots.ModuleRootModificationUtil.updateModel;
public class LightProjectDescriptor {
public static final LightProjectDescriptor EMPTY_PROJECT_DESCRIPTOR = new LightProjectDescriptor();
/**
* @author yole
*/
public interface LightProjectDescriptor {
@NotNull
ModuleType getModuleType();
Sdk getSdk();
void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry);
public ProjectInfo setUpProject(@NotNull Project project) throws Exception {
Module module = createMainModule(project);
VirtualFile contentRoot = createSourcesRoot(module);
return new ProjectInfo(module, contentRoot);
}
class Empty implements LightProjectDescriptor {
@NotNull
@Override
public ModuleType getModuleType() {
return EmptyModuleType.getInstance();
@NotNull
public Module createMainModule(@NotNull final Project project) {
return ApplicationManager.getApplication().runWriteAction(new Computable<Module>() {
@Override
public Module compute() {
return ModuleManager.getInstance(project).newModule("light_idea_test_case.iml", getModuleType().getId());
}
});
}
@NotNull
public ModuleType getModuleType() {
return EmptyModuleType.getInstance();
}
@Nullable
public VirtualFile createSourcesRoot(@NotNull final Module module) {
VirtualFile dummyRoot = VirtualFileManager.getInstance().findFileByUrl("temp:///");
assert dummyRoot != null;
dummyRoot.refresh(false, false);
final VirtualFile srcRoot;
try {
srcRoot = dummyRoot.createChildDirectory(this, "src");
cleanSourceRoot(srcRoot);
}
catch (IOException e) {
throw new RuntimeException(e);
}
@Override
public Sdk getSdk() {
return null;
}
final IndexableFileSet indexableFileSet = new IndexableFileSet() {
@Override
public boolean isInSet(@NotNull final VirtualFile file) {
return file.getFileSystem() == srcRoot.getFileSystem() &&
module.getProject().isOpen();
}
@Override
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
@Override
public void iterateIndexableFilesIn(@NotNull final VirtualFile file, @NotNull final ContentIterator iterator) {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
iterator.processFile(file);
return true;
}
});
}
};
FileBasedIndex.getInstance().registerIndexableSet(indexableFileSet, null);
Disposer.register(module.getProject(), new Disposable() {
@Override
public void dispose() {
FileBasedIndex.getInstance().removeIndexableSet(indexableFileSet);
}
});
updateModel(module, new Consumer<ModifiableRootModel>() {
@Override
public void consume(ModifiableRootModel model) {
Sdk sdk = getSdk();
if (sdk != null) {
model.setSdk(sdk);
}
ContentEntry contentEntry = model.addContentEntry(srcRoot);
contentEntry.addSourceFolder(srcRoot, false);
configureModule(module, model, contentEntry);
}
});
return srcRoot;
}
@Nullable
public Sdk getSdk() {
return null;
}
private void cleanSourceRoot(@NotNull VirtualFile contentRoot) throws IOException {
TempFileSystem tempFs = (TempFileSystem)contentRoot.getFileSystem();
for (VirtualFile child : contentRoot.getChildren()) {
if (!tempFs.exists(child)) {
tempFs.createChildFile(this, contentRoot, child.getName());
}
child.delete(this);
}
}
LightProjectDescriptor EMPTY_PROJECT_DESCRIPTOR = new Empty();
protected void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
}
public static class ProjectInfo {
@NotNull public final Module module;
@Nullable public final VirtualFile moduleSourcesRoot;
public ProjectInfo(@NotNull Module module, @Nullable VirtualFile moduleSourcesRoot) {
this.module = module;
this.moduleSourcesRoot = moduleSourcesRoot;
}
}
}
@@ -1,24 +0,0 @@
/*
* Copyright 2000-2015 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 com.intellij.testFramework;
import com.intellij.openapi.module.Module;
public interface LightProjectDescriptorEx extends LightProjectDescriptor {
boolean shouldConfigureModule();
void setupModule(Module module);
}
@@ -50,9 +50,9 @@
description="Navigate to the next answer holder">
</action>
<action id="PreviousTaskAction" class="com.jetbrains.edu.learning.actions.StudyPreviousStudyTaskAction" text="Previous Task"
description="Navigate to previous task"/>
description="Navigate to the previous task"/>
<action id="NextTaskAction" class="com.jetbrains.edu.learning.actions.StudyNextStudyTaskAction" text="Next Task"
description="Navigate to next task"/>
description="Navigate to the next task"/>
<action id="RefreshTaskAction" class="com.jetbrains.edu.learning.actions.StudyRefreshTaskFileAction" text="Reset Task File"
description="Refresh current task"/>
<action id="WatchInputAction" class="com.jetbrains.edu.learning.actions.StudyEditInputAction" text="Watch Test Input"
@@ -65,7 +65,7 @@
</actions>
<extensions defaultExtensionNs="com.intellij">
<toolWindow id="Course Description" anchor="right" factoryClass="com.jetbrains.edu.learning.ui.StudyToolWindowFactory" conditionClass="com.jetbrains.edu.learning.ui.StudyCondition"/>
<toolWindow id="Task Description" anchor="right" factoryClass="com.jetbrains.edu.learning.ui.StudyToolWindowFactory" conditionClass="com.jetbrains.edu.learning.ui.StudyCondition"/>
<fileEditorProvider implementation="com.jetbrains.edu.learning.editor.StudyFileEditorProvider"/>
<treeStructureProvider implementation="com.jetbrains.edu.learning.projectView.StudyTreeStructureProvider"/>
<applicationService serviceInterface="com.intellij.openapi.fileEditor.impl.EditorEmptyTextPainter"
@@ -33,7 +33,6 @@ import com.jetbrains.edu.courseFormat.Task;
import com.jetbrains.edu.courseFormat.TaskFile;
import com.jetbrains.edu.learning.actions.*;
import com.jetbrains.edu.learning.editor.StudyEditorFactoryListener;
import com.jetbrains.edu.learning.ui.StudyCondition;
import com.jetbrains.edu.learning.ui.StudyToolWindowFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -41,7 +40,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -134,19 +132,9 @@ public class StudyProjectComponent implements ProjectComponent {
}
private void registerToolWindow(@NotNull final ToolWindowManager toolWindowManager) {
try {
Method method = toolWindowManager.getClass().getDeclaredMethod("registerToolWindow", String.class,
JComponent.class,
ToolWindowAnchor.class,
boolean.class, boolean.class, boolean.class);
method.setAccessible(true);
method.invoke(toolWindowManager, StudyToolWindowFactory.STUDY_TOOL_WINDOW, null, ToolWindowAnchor.LEFT, true, true, true);
}
catch (Exception e) {
final ToolWindow toolWindow = toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
if (toolWindow == null) {
toolWindowManager.registerToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW, true, ToolWindowAnchor.RIGHT, myProject, true);
}
final ToolWindow toolWindow = toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
if (toolWindow == null) {
toolWindowManager.registerToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW, true, ToolWindowAnchor.RIGHT, myProject, true);
}
}
@@ -218,8 +206,6 @@ public class StudyProjectComponent implements ProjectComponent {
@Override
public void projectClosed() {
//noinspection AssignmentToStaticFieldFromInstanceMethod
StudyCondition.VALUE = false;
final Course course = StudyTaskManager.getInstance(myProject).getCourse();
if (course != null) {
ToolWindowManager.getInstance(myProject).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW).getContentManager()
@@ -6,13 +6,17 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.impl.DocumentImpl;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.ui.popup.Balloon;
@@ -21,6 +25,7 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.ui.JBColor;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.edu.EduAnswerPlaceholderDeleteHandler;
import com.jetbrains.edu.EduAnswerPlaceholderPainter;
@@ -34,7 +39,7 @@ import com.jetbrains.edu.learning.ui.StudyToolWindowFactory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.Collection;
import java.util.List;
@@ -181,13 +186,22 @@ public class StudyUtils {
* shows pop up in the center of "check task" button in study editor
*/
public static void showCheckPopUp(@NotNull final Project project, @NotNull final Balloon balloon) {
final StudyEditor studyEditor = StudyEditor.getSelectedStudyEditor(project);
final StudyEditor studyEditor = getSelectedStudyEditor(project);
assert studyEditor != null;
final JButton checkButton = studyEditor.getCheckButton();
balloon.showInCenterOf(checkButton);
balloon.show(computeLocation(studyEditor.getEditor()), Balloon.Position.above);
Disposer.register(project, balloon);
}
public static RelativePoint computeLocation(Editor editor){
final Rectangle visibleRect = editor.getComponent().getVisibleRect();
Point point = new Point(visibleRect.x + visibleRect.width + 10,
visibleRect.y + 10);
return new RelativePoint(editor.getComponent(), point);
}
/**
* returns language manager which contains all the information about language specific file names
*/
@@ -246,4 +260,47 @@ public class StudyUtils {
editor.getColorsScheme().setColor(EditorColors.READONLY_FRAGMENT_BACKGROUND_COLOR, null);
}
@Nullable
public static StudyEditor getSelectedStudyEditor(@NotNull final Project project) {
try {
final FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow().
getSelectedEditor().getSelectedEditorWithProvider().getFirst();
if (fileEditor instanceof StudyEditor) {
return (StudyEditor)fileEditor;
}
}
catch (Exception e) {
return null;
}
return null;
}
@Nullable
public static Editor getSelectedEditor(@NotNull final Project project) {
final StudyEditor studyEditor = getSelectedStudyEditor(project);
if (studyEditor != null) {
return studyEditor.getEditor();
}
return null;
}
public static void deleteGuardedBlocks(@NotNull final Document document) {
if (document instanceof DocumentImpl) {
final DocumentImpl documentImpl = (DocumentImpl)document;
List<RangeMarker> blocks = documentImpl.getGuardedBlocks();
for (final RangeMarker block : blocks) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
document.removeGuardedBlock(block);
}
});
}
});
}
}
}
}
@@ -6,6 +6,7 @@ import com.intellij.execution.process.ProcessOutput;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
@@ -14,6 +15,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.TaskInfo;
@@ -43,9 +45,11 @@ import com.jetbrains.edu.learning.editor.StudyEditor;
import com.jetbrains.edu.learning.navigation.StudyNavigator;
import com.jetbrains.edu.learning.run.StudySmartChecker;
import com.jetbrains.edu.learning.run.StudyTestRunner;
import icons.InteractiveLearningIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.util.List;
@@ -58,6 +62,11 @@ public class StudyCheckAction extends DumbAwareAction {
public static final String ACTION_ID = "CheckAction";
public static final String SHORTCUT = "ctrl alt pressed ENTER";
boolean checkInProgress = false;
public StudyCheckAction() {
super("Check Task (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), null)) + ")", "Check current task", InteractiveLearningIcons.Resolve);
}
private static void flushWindows(@NotNull final Task task, @NotNull final VirtualFile taskDir) {
for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
@@ -115,7 +124,7 @@ public class StudyCheckAction extends DumbAwareAction {
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
@Override
public void run() {
final StudyEditor selectedEditor = StudyEditor.getSelectedStudyEditor(project);
final StudyEditor selectedEditor = StudyUtils.getSelectedStudyEditor(project);
if (selectedEditor == null) return;
final StudyState studyState = new StudyState(selectedEditor);
if (!studyState.isValid()) {
@@ -158,7 +167,7 @@ public class StudyCheckAction extends DumbAwareAction {
if (testProcess == null) {
return;
}
selectedEditor.getCheckButton().setEnabled(false);
checkInProgress = true;
ProgressManager.getInstance().run(getCheckTask(studyState, testRunner, testProcess, project, selectedEditor));
}
});
@@ -202,14 +211,14 @@ public class StudyCheckAction extends DumbAwareAction {
drawAllPlaceholders(project, task, taskDir);
ProjectView.getInstance(project).refresh();
deleteWindowDescriptions(task, taskDir);
selectedEditor.getCheckButton().setEnabled(true);
checkInProgress = false;
}
@Override
public void onCancel() {
taskManager.setStatus(task, statusBeforeCheck);
deleteWindowDescriptions(task, taskDir);
selectedEditor.getCheckButton().setEnabled(true);
checkInProgress = false;
}
@Override
@@ -382,7 +391,6 @@ public class StudyCheckAction extends DumbAwareAction {
StudyUtils.showCheckPopUp(project, balloon);
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getProject();
@@ -390,4 +398,9 @@ public class StudyCheckAction extends DumbAwareAction {
check(project);
}
}
@Override
public void update(AnActionEvent e) {
e.getPresentation().setEnabled(!checkInProgress);
}
}
@@ -29,6 +29,7 @@ import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.courseFormat.UserTest;
import com.jetbrains.edu.learning.editor.StudyEditor;
import com.jetbrains.edu.learning.ui.StudyTestContentPanel;
import icons.InteractiveLearningIcons;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -46,8 +47,12 @@ public class StudyEditInputAction extends DumbAwareAction {
private JBEditorTabs tabbedPane;
private Map<TabInfo, UserTest> myEditableTabs = new HashMap<TabInfo, UserTest>();
public StudyEditInputAction() {
super("Watch Test Input", "Watch test input", InteractiveLearningIcons.WatchInput);
}
public void showInput(final Project project) {
final Editor selectedEditor = StudyEditor.getSelectedEditor(project);
final Editor selectedEditor = StudyUtils.getSelectedEditor(project);
if (selectedEditor != null) {
FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
final VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
@@ -100,7 +105,7 @@ public class StudyEditInputAction extends DumbAwareAction {
.setMovable(true)
.setRequestFocus(true)
.createPopup();
StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project);
StudyEditor selectedStudyEditor = StudyUtils.getSelectedStudyEditor(project);
assert selectedStudyEditor != null;
hint.showInCenterOf(selectedStudyEditor.getComponent());
hint.addListener(new HintClosedListener(currentTask, studyTaskManager));
@@ -219,4 +224,19 @@ public class StudyEditInputAction extends DumbAwareAction {
}
}
}
@Override
public void update(final AnActionEvent e) {
EduUtils.enableAction(e, false);
final Project project = e.getProject();
if (project != null) {
StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
if (studyEditor != null) {
final List<UserTest> userTests = StudyTaskManager.getInstance(project).getUserTests(studyEditor.getTaskFile().getTask());
if (!userTests.isEmpty()) {
EduUtils.enableAction(e, true);
}
}
}
}
}
@@ -1,7 +1,9 @@
package com.jetbrains.edu.learning.actions;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.keymap.KeymapUtil;
import com.jetbrains.edu.courseFormat.Task;
import com.jetbrains.edu.learning.editor.StudyEditor;
import com.jetbrains.edu.learning.navigation.StudyNavigator;
import org.jetbrains.annotations.NotNull;
@@ -12,9 +14,8 @@ public class StudyNextStudyTaskAction extends StudyTaskNavigationAction {
public static final String ACTION_ID = "NextTaskAction";
public static final String SHORTCUT = "ctrl pressed PERIOD";
@Override
protected JButton getButton(@NotNull final StudyEditor selectedStudyEditor) {
return selectedStudyEditor.getNextTaskButton();
public StudyNextStudyTaskAction() {
super("Next Task (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), null)) + ")", "Navigate to the next task", AllIcons.Actions.Forward);
}
@Override
@@ -1,21 +1,22 @@
package com.jetbrains.edu.learning.actions;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.keymap.KeymapUtil;
import com.jetbrains.edu.courseFormat.Task;
import com.jetbrains.edu.learning.editor.StudyEditor;
import com.jetbrains.edu.learning.navigation.StudyNavigator;
import icons.InteractiveLearningIcons;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class StudyPreviousStudyTaskAction extends StudyTaskNavigationAction {
public StudyPreviousStudyTaskAction() {
super("Previous Task (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), null)) + ")", "Navigate to the previous task", InteractiveLearningIcons.Prev);
}
public static final String ACTION_ID = "PreviousTaskAction";
public static final String SHORTCUT = "ctrl pressed COMMA";
@Override
protected JButton getButton(@NotNull final StudyEditor selectedStudyEditor) {
return selectedStudyEditor.getPrevTaskButton();
}
@Override
protected String getNavigationFinishedMessage() {
@@ -1,13 +1,16 @@
package com.jetbrains.edu.learning.actions;
import com.intellij.icons.AllIcons;
import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
@@ -35,6 +38,7 @@ import com.jetbrains.edu.learning.editor.StudyEditor;
import com.jetbrains.edu.learning.navigation.StudyNavigator;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.io.File;
public class StudyRefreshTaskFileAction extends DumbAwareAction {
@@ -42,6 +46,10 @@ public class StudyRefreshTaskFileAction extends DumbAwareAction {
public static final String SHORTCUT = "ctrl shift pressed X";
private static final Logger LOG = Logger.getInstance(StudyRefreshTaskFileAction.class.getName());
public StudyRefreshTaskFileAction() {
super("Reset Task File (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), null)) + ")", "Refresh current task", AllIcons.Actions.Refresh);
}
public static void refresh(@NotNull final Project project) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
@@ -50,7 +58,7 @@ public class StudyRefreshTaskFileAction extends DumbAwareAction {
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
@Override
public void run() {
StudyEditor studyEditor = StudyEditor.getSelectedStudyEditor(project);
StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
StudyState studyState = new StudyState(studyEditor);
if (studyEditor == null || !studyState.isValid()) {
LOG.info("RefreshTaskFileAction was invoked outside of Study Editor");
@@ -101,9 +109,9 @@ public class StudyRefreshTaskFileAction extends DumbAwareAction {
BalloonBuilder balloonBuilder =
JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(text, messageType, null);
final Balloon balloon = balloonBuilder.createBalloon();
StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project);
StudyEditor selectedStudyEditor = StudyUtils.getSelectedStudyEditor(project);
assert selectedStudyEditor != null;
balloon.showInCenterOf(selectedStudyEditor.getRefreshButton());
balloon.show(StudyUtils.computeLocation(selectedStudyEditor.getEditor()), Balloon.Position.above);
Disposer.register(project, balloon);
}
@@ -120,7 +128,7 @@ public class StudyRefreshTaskFileAction extends DumbAwareAction {
@NotNull final Document document,
@NotNull final TaskFile taskFile,
String fileName) {
StudyEditor.deleteGuardedBlocks(document);
StudyUtils.deleteGuardedBlocks(document);
taskFile.setTrackChanges(false);
clearDocument(document);
Task task = taskFile.getTask();
@@ -167,14 +175,14 @@ public class StudyRefreshTaskFileAction extends DumbAwareAction {
@Override
public void update(AnActionEvent event) {
EduUtils.enableAction(event, false);
final Project project = event.getProject();
if (project != null) {
StudyEditor studyEditor = StudyEditor.getSelectedStudyEditor(project);
StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
StudyState studyState = new StudyState(studyEditor);
if (studyState.isValid()) {
EduUtils.enableAction(event, true);
}
}
EduUtils.enableAction(event, false);
}
}
@@ -5,6 +5,7 @@ import com.intellij.execution.RunContentExecutor;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
@@ -14,20 +15,29 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.edu.EduUtils;
import com.jetbrains.edu.courseFormat.Task;
import com.jetbrains.edu.courseFormat.TaskFile;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.courseFormat.UserTest;
import com.jetbrains.edu.learning.editor.StudyEditor;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class StudyRunAction extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(StudyRunAction.class.getName());
public static final String ACTION_ID = "StudyRunAction";
private ProcessHandler myHandler;
public StudyRunAction() {
super("Run File With Tests", "Run your code with tests", AllIcons.General.Run);
}
public void run(@NotNull final Project project) {
if (myHandler != null && !myHandler.isProcessTerminated()) return;
Editor selectedEditor = StudyEditor.getSelectedEditor(project);
Editor selectedEditor = StudyUtils.getSelectedEditor(project);
FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
assert selectedEditor != null;
VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
@@ -79,4 +89,20 @@ public class StudyRunAction extends DumbAwareAction {
run(project);
}
}
@Override
public void update(AnActionEvent e) {
EduUtils.enableAction(e, false);
final Project project = e.getProject();
if (project != null) {
StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
if (studyEditor != null) {
final List<UserTest> userTests = StudyTaskManager.getInstance(project).getUserTests(studyEditor.getTaskFile().getTask());
if (!userTests.isEmpty()) {
EduUtils.enableAction(e, true);
}
}
}
}
}
@@ -3,8 +3,10 @@ package com.jetbrains.edu.learning.actions;
import com.intellij.codeInsight.documentation.DocumentationComponent;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
@@ -18,10 +20,11 @@ import com.jetbrains.edu.courseFormat.Course;
import com.jetbrains.edu.learning.StudyState;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.editor.StudyEditor;
import icons.InteractiveLearningIcons;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class StudyShowHintAction extends DumbAwareAction {
public static final String ACTION_ID = "ShowHintAction";
public static final String SHORTCUT = "ctrl pressed 7";
@@ -29,7 +32,7 @@ public class StudyShowHintAction extends DumbAwareAction {
public static final String HINT_NOT_AVAILABLE = "There is no hint for this answer placeholder";
public StudyShowHintAction() {
super("Show hint", "Show hint", InteractiveLearningIcons.ShowHint);
super("Show hint (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), null)) + ")", "Show hint", InteractiveLearningIcons.ShowHint);
}
public void actionPerformed(@NotNull AnActionEvent e) {
@@ -45,7 +48,7 @@ public class StudyShowHintAction extends DumbAwareAction {
if (course == null) {
return;
}
StudyState studyState = new StudyState(StudyEditor.getSelectedStudyEditor(project));
StudyState studyState = new StudyState(StudyUtils.getSelectedStudyEditor(project));
if (!studyState.isValid()) {
return;
}
@@ -18,8 +18,10 @@ import com.jetbrains.edu.EduNames;
import com.jetbrains.edu.courseFormat.Task;
import com.jetbrains.edu.courseFormat.TaskFile;
import com.jetbrains.edu.learning.StudyState;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.editor.StudyEditor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.TreePath;
@@ -27,8 +29,12 @@ import java.util.Map;
abstract public class StudyTaskNavigationAction extends DumbAwareAction {
public StudyTaskNavigationAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
super(text, description, icon);
}
public void navigateTask(@NotNull final Project project) {
StudyEditor studyEditor = StudyEditor.getSelectedStudyEditor(project);
StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
StudyState studyState = new StudyState(studyEditor);
if (!studyState.isValid()) {
return;
@@ -39,7 +45,7 @@ abstract public class StudyTaskNavigationAction extends DumbAwareAction {
JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(getNavigationFinishedMessage(), MessageType.INFO, null);
Balloon balloon = balloonBuilder.createBalloon();
assert studyEditor != null;
balloon.showInCenterOf(getButton(studyEditor));
balloon.show(StudyUtils.computeLocation(studyEditor.getEditor()), Balloon.Position.above);
return;
}
for (VirtualFile file : FileEditorManager.getInstance(project).getOpenFiles()) {
@@ -90,8 +96,6 @@ abstract public class StudyTaskNavigationAction extends DumbAwareAction {
}
}
protected abstract JButton getButton(@NotNull final StudyEditor selectedStudyEditor);
@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
@@ -9,7 +9,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.edu.courseFormat.AnswerPlaceholder;
import com.jetbrains.edu.courseFormat.TaskFile;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.editor.StudyEditor;
import com.jetbrains.edu.learning.navigation.StudyNavigator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -23,7 +22,7 @@ abstract public class StudyWindowNavigationAction extends DumbAwareAction {
}
private void navigateToPlaceholder(@NotNull final Project project) {
final Editor selectedEditor = StudyEditor.getSelectedEditor(project);
final Editor selectedEditor = StudyUtils.getSelectedEditor(project);
if (selectedEditor != null) {
final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
final VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
@@ -1,405 +1,38 @@
package com.jetbrains.edu.learning.editor;
import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
import com.intellij.icons.AllIcons;
import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.impl.DocumentImpl;
import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl;
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.pom.Navigatable;
import com.intellij.ui.BrowserHyperlinkListener;
import com.intellij.ui.HideableTitledPanel;
import com.intellij.ui.JBColor;
import com.intellij.util.ui.EmptyClipboardOwner;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.edu.EduDocumentListener;
import com.jetbrains.edu.courseFormat.Task;
import com.jetbrains.edu.courseFormat.TaskFile;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.actions.*;
import com.jetbrains.edu.learning.courseFormat.UserTest;
import icons.InteractiveLearningIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Implementation of StudyEditor which has panel with special buttons and task text
* also @see {@link StudyFileEditorProvider}
*/
public class StudyEditor implements TextEditor {
private static final String TASK_TEXT_HEADER = "Task Text";
private final FileEditor myDefaultEditor;
private final JComponent myComponent;
public class StudyEditor extends PsiAwareTextEditorImpl {
private final TaskFile myTaskFile;
private JButton myCheckButton;
private JButton myNextTaskButton;
private JButton myPrevTaskButton;
private JButton myRefreshButton;
private static final Map<Document, EduDocumentListener> myDocumentListeners = new HashMap<Document, EduDocumentListener>();
private final Project myProject;
public JButton getCheckButton() {
return myCheckButton;
}
public JButton getPrevTaskButton() {
return myPrevTaskButton;
}
public TaskFile getTaskFile() {
return myTaskFile;
}
private static JButton addButton(@NotNull final JComponent parentComponent, @NotNull final String actionID,
@NotNull final Icon icon, @Nullable String defaultShortcutString) {
final AnAction action = ActionManager.getInstance().getAction(actionID);
String toolTipText = KeymapUtil.createTooltipText(action.getTemplatePresentation().getText(), action);
if (!toolTipText.contains("(") && defaultShortcutString != null) {
KeyboardShortcut shortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(defaultShortcutString), null);
toolTipText += " (" + KeymapUtil.getShortcutText(shortcut) + ")";
}
final JButton newButton = new JButton();
newButton.setToolTipText(toolTipText);
newButton.setIcon(icon);
newButton.setSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
parentComponent.add(newButton);
return newButton;
}
public static void addDocumentListener(@NotNull final Document document, @NotNull final EduDocumentListener listener) {
document.addDocumentListener(listener);
myDocumentListeners.put(document, listener);
}
public StudyEditor(@NotNull final Project project, @NotNull final VirtualFile file) {
myProject = project;
myDefaultEditor = TextEditorProvider.getInstance().createEditor(myProject, file);
myComponent = myDefaultEditor.getComponent();
final JPanel studyPanel = new JPanel();
studyPanel.setLayout(new BoxLayout(studyPanel, BoxLayout.Y_AXIS));
super(project, file, TextEditorProvider.getInstance());
myTaskFile = StudyUtils.getTaskFile(project, file);
if (myTaskFile != null) {
final Task currentTask = myTaskFile.getTask();
final String taskText = currentTask.getText();
//initializeTaskText(studyPanel, taskText);
final JPanel studyButtonPanel = new JPanel(new GridLayout(1, 2));
final JPanel taskActionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
studyButtonPanel.add(taskActionsPanel);
studyButtonPanel.add(new JPanel());
initializeButtons(taskActionsPanel, myTaskFile);
studyPanel.add(studyButtonPanel);
myComponent.add(studyPanel, BorderLayout.NORTH);
}
}
class CopyListener extends MouseAdapter {
final JTextPane myTextPane;
public CopyListener(@NotNull final JTextPane textPane) {
myTextPane = textPane;
}
@Override
public void mouseReleased(MouseEvent e) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
final ToolWindow projectView = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PROJECT_VIEW);
if (projectView == null) {
return;
}
final Component focusComponent = projectView.getComponent();
IdeFocusManager.getInstance(myProject).requestFocus(focusComponent, true);
final String text = myTextPane.getSelectedText();
if (text == null) {
return;
}
KeyAdapter keyAdapter = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent ev) {
if (ev.getKeyCode() == KeyEvent.VK_C
&& ev.getModifiers() == InputEvent.CTRL_MASK) {
final StringSelection selection = new StringSelection(text);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, EmptyClipboardOwner.INSTANCE);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
IdeFocusManager.getInstance(myProject).requestFocus(myDefaultEditor.getComponent(), true);
}
});
}
}
};
focusComponent.addKeyListener(keyAdapter);
}
});
}
}
private void initializeTaskText(@NotNull final JPanel studyPanel, @Nullable final String taskText) {
final JTextPane taskTextPane = new JTextPane();
taskTextPane.addMouseListener(new CopyListener(taskTextPane));
taskTextPane.setContentType("text/html");
taskTextPane.setEditable(false);
taskTextPane.setText(taskText);
taskTextPane.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE);
final EditorColorsScheme editorColorsScheme = EditorColorsManager.getInstance().getGlobalScheme();
int fontSize = editorColorsScheme.getEditorFontSize();
final String fontName = editorColorsScheme.getEditorFontName();
setJTextPaneFont(taskTextPane, new Font(fontName, Font.PLAIN, fontSize));
taskTextPane.setBackground(UIUtil.getPanelBackground());
taskTextPane.setBorder(new EmptyBorder(15, 20, 0, 100));
final HideableTitledPanel taskTextPanel = new HideableTitledPanel(TASK_TEXT_HEADER, taskTextPane, true);
taskTextPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
studyPanel.add(taskTextPanel);
}
private static void setJTextPaneFont(@NotNull final JTextPane textPane, @NotNull final Font font) {
final MutableAttributeSet attrs = textPane.getInputAttributes();
StyleConstants.setFontFamily(attrs, font.getFamily());
StyleConstants.setFontSize(attrs, font.getSize());
StyleConstants.setItalic(attrs, (font.getStyle() & Font.ITALIC) != 0);
StyleConstants.setBold(attrs, (font.getStyle() & Font.BOLD) != 0);
StyleConstants.setForeground(attrs, JBColor.BLACK);
StyledDocument doc = textPane.getStyledDocument();
doc.setCharacterAttributes(0, doc.getLength() + 1, attrs, false);
}
private void initializeButtons(@NotNull final JPanel taskActionsPanel, @NotNull final TaskFile taskFile) {
myCheckButton = addButton(taskActionsPanel, StudyCheckAction.ACTION_ID, InteractiveLearningIcons.Resolve, StudyCheckAction.SHORTCUT);
myPrevTaskButton = addButton(taskActionsPanel, StudyPreviousStudyTaskAction.ACTION_ID, InteractiveLearningIcons.Prev, StudyPreviousStudyTaskAction.SHORTCUT);
myNextTaskButton = addButton(taskActionsPanel, StudyNextStudyTaskAction.ACTION_ID, AllIcons.Actions.Forward, StudyNextStudyTaskAction.SHORTCUT);
myRefreshButton = addButton(taskActionsPanel, StudyRefreshTaskFileAction.ACTION_ID, AllIcons.Actions.Refresh, StudyRefreshTaskFileAction.SHORTCUT);
final JButton myShowHintButton = addButton(taskActionsPanel, StudyShowHintAction.ACTION_ID, InteractiveLearningIcons.ShowHint, StudyShowHintAction.SHORTCUT);
final List<UserTest> userTests = StudyTaskManager.getInstance(myProject).getUserTests(taskFile.getTask());
if (!userTests.isEmpty()) {
final JButton runButton = addButton(taskActionsPanel, StudyRunAction.ACTION_ID, AllIcons.General.Run, null);
runButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StudyRunAction studyRunAction = (StudyRunAction)ActionManager.getInstance().getAction("StudyRunAction");
studyRunAction.run(myProject);
}
});
final JButton watchInputButton = addButton(taskActionsPanel, "WatchInputAction", InteractiveLearningIcons.WatchInput, null);
watchInputButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StudyEditInputAction studyEditInputAction =
(StudyEditInputAction)ActionManager.getInstance().getAction("WatchInputAction");
studyEditInputAction.showInput(myProject);
}
});
}
initializeButtonActions(myShowHintButton);
}
protected void initializeButtonActions(JButton myShowHintButton) {
myCheckButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StudyCheckAction studyCheckAction = (StudyCheckAction)ActionManager.getInstance().getAction("CheckAction");
studyCheckAction.check(myProject);
}
});
myNextTaskButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StudyNextStudyTaskAction studyNextTaskAction =
(StudyNextStudyTaskAction)ActionManager.getInstance().getAction("NextTaskAction");
studyNextTaskAction.navigateTask(myProject);
}
});
myPrevTaskButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StudyPreviousStudyTaskAction
prevTaskAction = (StudyPreviousStudyTaskAction)ActionManager.getInstance().getAction("PreviousTaskAction");
prevTaskAction.navigateTask(myProject);
}
});
myRefreshButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StudyRefreshTaskFileAction.refresh(myProject);
}
});
myShowHintButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
StudyShowHintAction.showHint(myProject);
}
});
}
public JButton getNextTaskButton() {
return myNextTaskButton;
}
public JButton getRefreshButton() {
return myRefreshButton;
}
private FileEditor getDefaultEditor() {
return myDefaultEditor;
}
@NotNull
@Override
public JComponent getComponent() {
return myComponent;
}
@Nullable
@Override
public JComponent getPreferredFocusedComponent() {
return myDefaultEditor.getPreferredFocusedComponent();
}
@NotNull
@Override
public String getName() {
return "Study Editor";
}
@NotNull
@Override
public FileEditorState getState(@NotNull FileEditorStateLevel level) {
return myDefaultEditor.getState(level);
}
@Override
public void setState(@NotNull FileEditorState state) {
myDefaultEditor.setState(state);
}
@Override
public boolean isModified() {
return myDefaultEditor.isModified();
}
@Override
public boolean isValid() {
return myDefaultEditor.isValid();
}
@Override
public void selectNotify() {
myDefaultEditor.selectNotify();
}
@Override
public void deselectNotify() {
myDefaultEditor.deselectNotify();
}
@Override
public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {
myDefaultEditor.addPropertyChangeListener(listener);
}
@Override
public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {
myDefaultEditor.removePropertyChangeListener(listener);
}
@Nullable
@Override
public BackgroundEditorHighlighter getBackgroundHighlighter() {
return myDefaultEditor.getBackgroundHighlighter();
}
@Nullable
@Override
public FileEditorLocation getCurrentLocation() {
return myDefaultEditor.getCurrentLocation();
}
@Nullable
@Override
public StructureViewBuilder getStructureViewBuilder() {
return myDefaultEditor.getStructureViewBuilder();
}
@Override
public void dispose() {
Disposer.dispose(myDefaultEditor);
}
@Nullable
@Override
public <T> T getUserData(@NotNull Key<T> key) {
return myDefaultEditor.getUserData(key);
}
@Override
public <T> void putUserData(@NotNull Key<T> key, @Nullable T value) {
myDefaultEditor.putUserData(key, value);
}
@Nullable
public static StudyEditor getSelectedStudyEditor(@NotNull final Project project) {
try {
final FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow().
getSelectedEditor().getSelectedEditorWithProvider().getFirst();
if (fileEditor instanceof StudyEditor) {
return (StudyEditor)fileEditor;
}
}
catch (Exception e) {
return null;
}
return null;
}
@Nullable
public static Editor getSelectedEditor(@NotNull final Project project) {
final StudyEditor studyEditor = getSelectedStudyEditor(project);
if (studyEditor != null) {
FileEditor defaultEditor = studyEditor.getDefaultEditor();
if (defaultEditor instanceof PsiAwareTextEditorImpl) {
return ((PsiAwareTextEditorImpl)defaultEditor).getEditor();
}
}
return null;
}
public static void removeListener(Document document) {
@@ -409,48 +42,4 @@ public class StudyEditor implements TextEditor {
}
myDocumentListeners.remove(document);
}
@NotNull
@Override
public Editor getEditor() {
if (myDefaultEditor instanceof TextEditor) {
return ((TextEditor)myDefaultEditor).getEditor();
}
return EditorFactory.getInstance().createViewer(new DocumentImpl(""), myProject);
}
@Override
public boolean canNavigateTo(@NotNull Navigatable navigatable) {
if (myDefaultEditor instanceof TextEditor) {
((TextEditor)myDefaultEditor).canNavigateTo(navigatable);
}
return false;
}
@Override
public void navigateTo(@NotNull Navigatable navigatable) {
if (myDefaultEditor instanceof TextEditor) {
((TextEditor)myDefaultEditor).navigateTo(navigatable);
}
}
public static void deleteGuardedBlocks(@NotNull final Document document) {
if (document instanceof DocumentImpl) {
final DocumentImpl documentImpl = (DocumentImpl)document;
List<RangeMarker> blocks = documentImpl.getGuardedBlocks();
for (final RangeMarker block : blocks) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
document.removeGuardedBlock(block);
}
});
}
});
}
}
}
}
@@ -9,11 +9,14 @@ import com.intellij.openapi.editor.event.EditorFactoryListener;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.problems.WolfTheProblemSolver;
import com.jetbrains.edu.EduDocumentListener;
import com.jetbrains.edu.courseFormat.TaskFile;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.navigation.StudyNavigator;
import com.jetbrains.edu.learning.ui.StudyToolWindowFactory;
import org.jetbrains.annotations.NotNull;
@@ -43,6 +46,13 @@ public class StudyEditorFactoryListener implements EditorFactoryListener {
StudyEditor.addDocumentListener(document, new EduDocumentListener(taskFile));
WolfTheProblemSolver.getInstance(project).clearProblems(openedFile);
StudyUtils.drawAllWindows(editor, taskFile);
final ToolWindow studyToolWindow = ToolWindowManager.getInstance(project).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
if (studyToolWindow != null) {
StudyUtils.updateStudyToolWindow(project);
studyToolWindow.show(null);
}
}
}
}
@@ -1,26 +1,15 @@
package com.jetbrains.edu.learning.ui;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.jetbrains.edu.learning.StudyTaskManager;
/**
* author: liana
* data: 7/29/14.
*/
public class StudyCondition implements Condition, DumbAware {
public static boolean VALUE = false;
@Override
public boolean value(Object o) {
if (o instanceof Project) {
Project project = (Project) o;
StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
if (taskManager.getCourse() != null) {
//noinspection AssignmentToStaticFieldFromInstanceMethod
VALUE = true;
}
}
return false;
}
}
@@ -0,0 +1,136 @@
/*
* Copyright 2000-2015 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 com.jetbrains.edu.learning.ui;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionToolbar;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.SimpleToolWindowPanel;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.BrowserHyperlinkListener;
import com.intellij.util.ui.JBUI;
import com.jetbrains.edu.courseFormat.Task;
import com.jetbrains.edu.courseFormat.TaskFile;
import com.jetbrains.edu.learning.StudyUtils;
import com.jetbrains.edu.learning.actions.*;
import com.jetbrains.edu.learning.editor.StudyEditor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class StudyToolWindow extends SimpleToolWindowPanel implements DataProvider, Disposable {
public StudyToolWindow(final Project project) {
super(true, true);
JPanel toolbarPanel = createToolbarPanel();
setToolbar(toolbarPanel);
final StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project);
if (studyEditor == null) return;
Task task = studyEditor.getTaskFile().getTask();
if (task != null) {
final String taskText = task.getText();
final JTextPane taskTextPane = new JTextPane();
taskTextPane.setContentType("text/html");
taskTextPane.setEditable(false);
taskTextPane.setText(taskText);
taskTextPane.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE);
taskTextPane.setBackground(EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground());
taskTextPane.setBorder(new EmptyBorder(15, 20, 0, 100));
setContent(taskTextPane);
final FileEditorManagerListener listener = new StudyFileEditorManagerListener(project, taskTextPane);
project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, listener);
}
}
public void dispose() {
}
private static JPanel createToolbarPanel() {
final DefaultActionGroup group = new DefaultActionGroup();
group.add(new StudyCheckAction());
group.add(new StudyPreviousStudyTaskAction());
group.add(new StudyNextStudyTaskAction());
group.add(new StudyRefreshTaskFileAction());
group.add(new StudyShowHintAction());
group.add(new StudyRunAction());
group.add(new StudyEditInputAction());
final ActionToolbar actionToolBar = ActionManager.getInstance().createActionToolbar("Study", group, true);
return JBUI.Panels.simplePanel(actionToolBar.getComponent());
}
static class StudyFileEditorManagerListener implements FileEditorManagerListener {
private Project myProject;
private JTextPane myTaskTextPane;
StudyFileEditorManagerListener(@NotNull final Project project, JTextPane taskTextPane){
myProject = project;
myTaskTextPane = taskTextPane;
}
@Override
public void fileOpened (@NotNull FileEditorManager source, @NotNull VirtualFile file){
Task task = getTask(file);
setTaskText(task);
}
@Override
public void fileClosed (@NotNull FileEditorManager source, @NotNull VirtualFile file){
}
@Override
public void selectionChanged (@NotNull FileEditorManagerEvent event){
VirtualFile file = event.getNewFile();
if (file != null) {
Task task = getTask(file);
setTaskText(task);
}
}
@Nullable
private Task getTask (@NotNull VirtualFile file){
TaskFile taskFile = StudyUtils.getTaskFile(myProject, file);
if (taskFile != null) {
return taskFile.getTask();
}
else {
return null;
}
}
private void setTaskText(@Nullable final Task task) {
if (task == null) {
return;
}
String text = task.getText();
myTaskTextPane.setText(text);
}
}
}
@@ -2,90 +2,31 @@ package com.jetbrains.edu.learning.ui;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowFactory;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.util.ui.UIUtil;
import com.intellij.ui.content.ContentManager;
import com.jetbrains.edu.courseFormat.Course;
import com.jetbrains.edu.courseFormat.Lesson;
import com.jetbrains.edu.courseFormat.Task;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.courseFormat.StudyStatus;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.List;
public class StudyToolWindowFactory implements ToolWindowFactory, DumbAware {
public static final String STUDY_TOOL_WINDOW = "Course Description";
public static final String STUDY_TOOL_WINDOW = "Task Description";
@Override
public void createToolWindowContent(@NotNull final Project project, @NotNull final ToolWindow toolWindow) {
JPanel contentPanel = new JPanel();
StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
if (taskManager.getCourse() != null) {
contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.PAGE_AXIS));
contentPanel.add(Box.createRigidArea(new Dimension(10, 0)));
final Course course = taskManager.getCourse();
if (course != null) {
final StudyToolWindow studyToolWindow = new StudyToolWindow(project);
final ContentManager contentManager = toolWindow.getContentManager();
final Content content = contentManager.getFactory().createContent(studyToolWindow, null, false);
contentManager.addContent(content);
Disposer.register(project, studyToolWindow);
Course course = taskManager.getCourse();
if (course == null) {
return;
}
String courseName = UIUtil.toHtml("<h1>" + course.getName() + "</h1>", 10);
String description = UIUtil.toHtml(course.getDescription(), 5);
String authorLabel = UIUtil.toHtml("<b>Author: </b>" + Course.getAuthorsString(course.getAuthors()), 5);
contentPanel.add(new JLabel(courseName));
contentPanel.add(new JLabel(authorLabel));
contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
contentPanel.add(new JLabel(description));
contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
int taskNum = 0;
int taskSolved = 0;
int lessonsCompleted = 0;
List<Lesson> lessons = course.getLessons();
for (Lesson lesson : lessons) {
StudyStatus status = taskManager.getStatus(lesson);
if (status == StudyStatus.Solved) {
lessonsCompleted++;
}
taskNum += lesson.getTaskList().size();
taskSolved += getSolvedTasks(lesson, taskManager);
}
String completedLessons = String.format("%d of %d lessons completed", lessonsCompleted, course.getLessons().size());
String completedTasks = String.format("%d of %d tasks completed", taskSolved, taskNum);
String tasksLeft = String.format("%d of %d tasks left", taskNum - taskSolved, taskNum);
contentPanel.add(Box.createVerticalStrut(10));
addStatistics(completedLessons, contentPanel);
addStatistics(completedTasks, contentPanel);
double percent = (taskSolved * 100.0) / taskNum;
contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
StudyProgressBar studyProgressBar = new StudyProgressBar(percent / 100, 40, 10);
contentPanel.add(studyProgressBar);
addStatistics(tasksLeft, contentPanel);
ContentFactory contentFactory = ContentFactory.SERVICE.getInstance();
Content content = contentFactory.createContent(contentPanel, "", true);
toolWindow.getContentManager().addContent(content);
}
}
private static int getSolvedTasks(@NotNull final Lesson lesson, StudyTaskManager taskManager) {
int solved = 0;
for (Task task : lesson.getTaskList()) {
if (taskManager.getStatus(task) == StudyStatus.Solved) {
solved += 1;
}
}
return solved;
}
private static void addStatistics(String statistics, JPanel contentPanel) {
String labelText = UIUtil.toHtml(statistics, 5);
contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
JLabel statisticLabel = new JLabel(labelText);
contentPanel.add(statisticLabel);
}
}
@@ -16,10 +16,8 @@
package com.jetbrains.python.fixtures;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
@@ -34,7 +32,7 @@ import org.jetbrains.annotations.NotNull;
* Project descriptor (extracted from {@link com.jetbrains.python.fixtures.PyTestCase}) and should be used with it.
* @author Ilya.Kazakevich
*/
public class PyLightProjectDescriptor implements LightProjectDescriptor {
public class PyLightProjectDescriptor extends LightProjectDescriptor {
private final String myPythonVersion;
public PyLightProjectDescriptor(String pythonVersion) {
@@ -52,10 +50,6 @@ public class PyLightProjectDescriptor implements LightProjectDescriptor {
return PythonMockSdk.findOrCreate(myPythonVersion);
}
@Override
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
}
protected void createLibrary(ModifiableRootModel model, final String name, final String path) {
final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary(name).getModifiableModel();
final VirtualFile home =