From 2a13b129d6c1cbab0f55b6fe05e35efef10570e2 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Tue, 22 Mar 2016 14:15:15 +0300 Subject: [PATCH 01/65] new editing mode for task description panel --- .../resources/META-INF/plugin.xml | 3 + .../coursecreator/CCStudyActionsProvider.java | 12 ++ .../actions/CCEditTaskTextAction.java | 81 ++++++++++++ .../student/resources/META-INF/plugin.xml | 1 + .../edu/learning/StudyActionsProvider.java | 10 ++ .../learning/StudyBasePluginConfigurator.java | 9 +- .../edu/learning/StudyProjectComponent.java | 10 +- .../edu/learning/StudyTaskManager.java | 20 +++ .../jetbrains/edu/learning/StudyUtils.java | 28 ++-- ...tion.java => StudyActionWithShortcut.java} | 9 +- .../learning/actions/StudyCheckAction.java | 2 +- .../actions/StudyRefreshTaskFileAction.java | 2 +- .../learning/actions/StudyShowHintAction.java | 2 +- .../actions/StudyTaskNavigationAction.java | 2 +- .../actions/StudyWindowNavigationAction.java | 2 +- .../learning/ui/StudyJavaFxToolWindow.java | 5 +- .../edu/learning/ui/StudySwingToolWindow.java | 5 +- .../edu/learning/ui/StudyToolWindow.java | 120 +++++++++++++++--- python/educational-core/student/student.iml | 1 + .../coursecreator/PyCCProjectGenerator.java | 5 + 20 files changed, 273 insertions(+), 56 deletions(-) create mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionsProvider.java create mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java create mode 100644 python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionsProvider.java rename python/educational-core/student/src/com/jetbrains/edu/learning/actions/{StudyToolbarAction.java => StudyActionWithShortcut.java} (58%) diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index 131d9f5b46d8..24da17d3f29c 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -24,6 +24,9 @@ + + + diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionsProvider.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionsProvider.java new file mode 100644 index 000000000000..7ccdc075ebe3 --- /dev/null +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionsProvider.java @@ -0,0 +1,12 @@ +package com.jetbrains.edu.coursecreator; + +import com.intellij.openapi.actionSystem.AnAction; +import com.jetbrains.edu.coursecreator.actions.CCEditTaskTextAction; +import com.jetbrains.edu.learning.StudyActionsProvider; + +public class CCStudyActionsProvider implements StudyActionsProvider{ + @Override + public AnAction[] getActions() { + return new AnAction[]{new CCEditTaskTextAction()}; + } +} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java new file mode 100644 index 000000000000..a528ba6039b6 --- /dev/null +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java @@ -0,0 +1,81 @@ +package com.jetbrains.edu.coursecreator.actions; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.coursecreator.CCProjectService; +import com.jetbrains.edu.learning.StudyState; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.editor.StudyEditor; +import com.jetbrains.edu.learning.ui.StudyToolWindow; +import org.jetbrains.annotations.NotNull; + +public class CCEditTaskTextAction extends ToggleAction implements DumbAware { + private static final Logger LOG = Logger.getInstance(CCEditTaskTextAction.class); + + public CCEditTaskTextAction() { + super("Editing Mode", "Editing Mode", AllIcons.Modules.Edit); + } + + @Override + public boolean isSelected(AnActionEvent e) { + Project project = e.getProject(); + if (project == null) { + return false; + } + return StudyTaskManager.getInstance(project).getToolWindowMode() == StudyToolWindow.StudyToolWindowMode.EDITING; + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + Project project = e.getProject(); + if (project == null) { + return; + } + StudyToolWindow window = StudyUtils.getStudyToolWindow(project); + if (window == null) { + return; + } + + final StudyEditor selectedEditor = StudyUtils.getSelectedStudyEditor(project); + if (selectedEditor == null) { + StudyTaskManager.getInstance(project).setTurnEditingMode(true); + return; + } + final StudyState studyState = new StudyState(selectedEditor); + VirtualFile taskTextFile = studyState.getTaskDir().findChild(EduNames.TASK_HTML); + if (taskTextFile == null) { + LOG.info("Failed to find task.html"); + return; + } + Document document = FileDocumentManager.getInstance().getDocument(taskTextFile); + if (!state) { + if (document != null) { + FileDocumentManager.getInstance().saveDocument(document); + } + window.leaveEditingMode(project); + return; + } + window.enterEditingMode(taskTextFile, project); + } + + @Override + public void update(@NotNull AnActionEvent e) { + Project project = e.getProject(); + if (project == null) { + return; + } + + if (CCProjectService.getInstance(project).getCourse() == null) { + e.getPresentation().setEnabledAndVisible(false); + } + } +} diff --git a/python/educational-core/student/resources/META-INF/plugin.xml b/python/educational-core/student/resources/META-INF/plugin.xml index 9d5142d93775..68aca8e54232 100644 --- a/python/educational-core/student/resources/META-INF/plugin.xml +++ b/python/educational-core/student/resources/META-INF/plugin.xml @@ -36,6 +36,7 @@ + diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionsProvider.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionsProvider.java new file mode 100644 index 000000000000..4aca599efea7 --- /dev/null +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionsProvider.java @@ -0,0 +1,10 @@ +package com.jetbrains.edu.learning; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.extensions.ExtensionPointName; + +public interface StudyActionsProvider { + ExtensionPointName EP_NAME = ExtensionPointName.create("Edu.studyActionsProvider"); + + AnAction[] getActions(); +} diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java index b269cde639b9..cd204d70c63c 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java @@ -50,9 +50,6 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur public FileEditorManagerListener getFileEditorManagerListener(@NotNull Project project, @NotNull StudyToolWindow toolWindow) { return new FileEditorManagerListener() { - - private static final String EMPTY_TASK_TEXT = "Please, open any task to see task description"; - @Override public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) { Task task = getTask(file); @@ -61,7 +58,7 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur @Override public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) { - toolWindow.setTaskText(EMPTY_TASK_TEXT); + toolWindow.setEmptyText(project); } @Override @@ -87,10 +84,10 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur private void setTaskText(@Nullable final Task task, @Nullable final VirtualFile taskDirectory) { String text = StudyUtils.getTaskTextFromTask(task, taskDirectory); if (text == null) { - toolWindow.setTaskText(EMPTY_TASK_TEXT); + toolWindow.setEmptyText(project); return; } - toolWindow.setTaskText(text); + toolWindow.setTaskText(text, taskDirectory, project); } }; } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java index 9b0d2aea6a8c..81af40c0d894 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java @@ -115,10 +115,12 @@ public class StudyProjectComponent implements ProjectComponent { List actionsOnToolbar = window.getActions(true); if (actionsOnToolbar != null) { for (AnAction action : actionsOnToolbar) { - if (action instanceof StudyToolbarAction) { - String id = ((StudyToolbarAction)action).getActionId(); - String[] shortcuts = ((StudyToolbarAction)action).getShortcuts(); - addShortcut(id, shortcuts); + if (action instanceof StudyActionWithShortcut) { + String id = ((StudyActionWithShortcut)action).getActionId(); + String[] shortcuts = ((StudyActionWithShortcut)action).getShortcuts(); + if (shortcuts != null) { + addShortcut(id, shortcuts); + } } } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java index 6d682f4af732..3a2ffd7d8f66 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTaskManager.java @@ -14,6 +14,7 @@ import com.intellij.util.xmlb.XmlSerializer; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.*; import com.jetbrains.edu.learning.oldCourseFormat.OldCourse; +import com.jetbrains.edu.learning.ui.StudyToolWindow; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +38,9 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb public Map myTaskStatusMap = new HashMap<>(); public Map> myUserTests = new HashMap<>(); public List myInvisibleFiles = new ArrayList<>(); + private StudyToolWindow.StudyToolWindowMode myToolWindowMode = StudyToolWindow.StudyToolWindowMode.TEXT; + private boolean myTurnEditingMode = false; + private StudyTaskManager() { } @@ -250,4 +254,20 @@ public class StudyTaskManager implements PersistentStateComponent, Dumb public boolean isInvisibleFile(String path) { return myInvisibleFiles.contains(path); } + + public StudyToolWindow.StudyToolWindowMode getToolWindowMode() { + return myToolWindowMode; + } + + public void setToolWindowMode(StudyToolWindow.StudyToolWindowMode toolWindowMode) { + myToolWindowMode = toolWindowMode; + } + + public boolean isTurnEditingMode() { + return myTurnEditingMode; + } + + public void setTurnEditingMode(boolean turnEditingMode) { + myTurnEditingMode = turnEditingMode; + } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index 940d94ce6b53..c204f012023f 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -128,7 +128,7 @@ public class StudyUtils { } public static void updateToolWindows(@NotNull final Project project) { - update(project); + updateStudyToolWindow(project); final ToolWindowManager windowManager = ToolWindowManager.getInstance(project); createProgressToolWindowContent(project, windowManager); @@ -461,14 +461,7 @@ public class StudyUtils { } public static String getTaskText(@NotNull final Project project) { - VirtualFile[] files = FileEditorManager.getInstance(project).getSelectedFiles(); - TaskFile taskFile = null; - for (VirtualFile file : files) { - taskFile = getTaskFile(project, file); - if (taskFile != null) { - break; - } - } + TaskFile taskFile = getSelectedTaskFile(project); if (taskFile == null) { return EMPTY_TASK_TEXT; } @@ -479,11 +472,24 @@ public class StudyUtils { return null; } - public static void update(Project project) { + @Nullable + public static TaskFile getSelectedTaskFile(@NotNull Project project) { + VirtualFile[] files = FileEditorManager.getInstance(project).getSelectedFiles(); + TaskFile taskFile = null; + for (VirtualFile file : files) { + taskFile = getTaskFile(project, file); + if (taskFile != null) { + break; + } + } + return taskFile; + } + + public static void updateStudyToolWindow(Project project) { final StudyToolWindow studyToolWindow = getStudyToolWindow(project); if (studyToolWindow != null) { String taskText = getTaskText(project); - studyToolWindow.setTaskText(taskText); + studyToolWindow.setTaskText(taskText, null, project); } } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyToolbarAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyActionWithShortcut.java similarity index 58% rename from python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyToolbarAction.java rename to python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyActionWithShortcut.java index a74e547984ef..ae1fa651031c 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyToolbarAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyActionWithShortcut.java @@ -6,8 +6,9 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; -public abstract class StudyToolbarAction extends DumbAwareAction { - public StudyToolbarAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) { +public abstract class StudyActionWithShortcut extends DumbAwareAction { + + public StudyActionWithShortcut(@Nullable String text, @Nullable String description, @Nullable Icon icon) { super(text, description, icon); } @@ -15,5 +16,5 @@ public abstract class StudyToolbarAction extends DumbAwareAction { public abstract String getActionId(); @Nullable - public abstract String[] getShortcuts(); -} + public abstract String[] getShortcuts(); +} \ No newline at end of file diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java index be3695794db6..5c42608382f1 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java @@ -15,7 +15,7 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; -public abstract class StudyCheckAction extends StudyToolbarAction { +public abstract class StudyCheckAction extends StudyActionWithShortcut { public static final String SHORTCUT = "ctrl alt pressed ENTER"; protected Ref myCheckInProgress = new Ref<>(false); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java index 110feeee370f..2a421abdb131 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java @@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; -public class StudyRefreshTaskFileAction extends StudyToolbarAction { +public class StudyRefreshTaskFileAction extends StudyActionWithShortcut { public static final String ACTION_ID = "RefreshTaskAction"; public static final String SHORTCUT = "ctrl shift pressed X"; private static final Logger LOG = Logger.getInstance(StudyRefreshTaskFileAction.class.getName()); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyShowHintAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyShowHintAction.java index 25642dc0cf87..75a1277c88d9 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyShowHintAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyShowHintAction.java @@ -25,7 +25,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; -public class StudyShowHintAction extends StudyToolbarAction { +public class StudyShowHintAction extends StudyActionWithShortcut { public static final String ACTION_ID = "ShowHintAction"; public static final String SHORTCUT = "ctrl pressed 7"; private static final String ourWarningMessage = "Put the caret in the answer placeholder to get hint"; diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java index 580bc3557d64..308a423d68f6 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyTaskNavigationAction.java @@ -27,7 +27,7 @@ import javax.swing.tree.TreePath; import java.util.Map; -abstract public class StudyTaskNavigationAction extends StudyToolbarAction { +abstract public class StudyTaskNavigationAction extends StudyActionWithShortcut { public StudyTaskNavigationAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) { super(text, description, icon); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyWindowNavigationAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyWindowNavigationAction.java index 50be6069aa36..cd0b5ccf1dbe 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyWindowNavigationAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyWindowNavigationAction.java @@ -16,7 +16,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; -abstract public class StudyWindowNavigationAction extends StudyToolbarAction implements DumbAware { +abstract public class StudyWindowNavigationAction extends StudyActionWithShortcut implements DumbAware { protected StudyWindowNavigationAction(String actionId, String description, Icon icon) { super(actionId, description, icon); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyJavaFxToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyJavaFxToolWindow.java index 98bec3d50589..058bd633a29b 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyJavaFxToolWindow.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyJavaFxToolWindow.java @@ -29,10 +29,9 @@ public class StudyJavaFxToolWindow extends StudyToolWindow { } @Override - public JComponent createTaskInfoPanel(String taskText, Project project) { + public JComponent createTaskInfoPanel(Project project) { myBrowserWindow = new StudyBrowserWindow(true, false); myBrowserWindow.addBackAndOpenButtons(); - myBrowserWindow.loadContent(taskText, StudyUtils.getConfigurator(project)); JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); panel.add(myBrowserWindow.getPanel()); @@ -40,7 +39,7 @@ public class StudyJavaFxToolWindow extends StudyToolWindow { } @Override - public void setTaskText(String text) { + public void setText(String text) { StudyPluginConfigurator configurator = StudyUtils.getConfigurator(ProjectUtil.guessCurrentProject(this)); myBrowserWindow.loadContent(text, configurator); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java index ae4914313f10..4e446b083a6c 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudySwingToolWindow.java @@ -35,7 +35,7 @@ public class StudySwingToolWindow extends StudyToolWindow { } @Override - public JComponent createTaskInfoPanel(String taskText, Project project) { + public JComponent createTaskInfoPanel(Project project) { myTaskTextPane = new JTextPane(); myTaskTextPane.setContentType(new HTMLEditorKit().getContentType()); final EditorColorsScheme editorColorsScheme = EditorColorsManager.getInstance().getGlobalScheme(); @@ -54,12 +54,11 @@ public class StudySwingToolWindow extends StudyToolWindow { myTaskTextPane.setBackground(EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground()); } myTaskTextPane.setBorder(new EmptyBorder(15, 20, 0, 100)); - myTaskTextPane.setText(taskText); myTaskTextPane.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE); return myTaskTextPane; } - public void setTaskText(String text) { + public void setText(String text) { myTaskTextPane.setText(text); } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java index b523ce4af211..96817aa4a794 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java @@ -15,23 +15,27 @@ */ package com.jetbrains.edu.learning.ui; +import com.intellij.ide.browsers.WebBrowserManager; 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.actionSystem.*; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.JBCardLayout; import com.intellij.ui.OnePixelSplitter; import com.intellij.util.ui.JBUI; -import com.jetbrains.edu.learning.StudyBasePluginConfigurator; -import com.jetbrains.edu.learning.StudyPluginConfigurator; -import com.jetbrains.edu.learning.StudyTaskManager; -import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.*; +import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.TaskFile; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -41,6 +45,7 @@ import java.util.Map; public abstract class StudyToolWindow extends SimpleToolWindowPanel implements DataProvider, Disposable { private static final Logger LOG = Logger.getInstance(StudyToolWindow.class); private static final String TASK_INFO_ID = "taskInfo"; + private static final String EMPTY_TASK_TEXT = "Please, open any task to see task description"; private final JBCardLayout myCardLayout; private final JPanel myContentPanel; private final OnePixelSplitter mySplitPane; @@ -49,17 +54,17 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D super(true, true); myCardLayout = new JBCardLayout(); myContentPanel = new JPanel(myCardLayout); - mySplitPane = new OnePixelSplitter(myVertical=true); + mySplitPane = new OnePixelSplitter(myVertical = true); } public void init(Project project) { String taskText = StudyUtils.getTaskText(project); if (taskText == null) return; - JPanel toolbarPanel = createToolbarPanel(project); + JPanel toolbarPanel = createToolbarPanel(getActionGroup(project)); setToolbar(toolbarPanel); - myContentPanel.add(TASK_INFO_ID, createTaskInfoPanel(taskText, project)); + myContentPanel.add(TASK_INFO_ID, createTaskInfoPanel(project)); mySplitPane.setFirstComponent(myContentPanel); addAdditionalPanels(project); myCardLayout.show(myContentPanel, TASK_INFO_ID); @@ -71,6 +76,17 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D final FileEditorManagerListener listener = configurator.getFileEditorManagerListener(project, this); project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, listener); } + + if (StudyTaskManager.getInstance(project).isTurnEditingMode() || StudyTaskManager.getInstance(project).getToolWindowMode() == StudyToolWindowMode.EDITING) { + TaskFile file = StudyUtils.getSelectedTaskFile(project); + if (file != null) { + VirtualFile taskDir = file.getTask().getTaskDir(project); + setTaskText(taskText, taskDir, project); + + } + } else { + setTaskText(taskText, null, project); + } } private void addAdditionalPanels(Project project) { @@ -88,7 +104,7 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D public void dispose() { } - + //used in checkiO plugin. @SuppressWarnings("unused") public void showPanelById(@NotNull final String panelId) { @@ -120,24 +136,25 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D } - public abstract JComponent createTaskInfoPanel(String taskText, Project project); - - private static JPanel createToolbarPanel(@NotNull final Project project) { - final DefaultActionGroup group = getActionGroup(project); + public abstract JComponent createTaskInfoPanel(Project project); + public static JPanel createToolbarPanel(ActionGroup group) { final ActionToolbar actionToolBar = ActionManager.getInstance().createActionToolbar("Study", group, true); return JBUI.Panels.simplePanel(actionToolBar.getComponent()); } - private static DefaultActionGroup getActionGroup(@NotNull final Project project) { + public static DefaultActionGroup getActionGroup(@NotNull final Project project) { + DefaultActionGroup group = new DefaultActionGroup(); Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null) { LOG.warn("Course is null"); - return new DefaultActionGroup(); + return group; } StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project); if (configurator != null) { - return configurator.getActionGroup(project); + group.addAll(configurator.getActionGroup(project)); + addAdditionalActions(group); + return group; } else { LOG.warn("No configurator is provided for plugin"); @@ -145,5 +162,68 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D } } - public abstract void setTaskText(String text) ; + private static void addAdditionalActions(DefaultActionGroup group) { + StudyActionsProvider[] providers = Extensions.getExtensions(StudyActionsProvider.EP_NAME); + for (StudyActionsProvider provider : providers) { + group.addAll(provider.getActions()); + } + } + + public void setTaskText(String text, VirtualFile taskDirectory, Project project) { + if (StudyTaskManager.getInstance(project).isTurnEditingMode()) { + if (taskDirectory == null) { + LOG.info("Failed to enter editing mode for StudyToolWindow"); + return; + } + VirtualFile taskTextFile = taskDirectory.findChild(EduNames.TASK_HTML); + enterEditingMode(taskTextFile, project); + StudyTaskManager.getInstance(project).setTurnEditingMode(false); + } + else { + setText(text); + } + } + + protected abstract void setText(String text); + + public void setEmptyText(@NotNull Project project) { + if (StudyTaskManager.getInstance(project).getToolWindowMode() == StudyToolWindowMode.EDITING) { + mySplitPane.setFirstComponent(myContentPanel); + StudyTaskManager.getInstance(project).setTurnEditingMode(true); + } + setTaskText(EMPTY_TASK_TEXT, null, project); + } + + public enum StudyToolWindowMode { + TEXT, EDITING + } + + + public void enterEditingMode(VirtualFile taskFile, Project project) { + final EditorFactory factory = EditorFactory.getInstance(); + Document document = FileDocumentManager.getInstance().getDocument(taskFile); + if (document == null) { + return; + } + WebBrowserManager.getInstance().setShowBrowserHover(false); + final EditorEx createdEditor = (EditorEx)factory.createEditor(document, project, taskFile, false); + Disposer.register(project, new Disposable() { + public void dispose() { + factory.releaseEditor(createdEditor); + } + }); + JComponent editorComponent = createdEditor.getComponent(); + mySplitPane.setFirstComponent(editorComponent); + mySplitPane.repaint(); + + StudyTaskManager.getInstance(project).setToolWindowMode(StudyToolWindowMode.EDITING); + } + + + public void leaveEditingMode(Project project) { + WebBrowserManager.getInstance().setShowBrowserHover(true); + mySplitPane.setFirstComponent(myContentPanel); + StudyTaskManager.getInstance(project).setToolWindowMode(StudyToolWindowMode.TEXT); + StudyUtils.updateStudyToolWindow(project); + } } diff --git a/python/educational-core/student/student.iml b/python/educational-core/student/student.iml index afa3ecaa230c..348ee0a814c1 100644 --- a/python/educational-core/student/student.iml +++ b/python/educational-core/student/student.iml @@ -22,5 +22,6 @@ + \ No newline at end of file diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java index ebffadfea5d2..501e73f76e9a 100644 --- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java @@ -15,6 +15,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.platform.DirectoryProjectGenerator; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiManager; +import com.jetbrains.edu.learning.StudyProjectComponent; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.coursecreator.actions.CCCreateLesson; import com.jetbrains.edu.coursecreator.actions.CCCreateTask; @@ -63,6 +65,9 @@ public class PyCCProjectGenerator extends PythonProjectGenerator implements Dire course.setLanguage("Python"); service.setCourse(course); + StudyTaskManager.getInstance(project).setCourse(course); + StudyProjectComponent.getInstance(project).registerStudyToolWindow(course); + final PsiDirectory projectDir = PsiManager.getInstance(project).findDirectory(baseDir); if (projectDir == null) return; new WriteCommandAction.Simple(project) { From 44e8906678b69181ad218465444d15c0e4ee57b1 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 23 Mar 2016 17:46:58 +0300 Subject: [PATCH 02/65] add courseMode to distinguish study and course creator projects --- .../jetbrains/edu/coursecreator/CCUtils.java | 19 ++++-- .../edu/learning/StudyProjectComponent.java | 32 +++++----- .../jetbrains/edu/learning/StudyUtils.java | 7 ++- .../jetbrains/edu/learning/core/EduNames.java | 3 +- .../edu/learning/courseFormat/Course.java | 17 +++++- .../coursecreator/PyCCProjectGenerator.java | 58 +++++++++++++------ 6 files changed, 92 insertions(+), 44 deletions(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java index 65131d0b36ae..0c5a9f77561c 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java @@ -18,6 +18,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.psi.PsiDirectory; import com.intellij.util.Function; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.StudyItem; @@ -33,8 +34,7 @@ import java.util.Comparator; public class CCUtils { private static final Logger LOG = Logger.getInstance(CCUtils.class); public static final String GENERATED_FILES_FOLDER = ".coursecreator"; - public static final String TESTS = "coursecreatortests"; - public static final String RESOURCES = "coursecreatorresources"; + public static final String COURSE_MODE = "Course Creator"; @Nullable public static CCLanguageManager getStudyLanguageManager(@NotNull final Course course) { @@ -100,9 +100,9 @@ public class CCUtils { if (sourceDirectory == null) { return false; } - CCProjectService service = CCProjectService.getInstance(sourceDirectory.getProject()); - Course course = service.getCourse(); - if (course != null && course.getLesson(sourceDirectory.getName()) != null) { + Project project = sourceDirectory.getProject(); + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course != null && isCourseCreator(project) && course.getLesson(sourceDirectory.getName()) != null) { return true; } return false; @@ -169,4 +169,13 @@ public class CCUtils { }); return folder.get(); } + + public static boolean isCourseCreator(@NotNull Project project) { + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + return false; + } + + return COURSE_MODE.equals(course.getCourseMode()); + } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java index 81af40c0d894..06e264a1cb7a 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java @@ -232,7 +232,7 @@ public class StudyProjectComponent implements ProjectComponent { keymap.addShortcut(actionShortcut.first, new KeyboardShortcut(KeyStroke.getKeyStroke(actionShortcut.second), null)); } } - } + } } myListener = null; } @@ -296,30 +296,30 @@ public class StudyProjectComponent implements ProjectComponent { final VirtualFile createdFile = event.getFile(); final VirtualFile taskDir = createdFile.getParent(); final Course course = StudyTaskManager.getInstance(myProject).getCourse(); + if (course == null || !EduNames.STUDY.equals(course.getCourseMode())) { + return; + } if (taskDir != null && taskDir.getName().contains(EduNames.TASK)) { int taskIndex = EduUtils.getIndex(taskDir.getName(), EduNames.TASK); final VirtualFile lessonDir = taskDir.getParent(); if (lessonDir != null && lessonDir.getName().contains(EduNames.LESSON)) { int lessonIndex = EduUtils.getIndex(lessonDir.getName(), EduNames.LESSON); - if (course != null) { - List lessons = course.getLessons(); - if (StudyUtils.indexIsValid(lessonIndex, lessons)) { - final Lesson lesson = lessons.get(lessonIndex); - final List tasks = lesson.getTaskList(); - if (StudyUtils.indexIsValid(taskIndex, tasks)) { - final Task task = tasks.get(taskIndex); - final TaskFile taskFile = new TaskFile(); - taskFile.initTaskFile(task, false); - taskFile.setUserCreated(true); - final String name = createdFile.getName(); - taskFile.name = name; - task.getTaskFiles().put(name, taskFile); - } + List lessons = course.getLessons(); + if (StudyUtils.indexIsValid(lessonIndex, lessons)) { + final Lesson lesson = lessons.get(lessonIndex); + final List tasks = lesson.getTaskList(); + if (StudyUtils.indexIsValid(taskIndex, tasks)) { + final Task task = tasks.get(taskIndex); + final TaskFile taskFile = new TaskFile(); + taskFile.initTaskFile(task, false); + taskFile.setUserCreated(true); + final String name = createdFile.getName(); + taskFile.name = name; + task.getTaskFiles().put(name, taskFile); } } } } } } - } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index c204f012023f..f683331174e0 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -411,9 +411,10 @@ public class StudyUtils { return false; } Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course == null) { + if (course == null || !EduNames.STUDY.equals(course.getCourseMode())) { return false; } + if (!isRenameableOrMoveable(project, course, element)) { return true; } @@ -492,4 +493,8 @@ public class StudyUtils { studyToolWindow.setTaskText(taskText, null, project); } } + + public static boolean isStudyProject(Project project) { + return StudyTaskManager.getInstance(project).getCourse() != null; + } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java index 03c06d19b30d..b670ba1cb6c4 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java @@ -38,8 +38,9 @@ public class EduNames { public static final String SANDBOX_DIR = "Sandbox"; public static final String COURSE_META_FILE = "course.json"; + public static final String STUDY = "Study"; public static String PYCHARM_ADDITIONAL = "PyCharm additional materials"; - + public static final String PYCHARM = "PyCharm"; private EduNames() { } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java index 5dfbebf0f609..e643d9470cc9 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/Course.java @@ -24,9 +24,14 @@ public class Course { private boolean myUpToDate; @Expose @SerializedName("language") - private String myLanguage="Python"; + private String myLanguage = "Python"; - private String courseType="PyCharm"; + //this field is used to distinguish ordinary and CheckIO projects + //"PyCharm" is used here for historical reasons + private String courseType = EduNames.PYCHARM; + + //this field is used to distinguish study and course creator modes + private String courseMode = EduNames.STUDY; /** * Initializes state of course @@ -145,4 +150,12 @@ public class Course { public void setCourseType(String courseType) { this.courseType = courseType; } + + public String getCourseMode() { + return courseMode; + } + + public void setCourseMode(String courseMode) { + this.courseMode = courseMode; + } } diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java index 501e73f76e9a..4af7914d2da4 100644 --- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCProjectGenerator.java @@ -6,21 +6,25 @@ import com.intellij.facet.ui.ValidationResult; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.FileTemplateUtil; +import com.intellij.openapi.application.PathManager; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.platform.DirectoryProjectGenerator; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiManager; -import com.jetbrains.edu.learning.StudyProjectComponent; -import com.jetbrains.edu.learning.StudyTaskManager; -import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.coursecreator.actions.CCCreateLesson; import com.jetbrains.edu.coursecreator.actions.CCCreateTask; import com.jetbrains.edu.coursecreator.ui.CCNewProjectPanel; +import com.jetbrains.edu.learning.StudyProjectComponent; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.python.PythonLanguage; import com.jetbrains.python.newProject.PythonProjectGenerator; import icons.CourseCreatorPythonIcons; import org.jetbrains.annotations.Nls; @@ -28,6 +32,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.io.File; public class PyCCProjectGenerator extends PythonProjectGenerator implements DirectoryProjectGenerator { @@ -57,28 +62,16 @@ public class PyCCProjectGenerator extends PythonProjectGenerator implements Dire public static void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir, @NotNull final String name, @NotNull final String[] authors, @NotNull final String description) { - final CCProjectService service = CCProjectService.getInstance(project); - final Course course = new Course(); - course.setName(name); - course.setAuthors(authors); - course.setDescription(description); - course.setLanguage("Python"); - service.setCourse(course); - - StudyTaskManager.getInstance(project).setCourse(course); - StudyProjectComponent.getInstance(project).registerStudyToolWindow(course); + final Course course = getCourse(project, name, authors, description); final PsiDirectory projectDir = PsiManager.getInstance(project).findDirectory(baseDir); if (projectDir == null) return; new WriteCommandAction.Simple(project) { @Override protected void run() throws Throwable { - final FileTemplate template = FileTemplateManager.getInstance(project).getInternalTemplate("test_helper"); - try { - FileTemplateUtil.createFromTemplate(template, "test_helper.py", null, projectDir); - } - catch (Exception ignored) { - } + + createTestHelper(project, projectDir); + PsiDirectory lessonDir = new CCCreateLesson().createItem(null, project, projectDir, course); if (lessonDir == null) { LOG.error("Failed to create lesson"); @@ -89,6 +82,33 @@ public class PyCCProjectGenerator extends PythonProjectGenerator implements Dire }.execute(); } + private static void createTestHelper(@NotNull Project project, PsiDirectory projectDir) { + final FileTemplate template = FileTemplateManager.getInstance(project).getInternalTemplate(FileUtil.getNameWithoutExtension(EduNames.TEST_HELPER)); + try { + FileTemplateUtil.createFromTemplate(template, EduNames.TEST_HELPER, null, projectDir); + } + catch (Exception ignored) { + } + } + + @NotNull + private static Course getCourse(@NotNull Project project, @NotNull String name, @NotNull String[] authors, @NotNull String description) { + final Course course = new Course(); + course.setName(name); + course.setAuthors(authors); + course.setDescription(description); + course.setLanguage(PythonLanguage.getInstance().getID()); + course.setCourseMode(CCUtils.COURSE_MODE); + + File coursesDir = new File(PathManager.getConfigPath(), "courses"); + File courseDir = new File(coursesDir, name + "-" + project.getName()); + course.setCourseDirectory(courseDir.getPath()); + + StudyTaskManager.getInstance(project).setCourse(course); + StudyProjectComponent.getInstance(project).registerStudyToolWindow(course); + return course; + } + @NotNull @Override public ValidationResult validate(@NotNull String s) { From 1f6371b9790d6b67f39dd49b19c5d3173a725e83 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 23 Mar 2016 17:53:36 +0300 Subject: [PATCH 03/65] refactoring of change course info action remove usage of CCProjectService use DialogBuilder instead of DialogWrapper --- .../actions/CCChangeCourseInfo.java | 89 ++++++------------- 1 file changed, 29 insertions(+), 60 deletions(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java index 28706dae9a72..3423c822aae8 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCChangeCourseInfo.java @@ -2,39 +2,39 @@ package com.jetbrains.edu.coursecreator.actions; import com.intellij.ide.IdeView; import com.intellij.ide.projectView.ProjectView; -import com.intellij.ide.util.DirectoryChooserUtil; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.DialogBuilder; import com.intellij.psi.PsiDirectory; -import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.coursecreator.CCProjectService; +import com.intellij.util.ui.JBUI; +import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.ui.CCNewProjectPanel; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.courseFormat.Course; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.*; public class CCChangeCourseInfo extends DumbAwareAction { + + private static final String ACTION_TEXT = "Change Course Information"; + public CCChangeCourseInfo() { - super("Change Course Information", "Change Course Information", null); + super(ACTION_TEXT, ACTION_TEXT, null); } @Override public void update(@NotNull AnActionEvent event) { - if (!CCProjectService.setCCActionAvailable(event)) { + final Project project = event.getProject(); + final Presentation presentation = event.getPresentation(); + if (project == null) { return; } - final Presentation presentation = event.getPresentation(); - presentation.setVisible(false); - presentation.setEnabled(false); - final Project project = event.getData(CommonDataKeys.PROJECT); - if (project == null) { + presentation.setEnabledAndVisible(false); + if (!CCUtils.isCourseCreator(project)) { return; } final IdeView view = event.getData(LangDataKeys.IDE_VIEW); @@ -45,45 +45,24 @@ public class CCChangeCourseInfo extends DumbAwareAction { if (directories.length == 0) { return; } - final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view); - if (directory != null && !project.getBaseDir().equals(directory.getVirtualFile())) { - return; - } - presentation.setVisible(true); - presentation.setEnabled(true); - + presentation.setEnabledAndVisible(true); } @Override public void actionPerformed(@NotNull AnActionEvent e) { - if (!CCProjectService.setCCActionAvailable(e)) { - return; - } - final Project project = e.getProject(); + Project project = e.getProject(); if (project == null) { return; } - Course course = CCProjectService.getInstance(project).getCourse(); + Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null) { return; } - final IdeView view = e.getData(LangDataKeys.IDE_VIEW); - if (view == null) { - return; - } - final PsiDirectory[] directories = view.getDirectories(); - if (directories.length == 0) { - return; - } - final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view); - if (directory != null && !project.getBaseDir().equals(directory.getVirtualFile())) { - return; - } - CCNewProjectPanel panel = new CCNewProjectPanel(course.getName(), Course.getAuthorsString(course.getAuthors()), course.getDescription()); - ChangeCourseInfoDialog changeCourseInfoDialog = - new ChangeCourseInfoDialog(project, panel); - changeCourseInfoDialog.show(); - if (changeCourseInfoDialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + + CCNewProjectPanel panel = + new CCNewProjectPanel(course.getName(), Course.getAuthorsString(course.getAuthors()), course.getDescription()); + DialogBuilder builder = createChangeInfoDialog(project, panel); + if (builder.showAndGet()) { course.setAuthors(panel.getAuthors()); course.setName(panel.getName()); course.setDescription(panel.getDescription()); @@ -91,24 +70,14 @@ public class CCChangeCourseInfo extends DumbAwareAction { } } - static class ChangeCourseInfoDialog extends DialogWrapper { + private static DialogBuilder createChangeInfoDialog(Project project, @NotNull CCNewProjectPanel panel) { + DialogBuilder builder = new DialogBuilder(project); - private final JPanel myMainPanel; + builder.setTitle(ACTION_TEXT); + JPanel changeInfoPanel = panel.getMainPanel(); + changeInfoPanel.setMinimumSize(JBUI.size(400, 300)); + builder.setCenterPanel(changeInfoPanel); - public ChangeCourseInfoDialog(@Nullable Project project, CCNewProjectPanel panel) { - super(project); - setTitle("Change Course Information"); - myMainPanel = panel.getMainPanel(); - init(); - } - - @Nullable - @Override - protected JComponent createCenterPanel() { - myMainPanel.setPreferredSize(new Dimension(400, 300)); - myMainPanel.setSize(new Dimension(400, 300)); - myMainPanel.setMaximumSize(new Dimension(400, 300)); - return myMainPanel; - } + return builder; } } From ecaf938cf9b2813eeb5b3d17c15c94f7f52d27c6 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 23 Mar 2016 18:02:47 +0300 Subject: [PATCH 04/65] allow lesson/task creation/modification in study projects with course creator mode --- .../actions/CCCreateStudyItemActionBase.java | 39 +++++++++---------- .../coursecreator/actions/CCCreateTask.java | 29 +++++++------- .../CCLessonMoveHandlerDelegate.java | 11 ++++-- .../{ => handlers}/CCLessonRenameHandler.java | 2 +- .../{ => handlers}/CCRenameHandler.java | 14 ++++--- .../CCTaskMoveHandlerDelegate.java | 14 ++++--- .../{ => handlers}/CCTaskRenameHandler.java | 2 +- .../edu/learning/StudyMoveDelegate.java | 3 +- 8 files changed, 62 insertions(+), 52 deletions(-) rename python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/{ => handlers}/CCLessonMoveHandlerDelegate.java (94%) rename python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/{ => handlers}/CCLessonRenameHandler.java (94%) rename python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/{ => handlers}/CCRenameHandler.java (88%) rename python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/{ => handlers}/CCTaskMoveHandlerDelegate.java (94%) rename python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/{ => handlers}/CCTaskRenameHandler.java (96%) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java index 520ce0961a6a..45310c7c0e8f 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java @@ -14,12 +14,13 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.util.Function; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.coursecreator.ui.CCCreateStudyItemDialog; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.StudyItem; -import com.jetbrains.edu.coursecreator.CCProjectService; -import com.jetbrains.edu.coursecreator.CCUtils; -import com.jetbrains.edu.coursecreator.ui.CCCreateStudyItemDialog; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,18 +34,16 @@ public abstract class CCCreateStudyItemActionBase extends DumbAwareAction { super(text, description, icon); } - @Override public void actionPerformed(AnActionEvent e) { final IdeView view = e.getData(LangDataKeys.IDE_VIEW); - final Project project = e.getData(CommonDataKeys.PROJECT); + final Project project = e.getProject(); if (view == null || project == null) { return; } final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view); if (directory == null) return; - final CCProjectService service = CCProjectService.getInstance(project); - final Course course = service.getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null) { return; } @@ -54,47 +53,45 @@ public abstract class CCCreateStudyItemActionBase extends DumbAwareAction { @Override public void update(@NotNull AnActionEvent event) { - if (!CCProjectService.setCCActionAvailable(event)) { - return; - } final Presentation presentation = event.getPresentation(); + presentation.setEnabledAndVisible(false); final Project project = event.getData(CommonDataKeys.PROJECT); final IdeView view = event.getData(LangDataKeys.IDE_VIEW); if (project == null || view == null) { presentation.setEnabledAndVisible(false); return; } + if (!StudyUtils.isStudyProject(project)) { + return; + } final PsiDirectory[] directories = view.getDirectories(); if (directories.length == 0) { - presentation.setEnabledAndVisible(false); return; } final PsiDirectory sourceDirectory = DirectoryChooserUtil.getOrChooseDirectory(view); - final CCProjectService service = CCProjectService.getInstance(project); - final Course course = service.getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null || sourceDirectory == null) { - presentation.setEnabledAndVisible(false); return; } - if (!isAddedAsLast(sourceDirectory, project, course) && - getThresholdItem(course, sourceDirectory) == null) { - presentation.setEnabledAndVisible(false); + if (!isAddedAsLast(sourceDirectory, project, course) && getThresholdItem(course, sourceDirectory) == null) { + return; } if (CommonDataKeys.PSI_FILE.getData(event.getDataContext()) != null) { - presentation.setEnabledAndVisible(false); + return; } + presentation.setEnabledAndVisible(true); } @Nullable protected abstract PsiDirectory getParentDir(@NotNull final Project project, - @NotNull final Course course, - @NotNull final PsiDirectory directory); + @NotNull final Course course, + @NotNull final PsiDirectory directory); @Nullable public PsiDirectory createItem(@Nullable final IdeView view, @NotNull final Project project, - @NotNull final PsiDirectory sourceDirectory, @NotNull final Course course) { + @NotNull final PsiDirectory sourceDirectory, @NotNull final Course course) { StudyItem parentItem = getParentItem(course, sourceDirectory); final StudyItem item = getItem(sourceDirectory, project, course, view, parentItem); if (item == null) { diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java index 316b06d77c04..0c053ab57c0b 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java @@ -9,19 +9,20 @@ import com.intellij.ide.util.EditorHelper; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.util.Function; +import com.jetbrains.edu.coursecreator.CCLanguageManager; +import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.courseFormat.Task; -import com.jetbrains.edu.coursecreator.CCLanguageManager; -import com.jetbrains.edu.coursecreator.CCUtils; import icons.InteractiveLearningIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,15 +39,15 @@ public class CCCreateTask extends CCCreateStudyItemActionBase { } - private static void createFromTemplateAndOpen(@NotNull final PsiDirectory taskDirectory, - @Nullable final FileTemplate template, - @Nullable IdeView view) { + private static void createFromTemplate(@NotNull final PsiDirectory taskDirectory, + @Nullable final FileTemplate template, + @Nullable IdeView view, boolean open) { if (template == null) { return; } try { final PsiElement file = FileTemplateUtil.createFromTemplate(template, template.getName(), null, taskDirectory); - if (view != null) { + if (view != null && open) { EditorHelper.openInEditor(file, false); view.selectElement(file); } @@ -91,22 +92,24 @@ public class CCCreateTask extends CCCreateStudyItemActionBase { protected PsiDirectory createItemDir(@NotNull final Project project, @NotNull final StudyItem item, @Nullable final IdeView view, @NotNull final PsiDirectory parentDirectory, @NotNull final Course course) { - final PsiDirectory[] taskDirectory = new PsiDirectory[1]; + + final Ref taskDirectory = new Ref<>(); ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - taskDirectory[0] = DirectoryUtil.createSubdirectories(EduNames.TASK + item.getIndex(), parentDirectory, "\\/"); - if (taskDirectory[0] != null) { + String taskDirName = EduNames.TASK + item.getIndex(); + taskDirectory.set(DirectoryUtil.createSubdirectories(taskDirName, parentDirectory, "\\/")); + if (taskDirectory.get() != null) { CCLanguageManager manager = CCUtils.getStudyLanguageManager(course); if (manager == null) { return; } - createFromTemplateAndOpen(taskDirectory[0], manager.getTestsTemplate(project), view); - createFromTemplateAndOpen(taskDirectory[0], FileTemplateManager.getInstance(project).getInternalTemplate("task.html"), view); + createFromTemplate(taskDirectory.get(), manager.getTestsTemplate(project), view, false); + createFromTemplate(taskDirectory.get(), FileTemplateManager.getInstance(project).getInternalTemplate(EduNames.TASK_HTML), view, false); String defaultExtension = manager.getDefaultTaskFileExtension(); if (defaultExtension != null) { FileTemplate taskFileTemplate = manager.getTaskFileTemplateForExtension(project, defaultExtension); - createFromTemplateAndOpen(taskDirectory[0], taskFileTemplate, view); + createFromTemplate(taskDirectory.get(), taskFileTemplate, view, true); if (taskFileTemplate != null) { String taskFileName = FileUtil.getNameWithoutExtension(taskFileTemplate.getName()); ((Task)item).addTaskFile(taskFileName + "." + defaultExtension, 1); @@ -115,7 +118,7 @@ public class CCCreateTask extends CCCreateStudyItemActionBase { } } }); - return taskDirectory[0]; + return taskDirectory.get(); } @Override diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonMoveHandlerDelegate.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java similarity index 94% rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonMoveHandlerDelegate.java rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java index 2a1cf8ca7733..ee6a92fa5e0e 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonMoveHandlerDelegate.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java @@ -1,4 +1,4 @@ -package com.jetbrains.edu.coursecreator; +package com.jetbrains.edu.coursecreator.handlers; import com.intellij.ide.IdeView; import com.intellij.ide.util.DirectoryChooserUtil; @@ -18,12 +18,14 @@ import com.intellij.psi.PsiReference; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandlerDelegate; import com.intellij.util.Function; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; -import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -67,7 +69,10 @@ public class CCLessonMoveHandlerDelegate extends MoveHandlerDelegate { if (targetContainer == null || !(targetContainer instanceof PsiDirectory)) { return; } - final Course course = CCProjectService.getInstance(project).getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + return; + } final PsiDirectory sourceDirectory = (PsiDirectory)elements[0]; final Lesson sourceLesson = course.getLesson(sourceDirectory.getName()); final Lesson targetLesson = course.getLesson(((PsiDirectory)targetContainer).getName()); diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonRenameHandler.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonRenameHandler.java similarity index 94% rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonRenameHandler.java rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonRenameHandler.java index 9b29cbafec2e..0efe1110a8ca 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLessonRenameHandler.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCLessonRenameHandler.java @@ -1,4 +1,4 @@ -package com.jetbrains.edu.coursecreator; +package com.jetbrains.edu.coursecreator.handlers; import com.intellij.ide.TitledHandler; import com.intellij.openapi.project.Project; diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRenameHandler.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCRenameHandler.java similarity index 88% rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRenameHandler.java rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCRenameHandler.java index 27bd42ca2484..e98ba1ab133f 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRenameHandler.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCRenameHandler.java @@ -1,4 +1,4 @@ -package com.jetbrains.edu.coursecreator; +package com.jetbrains.edu.coursecreator.handlers; import com.intellij.ide.projectView.ProjectView; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -12,6 +12,8 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.refactoring.rename.RenameHandler; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.StudyItem; import org.jetbrains.annotations.NotNull; @@ -23,9 +25,7 @@ public abstract class CCRenameHandler implements RenameHandler { if (element == null || !(element instanceof PsiDirectory)) { return false; } - CCProjectService instance = CCProjectService.getInstance(element.getProject()); - Course course = instance.getCourse(); - if (course == null) { + if (!CCUtils.isCourseCreator(element.getProject())) { return false; } VirtualFile directory = ((PsiDirectory)element).getVirtualFile(); @@ -44,8 +44,10 @@ public abstract class CCRenameHandler implements RenameHandler { PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext); assert element != null; PsiDirectory directory = (PsiDirectory)element; - CCProjectService instance = CCProjectService.getInstance(project); - Course course = instance.getCourse(); + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + return; + } rename(project, course, directory); ProjectView.getInstance(project).refresh(); } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskMoveHandlerDelegate.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java similarity index 94% rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskMoveHandlerDelegate.java rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java index 37cd620bc2e6..a132e408b85f 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskMoveHandlerDelegate.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskMoveHandlerDelegate.java @@ -1,4 +1,4 @@ -package com.jetbrains.edu.coursecreator; +package com.jetbrains.edu.coursecreator.handlers; import com.intellij.ide.IdeView; import com.intellij.ide.util.DirectoryChooserUtil; @@ -18,13 +18,15 @@ import com.intellij.psi.PsiReference; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandlerDelegate; import com.intellij.util.Function; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.courseFormat.Task; -import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -59,9 +61,9 @@ public class CCTaskMoveHandlerDelegate extends MoveHandlerDelegate { if (sourceDirectory == null) { return false; } - CCProjectService service = CCProjectService.getInstance(sourceDirectory.getProject()); - Course course = service.getCourse(); - if (course == null) { + Project project = sourceDirectory.getProject(); + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null || !CCUtils.isCourseCreator(project)) { return false; } return EduUtils.getTask(sourceDirectory, course) != null; @@ -86,7 +88,7 @@ public class CCTaskMoveHandlerDelegate extends MoveHandlerDelegate { Messages.showInfoMessage("Tasks can be moved only to other lessons or inside lesson", "Incorrect Target For Move"); return; } - final Course course = CCProjectService.getInstance(project).getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); final PsiDirectory sourceDirectory = (PsiDirectory)elements[0]; final Task taskToMove = EduUtils.getTask(sourceDirectory, course); diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskRenameHandler.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskRenameHandler.java similarity index 96% rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskRenameHandler.java rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskRenameHandler.java index 0f30a1d689f5..98bcba87c6c8 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCTaskRenameHandler.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/handlers/CCTaskRenameHandler.java @@ -1,4 +1,4 @@ -package com.jetbrains.edu.coursecreator; +package com.jetbrains.edu.coursecreator.handlers; import com.intellij.ide.TitledHandler; import com.intellij.openapi.project.Project; diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyMoveDelegate.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyMoveDelegate.java index e21bb4007af4..d7ff54c0560b 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyMoveDelegate.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyMoveDelegate.java @@ -8,6 +8,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.refactoring.move.MoveCallback; import com.intellij.refactoring.move.MoveHandlerDelegate; +import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; import org.jetbrains.annotations.Nullable; @@ -22,7 +23,7 @@ public class StudyMoveDelegate extends MoveHandlerDelegate{ if (elements.length == 1) { Project project = elements[0].getProject(); Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course == null) { + if (course == null || !EduNames.STUDY.equals(course.getCourseMode())) { return false; } return !StudyUtils.isRenameableOrMoveable(project, course, elements[0]); From b32423a934b5bc8fa7b09ac47bcbccb7438d3bb6 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Mon, 4 Apr 2016 15:18:29 +0300 Subject: [PATCH 05/65] add new files as task files --- .../edu/coursecreator/CCLanguageManager.java | 5 ++ .../edu/coursecreator/CCProjectComponent.java | 21 +++----- .../jetbrains/edu/coursecreator/CCUtils.java | 12 +++++ .../coursecreator/CCVirtualFileListener.java | 48 +++++++++++++++++++ .../coursecreator/actions/CCCreateTask.java | 5 -- .../jetbrains/edu/learning/StudyUtils.java | 17 +++++++ .../coursecreator/PyCCLanguageManager.java | 6 +++ 7 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLanguageManager.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLanguageManager.java index 5ab5f5591ed8..b6c8fd4ecf53 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLanguageManager.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCLanguageManager.java @@ -3,6 +3,7 @@ package com.jetbrains.edu.coursecreator; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.lang.LanguageExtension; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,4 +22,8 @@ public interface CCLanguageManager { FileTemplate getTestsTemplate(@NotNull final Project project); boolean doNotPackFile(File pathname); + + default boolean isTestFile(VirtualFile file) { + return false; + } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java index e5871848ecf1..25ba06fd9b30 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java @@ -1,23 +1,13 @@ package com.jetbrains.edu.coursecreator; import com.intellij.openapi.components.ProjectComponent; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorFactory; -import com.intellij.openapi.editor.event.EditorFactoryEvent; -import com.intellij.openapi.editor.impl.EditorFactoryImpl; -import com.intellij.openapi.fileEditor.FileEditor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; -import com.jetbrains.edu.learning.courseFormat.Course; import org.jetbrains.annotations.NotNull; public class CCProjectComponent implements ProjectComponent { private final Project myProject; + private final CCVirtualFileListener myTaskFileLifeListener = new CCVirtualFileListener(); private CCFileDeletedListener myListener; public CCProjectComponent(Project project) { @@ -25,6 +15,7 @@ public class CCProjectComponent implements ProjectComponent { } public void initComponent() { + VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); } public void disposeComponent() { @@ -36,14 +27,15 @@ public class CCProjectComponent implements ProjectComponent { } public void projectOpened() { + VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() { @Override public void run() { final Course course = CCProjectService.getInstance(myProject).getCourse(); if (course != null) { course.initCourse(true); - myListener = new CCFileDeletedListener(myProject); - VirtualFileManager.getInstance().addVirtualFileListener(myListener); + myTaskFileLifeListener = new CCFileDeletedListener(myProject); + VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); final CCEditorFactoryListener editorFactoryListener = new CCEditorFactoryListener(); EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, myProject); VirtualFile[] files = FileEditorManager.getInstance(myProject).getOpenFiles(); @@ -64,8 +56,9 @@ public class CCProjectComponent implements ProjectComponent { } public void projectClosed() { + VirtualFileManager.getInstance().removeVirtualFileListener(myTaskFileLifeListener); if (myListener != null) { - VirtualFileManager.getInstance().removeVirtualFileListener(myListener); + VirtualFileManager.getInstance().removeVirtualFileListener(myTaskFileLifeListener); } } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java index 0c5a9f77561c..139a15be6845 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java @@ -178,4 +178,16 @@ public class CCUtils { return COURSE_MODE.equals(course.getCourseMode()); } + + public static boolean isTestsFile(@NotNull Project project, @NotNull VirtualFile file) { + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + return false; + } + CCLanguageManager manager = getStudyLanguageManager(course); + if (manager == null) { + return false; + } + return manager.isTestFile(file); + } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java new file mode 100644 index 000000000000..6a7eda601c07 --- /dev/null +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -0,0 +1,48 @@ +package com.jetbrains.edu.coursecreator; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileAdapter; +import com.intellij.openapi.vfs.VirtualFileEvent; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.Task; +import com.jetbrains.edu.learning.courseFormat.TaskFile; +import org.jetbrains.annotations.NotNull; + +public class CCVirtualFileListener extends VirtualFileAdapter { + + @Override + public void fileCreated(@NotNull VirtualFileEvent event) { + VirtualFile createdFile = event.getFile(); + Project project = ProjectUtil.guessProjectForContentFile(createdFile); + if (project == null) { + return; + } + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null || !CCUtils.isCourseCreator(project)) { + return; + } + TaskFile taskFile = StudyUtils.getTaskFile(project, createdFile); + if (taskFile != null) { + return; + } + + if (CCUtils.isTestsFile(project, createdFile) || EduNames.TASK_HTML.equals(createdFile.getName())) { + return; + } + + VirtualFile taskVF = createdFile.getParent(); + if (taskVF == null) { + return; + } + Task task = StudyUtils.getTask(project,taskVF); + if (task == null) { + return; + } + task.addTaskFile(createdFile.getName(), 1); + } +} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java index 0c053ab57c0b..844fc9ad3796 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java @@ -10,7 +10,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; @@ -110,10 +109,6 @@ public class CCCreateTask extends CCCreateStudyItemActionBase { if (defaultExtension != null) { FileTemplate taskFileTemplate = manager.getTaskFileTemplateForExtension(project, defaultExtension); createFromTemplate(taskDirectory.get(), taskFileTemplate, view, true); - if (taskFileTemplate != null) { - String taskFileName = FileUtil.getNameWithoutExtension(taskFileTemplate.getName()); - ((Task)item).addTaskFile(taskFileName + "." + defaultExtension, 1); - } } } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index f683331174e0..3db531be22d2 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -497,4 +497,21 @@ public class StudyUtils { public static boolean isStudyProject(Project project) { return StudyTaskManager.getInstance(project).getCourse() != null; } + + @Nullable + public static Task getTask(@NotNull Project project, @NotNull VirtualFile taskVF) { + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + return null; + } + VirtualFile lessonVF = taskVF.getParent(); + if (lessonVF == null) { + return null; + } + Lesson lesson = course.getLesson(lessonVF.getName()); + if (lesson == null) { + return null; + } + return lesson.getTask(taskVF.getName()); + } } diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCLanguageManager.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCLanguageManager.java index f66ecff6ddd3..8628bbdecc41 100644 --- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCLanguageManager.java +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCLanguageManager.java @@ -3,6 +3,7 @@ package com.jetbrains.edu.coursecreator; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.edu.learning.core.EduNames; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,4 +41,9 @@ public class PyCCLanguageManager implements CCLanguageManager { private static FileTemplate getInternalTemplateByName(@NotNull final Project project, String name) { return FileTemplateManager.getInstance(project).getInternalTemplate(name); } + + @Override + public boolean isTestFile(VirtualFile file) { + return EduNames.TESTS_FILE.equals(file.getName()); + } } From a4102ad3da9d282f7d4755c7b65407735039abe2 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Tue, 5 Apr 2016 14:40:51 +0300 Subject: [PATCH 06/65] create resource files for created task files --- .../coursecreator/CCVirtualFileListener.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java index 6a7eda601c07..2b42574ea946 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -1,7 +1,9 @@ package com.jetbrains.edu.coursecreator; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectUtil; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileAdapter; import com.intellij.openapi.vfs.VirtualFileEvent; @@ -13,8 +15,13 @@ import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.courseFormat.TaskFile; import org.jetbrains.annotations.NotNull; +import java.io.File; +import java.io.IOException; + public class CCVirtualFileListener extends VirtualFileAdapter { + private static final Logger LOG = Logger.getInstance(CCVirtualFileListener.class); + @Override public void fileCreated(@NotNull VirtualFileEvent event) { VirtualFile createdFile = event.getFile(); @@ -43,6 +50,31 @@ public class CCVirtualFileListener extends VirtualFileAdapter { if (task == null) { return; } + + createResourceFile(createdFile, course, taskVF); + task.addTaskFile(createdFile.getName(), 1); } + + private static void createResourceFile(VirtualFile createdFile, Course course, VirtualFile taskVF) { + VirtualFile lessonVF = taskVF.getParent(); + if (lessonVF == null) { + return; + } + + String taskResourcesPath = FileUtil.join(course.getCourseDirectory(), lessonVF.getName(), taskVF.getName()); + File taskResourceFile = new File(taskResourcesPath); + if (!taskResourceFile.exists()) { + if (!taskResourceFile.mkdirs()) { + LOG.info("Failed to create resources for task " + taskResourcesPath); + } + } + try { + File toFile = new File(taskResourceFile, createdFile.getName()); + FileUtil.copy(new File(createdFile.getPath()), toFile); + } + catch (IOException e) { + LOG.info("Failed to copy created task file to resources " + createdFile.getPath()); + } + } } From 183107beeb78dc3ae4c37d66971295d9c2b14224 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 6 Apr 2016 13:54:52 +0300 Subject: [PATCH 07/65] merge Add and Delete Placeholder actions --- .../resources/META-INF/plugin.xml | 21 ++- .../actions/CCAddAnswerPlaceholder.java | 153 ++++++++---------- .../actions/CCAnswerPlaceholderAction.java | 25 +-- .../actions/CCDeleteAnswerPlaceholder.java | 39 ----- .../jetbrains/edu/learning/core/EduNames.java | 2 + 5 files changed, 87 insertions(+), 153 deletions(-) delete mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAnswerPlaceholder.java diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index 24da17d3f29c..9b90a825914a 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -16,13 +16,12 @@ com.jetbrains.edu.interactivelearning - - - - - + + + + @@ -33,7 +32,6 @@ - com.jetbrains.edu.coursecreator.CCProjectComponent @@ -61,15 +59,14 @@ - - - + + + + + - - - diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java index 791d7fb0efae..aab278175e0b 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java @@ -1,32 +1,29 @@ package com.jetbrains.edu.coursecreator.actions; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; -import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.ui.JBColor; -import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; -import com.jetbrains.edu.coursecreator.CCProjectService; import com.jetbrains.edu.coursecreator.ui.CCCreateAnswerPlaceholderDialog; -import com.jetbrains.edu.learning.courseFormat.*; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; +import com.jetbrains.edu.learning.courseFormat.TaskFile; import org.jetbrains.annotations.NotNull; import java.util.List; -public class CCAddAnswerPlaceholder extends DumbAwareAction { - private static final Logger LOG = Logger.getInstance(CCAddAnswerPlaceholder.class); +public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction { public CCAddAnswerPlaceholder() { - super("Add Answer Placeholder", "Add answer placeholder", null); + super("Add/Delete Answer Placeholder", "Add/Delete answer placeholder", null); } @@ -43,47 +40,33 @@ public class CCAddAnswerPlaceholder extends DumbAwareAction { return false; } - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - final Project project = e.getData(CommonDataKeys.PROJECT); - if (project == null) { + private static void addPlaceholder(@NotNull CCState state) { + Editor editor = state.getEditor(); + Project project = state.getProject(); + PsiFile file = state.getFile(); + + final Document document = PsiDocumentManager.getInstance(project).getDocument(file); + if (document == null) { return; } - final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext()); - if (file == null) return; - final Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext()); - if (editor == null) return; + final SelectionModel model = editor.getSelectionModel(); - final Document document = PsiDocumentManager.getInstance(project).getDocument(file); - if (document == null) return; final int start = model.getSelectionStart(); - final int end = model.getSelectionEnd(); final int lineNumber = document.getLineNumber(start); int realStart = start - document.getLineStartOffset(lineNumber); - - final CCProjectService service = CCProjectService.getInstance(project); - final PsiDirectory taskDir = file.getContainingDirectory(); - final PsiDirectory lessonDir = taskDir.getParent(); - if (lessonDir == null) return; - - final TaskFile taskFile = service.getTaskFile(file.getVirtualFile()); - if (taskFile == null) { - return; - } - if (arePlaceholdersIntersect(taskFile, document, start, end)) { - return; - } final AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder(); answerPlaceholder.setLine(lineNumber); answerPlaceholder.setStart(realStart); - answerPlaceholder.setPossibleAnswer(model.getSelectedText()); + String selectedText = model.getSelectedText(); + answerPlaceholder.setPossibleAnswer(selectedText); - CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder - ); + CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder); dlg.show(); if (dlg.getExitCode() != DialogWrapper.OK_EXIT_CODE) { return; } + + TaskFile taskFile = state.getTaskFile(); int index = taskFile.getAnswerPlaceholders().size() + 1; answerPlaceholder.setIndex(index); taskFile.addAnswerPlaceholder(answerPlaceholder); @@ -92,65 +75,67 @@ public class CCAddAnswerPlaceholder extends DumbAwareAction { EduAnswerPlaceholderPainter.createGuardedBlocks(editor, answerPlaceholder, false); } + @Override + protected void performAnswerPlaceholderAction(@NotNull CCState state) { + if (canAddPlaceholder(state)) { + addPlaceholder(state); + return; + } + if (canDeletePlaceholder(state)) { + deletePlaceholder(state); + } + } + + private static void deletePlaceholder(@NotNull CCState state) { + Project project = state.getProject(); + PsiFile psiFile = state.getFile(); + final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); + if (document == null) return; + TaskFile taskFile = state.getTaskFile(); + AnswerPlaceholder answerPlaceholder = state.getAnswerPlaceholder(); + final List answerPlaceholders = taskFile.getAnswerPlaceholders(); + if (answerPlaceholders.contains(answerPlaceholder)) { + answerPlaceholders.remove(answerPlaceholder); + final Editor editor = state.getEditor(); + editor.getMarkupModel().removeAllHighlighters(); + StudyUtils.drawAllWindows(editor, taskFile); + EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, false); + } + } + @Override public void update(@NotNull AnActionEvent event) { - if (!CCProjectService.setCCActionAvailable(event)) { - return; - } final Presentation presentation = event.getPresentation(); - final Project project = event.getData(CommonDataKeys.PROJECT); - if (project == null) { - presentation.setVisible(false); - presentation.setEnabled(false); + presentation.setEnabledAndVisible(false); + + CCState state = getState(event); + if (state == null) { return; } - final Editor editor = CommonDataKeys.EDITOR.getData(event.getDataContext()); - final PsiFile file = CommonDataKeys.PSI_FILE.getData(event.getDataContext()); - if (editor == null || file == null) { - presentation.setVisible(false); - presentation.setEnabled(false); - return; + + presentation.setVisible(true); + if (canAddPlaceholder(state) || canDeletePlaceholder(state)) { + presentation.setEnabled(true); + presentation.setText((state.getAnswerPlaceholder() == null ? "Add " : "Delete ") + EduNames.PLACEHOLDER); } + } + + + private static boolean canAddPlaceholder(@NotNull CCState state) { + Editor editor = state.getEditor(); SelectionModel selectionModel = editor.getSelectionModel(); if (!selectionModel.hasSelection()) { - presentation.setVisible(false); - presentation.setEnabled(false); - return; + return false; } int start = selectionModel.getSelectionStart(); int end = selectionModel.getSelectionEnd(); + return !arePlaceholdersIntersect(state.getTaskFile(), editor.getDocument(), start, end); + } - final CCProjectService service = CCProjectService.getInstance(project); - final PsiDirectory taskDir = file.getContainingDirectory(); - final PsiDirectory lessonDir = taskDir.getParent(); - if (lessonDir == null) return; - - final Course course = service.getCourse(); - final Lesson lesson = course.getLesson(lessonDir.getName()); - if (lesson == null) { - presentation.setVisible(false); - presentation.setEnabled(false); - return; + private static boolean canDeletePlaceholder(@NotNull CCState state) { + if (state.getEditor().getSelectionModel().hasSelection()) { + return false; } - final Task task = lesson.getTask(taskDir.getName()); - if (task == null) { - presentation.setVisible(false); - presentation.setEnabled(false); - return; - } - TaskFile taskFile = service.getTaskFile(file.getVirtualFile()); - if (taskFile == null) { - LOG.info("could not find task file"); - presentation.setVisible(false); - presentation.setEnabled(false); - return; - } - if (arePlaceholdersIntersect(taskFile, editor.getDocument(), start, end)) { - presentation.setVisible(false); - presentation.setEnabled(false); - return; - } - presentation.setVisible(true); - presentation.setEnabled(true); + return state.getAnswerPlaceholder() != null; } } \ No newline at end of file diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java index 48425e247100..e1633044d5e6 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAnswerPlaceholderAction.java @@ -2,15 +2,15 @@ package com.jetbrains.edu.coursecreator.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.coursecreator.CCProjectService; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,9 +23,9 @@ abstract public class CCAnswerPlaceholderAction extends DumbAwareAction { } @Nullable - private static CCState getState(@NotNull AnActionEvent e) { + protected static CCState getState(@NotNull AnActionEvent e) { final Project project = e.getProject(); - if (project == null || CCProjectService.getInstance(project).getCourse() == null) { + if (project == null || !CCUtils.isCourseCreator(project)) { return null; } final PsiFile psiFile = CommonDataKeys.PSI_FILE.getData(e.getDataContext()); @@ -40,27 +40,16 @@ abstract public class CCAnswerPlaceholderAction extends DumbAwareAction { if (editor == null) { return null; } - TaskFile taskFile = CCProjectService.getInstance(project).getTaskFile(virtualFile); + TaskFile taskFile = StudyUtils.getTaskFile(project, virtualFile); if (taskFile == null) { return null; } AnswerPlaceholder answerPlaceholder = taskFile.getAnswerPlaceholder(editor.getDocument(), editor.getCaretModel().getLogicalPosition(), true); - if (answerPlaceholder == null) { - return null; - } return new CCState(taskFile, answerPlaceholder, psiFile, editor, project); } - @Override - public void update(@NotNull AnActionEvent e) { - Presentation presentation = e.getPresentation(); - boolean isAvailable = getState(e) != null; - presentation.setEnabled(isAvailable); - presentation.setVisible(isAvailable); - } - @Override public void actionPerformed(@NotNull AnActionEvent e) { CCState state = getState(e); @@ -80,7 +69,7 @@ abstract public class CCAnswerPlaceholderAction extends DumbAwareAction { private Project myProject; public CCState(@NotNull final TaskFile taskFile, - @NotNull final AnswerPlaceholder answerPlaceholder, + @Nullable final AnswerPlaceholder answerPlaceholder, @NotNull final PsiFile file, @NotNull final Editor editor, @NotNull final Project project) { @@ -96,7 +85,7 @@ abstract public class CCAnswerPlaceholderAction extends DumbAwareAction { return myTaskFile; } - @NotNull + @Nullable public AnswerPlaceholder getAnswerPlaceholder() { return myAnswerPlaceholder; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAnswerPlaceholder.java deleted file mode 100644 index e385589b32bd..000000000000 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAnswerPlaceholder.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.jetbrains.edu.coursecreator.actions; - -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; -import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; -import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.coursecreator.CCProjectService; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -public class CCDeleteAnswerPlaceholder extends CCAnswerPlaceholderAction { - - public CCDeleteAnswerPlaceholder() { - super("Delete Answer Placeholder","Delete answer placeholder", null); - } - - @Override - protected void performAnswerPlaceholderAction(@NotNull CCState state) { - Project project = state.getProject(); - PsiFile psiFile = state.getFile(); - final Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile); - if (document == null) return; - TaskFile taskFile = state.getTaskFile(); - AnswerPlaceholder answerPlaceholder = state.getAnswerPlaceholder(); - final List answerPlaceholders = taskFile.getAnswerPlaceholders(); - if (answerPlaceholders.contains(answerPlaceholder)) { - answerPlaceholders.remove(answerPlaceholder); - final Editor editor = state.getEditor(); - editor.getMarkupModel().removeAllHighlighters(); - CCProjectService.getInstance(project).drawAnswerPlaceholders(psiFile.getVirtualFile(), editor); - EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, false); - } - } -} \ No newline at end of file diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java index b670ba1cb6c4..34ef6f000899 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java @@ -41,6 +41,8 @@ public class EduNames { public static final String STUDY = "Study"; public static String PYCHARM_ADDITIONAL = "PyCharm additional materials"; public static final String PYCHARM = "PyCharm"; + + public static String PLACEHOLDER = "Answer Placeholder"; private EduNames() { } From da3661da9132519441f089489498e09b0965976e Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 6 Apr 2016 17:51:45 +0300 Subject: [PATCH 08/65] refactoring of Delete All Answer Placeholders action --- .../CCDeleteAllAnswerPlaceholdersAction.java | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java index 55915d05bae4..aaabc9777eca 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java @@ -3,6 +3,7 @@ package com.jetbrains.edu.coursecreator.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.command.WriteCommandAction; @@ -14,10 +15,11 @@ import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.jetbrains.edu.learning.core.EduUtils; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.coursecreator.CCProjectService; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,7 +28,7 @@ import java.util.List; public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction { - public static final String ACTION_NAME = "Delete All Answer Placeholders"; + public static final String ACTION_NAME = "Delete All " + EduNames.PLACEHOLDER + "s"; public CCDeleteAllAnswerPlaceholdersAction() { super(ACTION_NAME); @@ -40,7 +42,7 @@ public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction { if (file == null || project == null) { return; } - final TaskFile taskFile = CCProjectService.getInstance(project).getTaskFile(file); + final TaskFile taskFile = StudyUtils.getTaskFile(project, file); if (taskFile == null) { return; } @@ -57,7 +59,7 @@ public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction { editor = ((TextEditor)fileEditor).getEditor(); } List placeholders = new ArrayList(taskFile.getAnswerPlaceholders()); - final ClearPlaceholders action = new ClearPlaceholders(taskFile, placeholders, editor, file, project); + final ClearPlaceholders action = new ClearPlaceholders(taskFile, placeholders, editor); new WriteCommandAction(project, ACTION_NAME) { protected void run(@NotNull final Result result) throws Throwable { action.redo(); @@ -72,60 +74,57 @@ public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction { } private static void updateView(@NotNull final Editor editor, - @NotNull final VirtualFile file, - @NotNull final Project project) { + @NotNull final TaskFile taskFile) { editor.getMarkupModel().removeAllHighlighters(); - CCProjectService.getInstance(project).drawAnswerPlaceholders(file, editor); + StudyUtils.drawAllWindows(editor, taskFile, false); } @Override public void update(AnActionEvent e) { - if (!CCProjectService.setCCActionAvailable(e)) { + Presentation presentation = e.getPresentation(); + presentation.setEnabledAndVisible(false); + + Project project = e.getProject(); + if (project == null) { + return; + } + if (!CCUtils.isCourseCreator(project)) { return; } DataContext context = e.getDataContext(); VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(context); - final Project project = e.getProject(); - if (file == null || project == null) { - EduUtils.enableAction(e, false); + if (file == null ) { return; } - TaskFile taskFile = CCProjectService.getInstance(project).getTaskFile(file); - if (taskFile == null) { - EduUtils.enableAction(e, false); + TaskFile taskFile = StudyUtils.getTaskFile(project, file); + if (taskFile == null || taskFile.getAnswerPlaceholders().isEmpty()) { return; } - if (taskFile.getAnswerPlaceholders().isEmpty()) { - EduUtils.enableAction(e, false); - } + presentation.setEnabledAndVisible(true); } private static class ClearPlaceholders implements UndoableAction { private final List myPlaceholders; private final Editor myEditor; - private final VirtualFile myFile; - private final Project myProject; TaskFile myTaskFile; - public ClearPlaceholders(TaskFile taskFile, List placeholders, Editor editor, VirtualFile file, Project project) { + public ClearPlaceholders(TaskFile taskFile, List placeholders, Editor editor) { myTaskFile = taskFile; myPlaceholders = placeholders; myEditor = editor; - myFile = file; - myProject = project; } @Override public void undo() throws UnexpectedUndoException { myTaskFile.getAnswerPlaceholders().addAll(myPlaceholders); - updateView(myEditor, myFile, myProject); + updateView(myEditor, myTaskFile); } @Override public void redo() throws UnexpectedUndoException { myTaskFile.getAnswerPlaceholders().clear(); - updateView(myEditor, myFile, myProject); + updateView(myEditor, myTaskFile); } @Nullable From 9a8d6c5b16062eb37bb726f9d6bb1354bd84846a Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 6 Apr 2016 17:52:27 +0300 Subject: [PATCH 09/65] separate action group for course creator project view actions --- .../course-creator/resources/META-INF/plugin.xml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index 9b90a825914a..971a70b3b76c 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -59,9 +59,16 @@ + + + + + + - + + @@ -84,11 +91,6 @@ - - - - - \ No newline at end of file From 36106d10863b24ca655f0ad6c4d0fab9c3d70037 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 6 Apr 2016 17:53:52 +0300 Subject: [PATCH 10/65] use correct placeholder length --- .../actions/CCAddAnswerPlaceholder.java | 2 +- .../com/jetbrains/edu/learning/StudyUtils.java | 9 ++++++--- .../editor/StudyEditorFactoryListener.java | 18 +++++++++++++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java index aab278175e0b..d7835cb5db04 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java @@ -98,7 +98,7 @@ public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction { answerPlaceholders.remove(answerPlaceholder); final Editor editor = state.getEditor(); editor.getMarkupModel().removeAllHighlighters(); - StudyUtils.drawAllWindows(editor, taskFile); + StudyUtils.drawAllWindows(editor, taskFile, false); EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, false); } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index 3db531be22d2..80fbb6a339b4 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -300,20 +300,23 @@ public class StudyUtils { return null; } - public static void drawAllWindows(Editor editor, TaskFile taskFile) { + drawAllWindows(editor, taskFile, true); + } + + public static void drawAllWindows(Editor editor, TaskFile taskFile, boolean useLength) { editor.getMarkupModel().removeAllHighlighters(); final Project project = editor.getProject(); if (project == null) return; final StudyTaskManager taskManager = StudyTaskManager.getInstance(project); for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) { final JBColor color = taskManager.getColor(answerPlaceholder); - EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, true, color); + EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, useLength, color); } final Document document = editor.getDocument(); EditorActionManager.getInstance() .setReadonlyFragmentModificationHandler(document, new EduAnswerPlaceholderDeleteHandler(editor)); - EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, true); + EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, useLength); editor.getColorsScheme().setColor(EditorColors.READONLY_FRAGMENT_BACKGROUND_COLOR, null); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java b/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java index 9a1eb88859f2..55a784a534cb 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java @@ -15,8 +15,11 @@ 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.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduDocumentListener; +import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; +import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.TaskFile; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.navigation.StudyNavigator; @@ -76,11 +79,20 @@ public class StudyEditorFactoryListener implements EditorFactoryListener { StudyUtils.updateToolWindows(project); studyToolWindow.show(null); } + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + return; + } + if (!taskFile.getAnswerPlaceholders().isEmpty()) { StudyNavigator.navigateToFirstAnswerPlaceholder(editor, taskFile); - StudyEditor.addDocumentListener(document, new EduDocumentListener(taskFile)); - StudyUtils.drawAllWindows(editor, taskFile); - editor.addEditorMouseListener(new WindowSelectionListener(taskFile)); + boolean isStudyProject = EduNames.STUDY.equals(course.getCourseType()); + StudyEditor.addDocumentListener(document, new EduDocumentListener(taskFile, true, + !isStudyProject)); + StudyUtils.drawAllWindows(editor, taskFile, isStudyProject); + if (isStudyProject) { + editor.addEditorMouseListener(new WindowSelectionListener(taskFile)); + } } } } From e6788ae141f3e20c2591c0564c2f56ac7821c4c5 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Thu, 7 Apr 2016 13:01:21 +0300 Subject: [PATCH 11/65] rename edit answer placeholder action and fix action update --- .../resources/META-INF/plugin.xml | 3 +++ ...ails.java => CCEditAnswerPlaceholder.java} | 20 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) rename python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/{CCShowAnswerPlaceholderDetails.java => CCEditAnswerPlaceholder.java} (62%) diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index 971a70b3b76c..2e95149ee8a6 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -59,6 +59,7 @@ + @@ -66,11 +67,13 @@ + + diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowAnswerPlaceholderDetails.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java similarity index 62% rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowAnswerPlaceholderDetails.java rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java index 7068c5e1c572..622ddacf1cac 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowAnswerPlaceholderDetails.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditAnswerPlaceholder.java @@ -1,5 +1,7 @@ package com.jetbrains.edu.coursecreator.actions; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; @@ -7,9 +9,9 @@ import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.coursecreator.ui.CCCreateAnswerPlaceholderDialog; import org.jetbrains.annotations.NotNull; -public class CCShowAnswerPlaceholderDetails extends CCAnswerPlaceholderAction { +public class CCEditAnswerPlaceholder extends CCAnswerPlaceholderAction { - public CCShowAnswerPlaceholderDetails() { + public CCEditAnswerPlaceholder() { super("Edit Answer Placeholder", "Edit answer placeholder", null); } @@ -21,9 +23,23 @@ public class CCShowAnswerPlaceholderDetails extends CCAnswerPlaceholderAction { final PsiDirectory lessonDir = taskDir.getParent(); if (lessonDir == null) return; AnswerPlaceholder answerPlaceholder = state.getAnswerPlaceholder(); + if (answerPlaceholder == null) { + return; + } CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder ); dlg.setTitle("Edit Answer Placeholder"); dlg.show(); } + + @Override + public void update(AnActionEvent e) { + Presentation presentation = e.getPresentation(); + presentation.setEnabledAndVisible(false); + CCState state = getState(e); + if (state == null || state.getAnswerPlaceholder() == null) { + return; + } + presentation.setEnabledAndVisible(true); + } } \ No newline at end of file From 55aae412f56b300d904c8e743f477395384476b8 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Thu, 7 Apr 2016 17:41:07 +0300 Subject: [PATCH 12/65] remove usages of redundant CCProjectService --- .../actions/CCAddAsTaskFile.java | 6 ++--- .../actions/CCCreateCourseArchive.java | 13 +++++----- .../actions/CCCreateTaskFile.java | 24 ++++--------------- .../actions/CCEditTaskTextAction.java | 4 ++-- .../coursecreator/actions/CCPushCourse.java | 10 +++++--- .../coursecreator/actions/CCPushLesson.java | 6 ++--- .../coursecreator/actions/CCShowPreview.java | 21 ++++++++-------- .../ui/CreateCourseArchiveDialog.java | 4 ++-- .../ui/CreateCourseArchivePanel.java | 2 +- 9 files changed, 40 insertions(+), 50 deletions(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java index 867cc77440b6..fa5423922e37 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java @@ -7,8 +7,8 @@ import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.courseFormat.Task; -import com.jetbrains.edu.coursecreator.CCProjectService; public class CCAddAsTaskFile extends AnAction { @Override @@ -21,7 +21,7 @@ public class CCAddAsTaskFile extends AnAction { if (file == null) { return; } - Task task = CCProjectService.getInstance(project).getTask(file); + Task task = StudyUtils.getTask(project, file); if (task == null) { return; } @@ -39,7 +39,7 @@ public class CCAddAsTaskFile extends AnAction { return; } VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); - if (file == null || file.isDirectory() || CCProjectService.getInstance(project).getTaskFile(file) != null) { + if (file == null || file.isDirectory() || StudyUtils.getTaskFile(project, file) != null) { presentation.setEnabledAndVisible(false); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java index 486f3b247c5d..bbef6bc15515 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java @@ -7,6 +7,7 @@ import com.intellij.ide.projectView.ProjectView; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; @@ -20,6 +21,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.util.containers.HashMap; import com.intellij.util.io.ZipUtil; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; @@ -27,7 +29,6 @@ import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.courseFormat.TaskFile; import com.jetbrains.edu.coursecreator.CCLanguageManager; -import com.jetbrains.edu.coursecreator.CCProjectService; import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.ui.CreateCourseArchiveDialog; import org.jetbrains.annotations.NotNull; @@ -56,7 +57,9 @@ public class CCCreateCourseArchive extends DumbAwareAction { @Override public void update(@NotNull AnActionEvent e) { - CCProjectService.setCCActionAvailable(e); + Presentation presentation = e.getPresentation(); + Project project = e.getProject(); + presentation.setEnabledAndVisible(project != null && CCUtils.isCourseCreator(project)); } @Override @@ -70,8 +73,7 @@ public class CCCreateCourseArchive extends DumbAwareAction { } private void createCourseArchive(final Project project, Module module) { - final CCProjectService service = CCProjectService.getInstance(project); - final Course course = service.getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null) return; CreateCourseArchiveDialog dlg = new CreateCourseArchiveDialog(project, this); dlg.show(); @@ -195,8 +197,7 @@ public class CCCreateCourseArchive extends DumbAwareAction { @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") private static void generateJson(@NotNull final Project project, VirtualFile parentDir) { - final CCProjectService service = CCProjectService.getInstance(project); - final Course course = service.getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); final String json = gson.toJson(course); final File courseJson = new File(parentDir.getPath(), EduNames.COURSE_META_FILE); diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java index eb5598625cce..88e14494ef39 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java @@ -19,12 +19,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.coursecreator.CCLanguageManager; -import com.jetbrains.edu.coursecreator.CCProjectService; import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.ui.CreateTaskFileDialog; import org.jetbrains.annotations.NotNull; @@ -51,8 +51,7 @@ public class CCCreateTaskFile extends DumbAwareAction { if (lessonDir == null) { return; } - final CCProjectService service = CCProjectService.getInstance(project); - final Course course = service.getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); final Lesson lesson = course.getLesson(lessonDir.getName()); final Task task = lesson.getTask(taskDir.getName()); @@ -105,39 +104,26 @@ public class CCCreateTaskFile extends DumbAwareAction { @Override public void update(@NotNull AnActionEvent event) { - if (!CCProjectService.setCCActionAvailable(event)) { - return; - } final Presentation presentation = event.getPresentation(); + presentation.setEnabledAndVisible(false); final Project project = event.getData(CommonDataKeys.PROJECT); if (project == null) { - presentation.setVisible(false); - presentation.setEnabled(false); return; } - final IdeView view = event.getData(LangDataKeys.IDE_VIEW); if (view == null) { - presentation.setVisible(false); - presentation.setEnabled(false); return; } final PsiDirectory[] directories = view.getDirectories(); if (directories.length == 0) { - presentation.setVisible(false); - presentation.setEnabled(false); return; } final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view); - final CCProjectService service = CCProjectService.getInstance(project); - final Course course = service.getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); if (course != null && directory != null && !directory.getName().contains(EduNames.TASK)) { - presentation.setVisible(false); - presentation.setEnabled(false); return; } - presentation.setVisible(true); - presentation.setEnabled(true); + presentation.setEnabledAndVisible(true); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java index a528ba6039b6..d86a0ae61754 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCEditTaskTextAction.java @@ -9,7 +9,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.jetbrains.edu.coursecreator.CCProjectService; +import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.learning.StudyState; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; @@ -74,7 +74,7 @@ public class CCEditTaskTextAction extends ToggleAction implements DumbAware { return; } - if (CCProjectService.getInstance(project).getCourse() == null) { + if (!CCUtils.isCourseCreator(project)) { e.getPresentation().setEnabledAndVisible(false); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java index 78410c9ad3a1..f1a1f3006bf6 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushCourse.java @@ -4,10 +4,12 @@ import com.intellij.ide.IdeView; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.coursecreator.CCProjectService; import com.jetbrains.edu.learning.stepic.EduStepicConnector; import org.jetbrains.annotations.NotNull; @@ -18,7 +20,9 @@ public class CCPushCourse extends DumbAwareAction { @Override public void update(@NotNull AnActionEvent e) { - CCProjectService.setCCActionAvailable(e); + Presentation presentation = e.getPresentation(); + Project project = e.getProject(); + presentation.setEnabledAndVisible(project != null && CCUtils.isCourseCreator(project)); } @Override @@ -28,7 +32,7 @@ public class CCPushCourse extends DumbAwareAction { if (view == null || project == null) { return; } - final Course course = CCProjectService.getInstance(project).getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null) { return; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java index 068b82bf0b1a..4e3f7ecc7414 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCPushLesson.java @@ -11,9 +11,9 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; -import com.jetbrains.edu.coursecreator.CCProjectService; import com.jetbrains.edu.learning.stepic.EduStepicConnector; import org.jetbrains.annotations.NotNull; @@ -30,7 +30,7 @@ public class CCPushLesson extends DumbAwareAction { if (view == null || project == null) { return; } - final Course course = CCProjectService.getInstance(project).getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null) { return; } @@ -51,7 +51,7 @@ public class CCPushLesson extends DumbAwareAction { if (view == null || project == null) { return; } - final Course course = CCProjectService.getInstance(project).getCourse(); + final Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null) { return; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java index f0662db25052..dd97b6f7f337 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java @@ -37,12 +37,13 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.ui.JBColor; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.coursecreator.CCProjectService; import com.jetbrains.edu.coursecreator.CCUtils; import org.jetbrains.annotations.NotNull; @@ -61,24 +62,23 @@ public class CCShowPreview extends DumbAwareAction { @Override public void update(@NotNull AnActionEvent e) { - if (!CCProjectService.setCCActionAvailable(e)) { - return; - } + Presentation presentation = e.getPresentation(); + presentation.setEnabledAndVisible(false); Project project = e.getProject(); if (project == null) { return; } - Presentation presentation = e.getPresentation(); - presentation.setEnabledAndVisible(false); + if (!CCUtils.isCourseCreator(project)) { + return; + } final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext()); - if (file != null && CCProjectService.getInstance(project).getTaskFile(file.getVirtualFile()) != null) { + if (file != null && StudyUtils.getTaskFile(project, file.getVirtualFile()) != null) { presentation.setEnabledAndVisible(true); } } @Override public void actionPerformed(@NotNull AnActionEvent e) { - //TODO: need to rewrite this action using new GENERATED_ROOT_FOLDER final Project project = e.getProject(); Module module = LangDataKeys.MODULE.getData(e.getDataContext()); if (project == null || module == null) { @@ -88,13 +88,12 @@ public class CCShowPreview extends DumbAwareAction { if (file == null) { return; } - final CCProjectService service = CCProjectService.getInstance(project); - Course course = service.getCourse(); + Course course = StudyTaskManager.getInstance(project).getCourse(); if (course == null) { return; } VirtualFile virtualFile = file.getVirtualFile(); - TaskFile taskFile = service.getTaskFile(virtualFile); + TaskFile taskFile = StudyUtils.getTaskFile(project, virtualFile); if (taskFile == null) { return; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchiveDialog.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchiveDialog.java index d1bc4fca3469..538665e54864 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchiveDialog.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchiveDialog.java @@ -2,8 +2,8 @@ package com.jetbrains.edu.coursecreator.ui; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.coursecreator.CCProjectService; import com.jetbrains.edu.coursecreator.actions.CCCreateCourseArchive; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,7 +17,7 @@ public class CreateCourseArchiveDialog extends DialogWrapper { public CreateCourseArchiveDialog(@NotNull final Project project, CCCreateCourseArchive action) { super(project); - Course course = CCProjectService.getInstance(project).getCourse(); + Course course = StudyTaskManager.getInstance(project).getCourse(); assert course != null; setTitle("Create Course Archive"); myPanel = new CreateCourseArchivePanel(project, this, course.getName()); diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchivePanel.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchivePanel.java index c84a5cdf2b26..1eeb2edd0b14 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchivePanel.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CreateCourseArchivePanel.java @@ -33,7 +33,7 @@ public class CreateCourseArchivePanel extends JPanel { myNameField.setText(sanitizedName.startsWith("_") ? EduNames.COURSE : sanitizedName); myLocationField.setText(project.getBasePath()); FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); - myLocationField.addBrowseFolderListener("Choose location folder", null, project, descriptor); + myLocationField.addBrowseFolderListener("Choose Location Folder", null, project, descriptor); myLocationField.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { From 237b65292068970aba29433895a606d70770dc47 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Thu, 7 Apr 2016 19:41:11 +0300 Subject: [PATCH 13/65] show invisible nodes in course creator project view --- .../projectView/CCDirectoryNode.java | 83 ------------------- .../projectView/CCTreeStructureProvider.java | 50 ++++------- .../StudyTreeStructureProvider.java | 21 +++-- 3 files changed, 28 insertions(+), 126 deletions(-) delete mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java deleted file mode 100644 index 551d344e3772..000000000000 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.jetbrains.edu.coursecreator.projectView; - -import com.intellij.ide.projectView.PresentationData; -import com.intellij.ide.projectView.ViewSettings; -import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDirectory; -import com.intellij.ui.SimpleTextAttributes; -import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.Lesson; -import com.jetbrains.edu.learning.courseFormat.Task; -import com.jetbrains.edu.coursecreator.CCProjectService; -import icons.InteractiveLearningIcons; -import org.jetbrains.annotations.NotNull; - -public class CCDirectoryNode extends PsiDirectoryNode { - private final PsiDirectory myValue; - private final Project myProject; - - public CCDirectoryNode(@NotNull final Project project, - PsiDirectory value, - ViewSettings viewSettings) { - super(project, value, viewSettings); - myValue = value; - myProject = project; - } - - @Override - protected void updateImpl(PresentationData data) { - String valueName = myValue.getName(); - final CCProjectService service = CCProjectService.getInstance(myProject); - final Course course = service.getCourse(); - if (course == null) return; - if (myProject.getBaseDir().equals(myValue.getVirtualFile())) { - data.clearText(); - data.setIcon(InteractiveLearningIcons.Course); - data.addText(course.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); - data.addText(" (" + valueName + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES); - return; - } - final Lesson lesson = course.getLesson(valueName); - if (lesson != null) { - data.clearText(); - data.setIcon(InteractiveLearningIcons.Lesson); - data.addText(lesson.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); - return; - } - else { - final PsiDirectory parentDir = myValue.getParentDirectory(); - if (parentDir != null) { - final Lesson parentLesson = course.getLesson(parentDir.getName()); - if (parentLesson != null) { - final Task task = parentLesson.getTask(valueName); - if (task != null) { - data.clearText(); - data.setIcon(InteractiveLearningIcons.Task); - data.addText(task.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); - return; - } - } - } - } - data.setPresentableText(valueName); - } - - @Override - public int getTypeSortWeight(boolean sortByType) { - String name = myValue.getName(); - if (name.startsWith(EduNames.LESSON) || name.startsWith(EduNames.TASK)) { - String logicalName = name.contains(EduNames.LESSON) ? EduNames.LESSON : EduNames.TASK; - int index = EduUtils.getIndex(name, logicalName) + 1; - return index != -1 ? index + 1: 0; - } - return 0; - } - - @Override - public String getNavigateActionText(boolean focusEditor) { - return null; - } -} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java index d4f39fbefd2f..2702e3d4cf56 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTreeStructureProvider.java @@ -1,23 +1,22 @@ package com.jetbrains.edu.coursecreator.projectView; -import com.intellij.ide.projectView.TreeStructureProvider; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.projectView.impl.nodes.PsiFileNode; import com.intellij.ide.util.treeView.AbstractTreeNode; -import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; -import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.coursecreator.CCProjectService; import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.projectView.StudyTreeStructureProvider; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; -public class CCTreeStructureProvider implements TreeStructureProvider, DumbAware { +public class CCTreeStructureProvider extends StudyTreeStructureProvider { @NotNull @Override public Collection modify(@NotNull AbstractTreeNode parent, @@ -26,18 +25,16 @@ public class CCTreeStructureProvider implements TreeStructureProvider, DumbAware if (!needModify(parent)) { return children; } - Collection nodes = new ArrayList(); + Collection modifiedChildren = new ArrayList(super.modify(parent, children, settings)); + for (AbstractTreeNode node : children) { Project project = node.getProject(); - if (project != null) { if (node.getValue() instanceof PsiDirectory) { String name = ((PsiDirectory)node.getValue()).getName(); - if (CCUtils.GENERATED_FILES_FOLDER.equals(name)) { + if ("zip".equals(FileUtilRt.getExtension(name))) { + modifiedChildren.add(node); continue; } - PsiDirectory directory = (PsiDirectory)node.getValue(); - nodes.add(new CCDirectoryNode(project, directory, settings)); - continue; } if (node instanceof PsiFileNode) { PsiFileNode fileNode = (PsiFileNode)node; @@ -45,34 +42,19 @@ public class CCTreeStructureProvider implements TreeStructureProvider, DumbAware if (virtualFile == null) { continue; } - if (virtualFile.getName().contains(EduNames.WINDOWS_POSTFIX)) { - continue; - } - - if (virtualFile.getParent().getName().contains(EduNames.TASK) && !CCProjectService.getInstance(project).isTaskFile(virtualFile)) { - nodes.add(new CCStudentInvisibleFileNode(project, ((PsiFileNode)node).getValue(), settings)); - continue; + if (StudyUtils.getTaskFile(project, virtualFile) == null && !EduNames.TASK_HTML.equals(virtualFile.getName())) { + modifiedChildren.add(new CCStudentInvisibleFileNode(project, ((PsiFileNode)node).getValue(), settings)); } } - nodes.add(node); - } } - return nodes; + return modifiedChildren; } - private static boolean needModify(@NotNull final AbstractTreeNode parent) { + protected boolean needModify(@NotNull final AbstractTreeNode parent) { Project project = parent.getProject(); - if (project != null) { - if (CCProjectService.getInstance(project).getCourse() == null) { - return false; - } + if (project == null) { + return false; } - return true; - } - - @Nullable - @Override - public Object getData(Collection selected, String dataName) { - return null; + return CCUtils.isCourseCreator(project); } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyTreeStructureProvider.java b/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyTreeStructureProvider.java index 6fd47eaece84..0a3a3e841feb 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyTreeStructureProvider.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/projectView/StudyTreeStructureProvider.java @@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.TaskFile; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; @@ -24,7 +25,7 @@ public class StudyTreeStructureProvider implements TreeStructureProvider, DumbAw public Collection modify(@NotNull AbstractTreeNode parent, @NotNull Collection children, ViewSettings settings) { - if (!isCourseBasedProject(parent)) { + if (!needModify(parent)) { return children; } Collection nodes = new ArrayList<>(); @@ -78,21 +79,23 @@ public class StudyTreeStructureProvider implements TreeStructureProvider, DumbAw if (!StudyTaskManager.getInstance(project).isInvisibleFile(virtualFile.getPath())) { String fileName = virtualFile.getName(); if (!fileName.contains(EduNames.WINDOW_POSTFIX) && !fileName.contains(EduNames.WINDOWS_POSTFIX) - && !StudyUtils.isTestsFile(project, fileName) && !EduNames.TASK_HTML.equals(fileName) && !fileName.contains(".answer")) { + && !StudyUtils.isTestsFile(project, fileName) && !EduNames.TASK_HTML.equals(fileName)) { nodes.add(node); } } } - protected boolean isCourseBasedProject(@NotNull final AbstractTreeNode parent) { + protected boolean needModify(@NotNull final AbstractTreeNode parent) { final Project project = parent.getProject(); - if (project != null) { - final StudyTaskManager studyTaskManager = StudyTaskManager.getInstance(project); - if (studyTaskManager.getCourse() == null) { - return false; - } + if (project == null) { + return false; } - return true; + final StudyTaskManager studyTaskManager = StudyTaskManager.getInstance(project); + Course course = studyTaskManager.getCourse(); + if (course == null) { + return false; + } + return EduNames.STUDY.equals(course.getCourseMode()); } @Nullable From ef1dc9ee9d57e34240714b32bd7f9e2e313e24c7 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Fri, 8 Apr 2016 13:11:14 +0300 Subject: [PATCH 14/65] merge course creator virtual file listeners --- .../CCEditorFactoryListener.java | 69 -------------- .../coursecreator/CCFileDeletedListener.java | 90 ------------------- .../edu/coursecreator/CCProjectComponent.java | 35 -------- .../coursecreator/CCVirtualFileListener.java | 80 ++++++++++++++++- 4 files changed, 76 insertions(+), 198 deletions(-) delete mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCEditorFactoryListener.java delete mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCEditorFactoryListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCEditorFactoryListener.java deleted file mode 100644 index 0ecea377388c..000000000000 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCEditorFactoryListener.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.jetbrains.edu.coursecreator; - -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.actionSystem.EditorActionManager; -import com.intellij.openapi.editor.colors.EditorColors; -import com.intellij.openapi.editor.event.EditorFactoryEvent; -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.jetbrains.edu.learning.core.EduAnswerPlaceholderDeleteHandler; -import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; -import com.jetbrains.edu.learning.core.EduDocumentListener; -import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.TaskFile; -import org.jetbrains.annotations.NotNull; - -public class CCEditorFactoryListener implements EditorFactoryListener { - @Override - public void editorCreated(@NotNull EditorFactoryEvent event) { - Editor editor = event.getEditor(); - Project project = editor.getProject(); - if (project == null) { - return; - } - VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(editor.getDocument()); - if (virtualFile == null) { - return; - } - final CCProjectService service = CCProjectService.getInstance(project); - Course course = service.getCourse(); - if (course == null) { - return; - } - final VirtualFile taskDir = virtualFile.getParent(); - if (taskDir == null || !taskDir.getName().contains(EduNames.TASK)) { - return; - } - final VirtualFile lessonDir = taskDir.getParent(); - if (lessonDir == null) return; - final TaskFile taskFile = service.getTaskFile(virtualFile); - if (taskFile == null) { - return; - } - EduDocumentListener listener = new EduDocumentListener(taskFile, true, true); - CCProjectService.addDocumentListener(editor.getDocument(), listener); - editor.getDocument().addDocumentListener(listener); - EditorActionManager.getInstance() - .setReadonlyFragmentModificationHandler(editor.getDocument(), new EduAnswerPlaceholderDeleteHandler(editor)); - service.drawAnswerPlaceholders(virtualFile, editor); - editor.getColorsScheme().setColor(EditorColors.READONLY_FRAGMENT_BACKGROUND_COLOR, null); - EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, false); - } - - @Override - public void editorReleased(@NotNull EditorFactoryEvent event) { - Editor editor = event.getEditor(); - Document document = editor.getDocument(); - EduDocumentListener listener = CCProjectService.getListener(document); - if (listener != null) { - document.removeDocumentListener(listener); - CCProjectService.removeListener(document); - } - editor.getMarkupModel().removeAllHighlighters(); - editor.getSelectionModel().removeSelection(); - } -} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java deleted file mode 100644 index 1d840f0c5943..000000000000 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCFileDeletedListener.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.jetbrains.edu.coursecreator; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileAdapter; -import com.intellij.openapi.vfs.VirtualFileEvent; -import com.intellij.util.Function; -import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.learning.courseFormat.*; -import org.jetbrains.annotations.NotNull; - -class CCFileDeletedListener extends VirtualFileAdapter { - - private final Project myProject; - - CCFileDeletedListener(@NotNull final Project project) { - myProject = project; - } - - @Override - public void fileDeleted(@NotNull VirtualFileEvent event) { - if (myProject.isDisposed() || !myProject.isOpen()) { - return; - } - VirtualFile removedFile = event.getFile(); - if (removedFile.getPath().contains(CCUtils.GENERATED_FILES_FOLDER)) { - return; - } - final TaskFile taskFile = CCProjectService.getInstance(myProject).getTaskFile(removedFile); - if (taskFile != null) { - deleteTaskFile(removedFile, taskFile); - return; - } - Course course = CCProjectService.getInstance(myProject).getCourse(); - if (course == null) { - return; - } - if (removedFile.getName().contains(EduNames.TASK)) { - deleteTask(course, removedFile, myProject); - } - if (removedFile.getName().contains(EduNames.LESSON)) { - deleteLesson(course, removedFile); - } - } - - private void deleteLesson(@NotNull final Course course, @NotNull final VirtualFile removedLessonFile) { - Lesson removedLesson = course.getLesson(removedLessonFile.getName()); - if (removedLesson == null) { - return; - } - VirtualFile courseDir = myProject.getBaseDir(); - CCUtils.updateHigherElements(courseDir.getChildren(), new Function() { - @Override - public StudyItem fun(VirtualFile file) { - return course.getLesson(file.getName()); - } - }, removedLesson.getIndex(), EduNames.LESSON, -1); - course.getLessons().remove(removedLesson); - } - - private static void deleteTask(@NotNull final Course course, @NotNull final VirtualFile removedTask, @NotNull final Project project) { - VirtualFile lessonDir = removedTask.getParent(); - if (lessonDir == null || !lessonDir.getName().contains(EduNames.LESSON)) { - return; - } - final Lesson lesson = course.getLesson(lessonDir.getName()); - if (lesson == null) { - return; - } - Task task = lesson.getTask(removedTask.getName()); - if (task == null) { - return; - } - CCUtils.updateHigherElements(lessonDir.getChildren(), new Function() { - @Override - public StudyItem fun(VirtualFile file) { - return lesson.getTask(file.getName()); - } - }, task.getIndex(), EduNames.TASK, -1); - lesson.getTaskList().remove(task); - } - - private static void deleteTaskFile(@NotNull final VirtualFile removedTaskFile, TaskFile taskFile) { - Task task = taskFile.getTask(); - if (task == null) { - return; - } - task.getTaskFiles().remove(removedTaskFile.getName()); - } -} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java index 25ba06fd9b30..2b91b9509dc2 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java @@ -1,18 +1,11 @@ package com.jetbrains.edu.coursecreator; import com.intellij.openapi.components.ProjectComponent; -import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFileManager; import org.jetbrains.annotations.NotNull; public class CCProjectComponent implements ProjectComponent { - private final Project myProject; private final CCVirtualFileListener myTaskFileLifeListener = new CCVirtualFileListener(); - private CCFileDeletedListener myListener; - - public CCProjectComponent(Project project) { - myProject = project; - } public void initComponent() { VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); @@ -28,37 +21,9 @@ public class CCProjectComponent implements ProjectComponent { public void projectOpened() { VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); - StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() { - @Override - public void run() { - final Course course = CCProjectService.getInstance(myProject).getCourse(); - if (course != null) { - course.initCourse(true); - myTaskFileLifeListener = new CCFileDeletedListener(myProject); - VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); - final CCEditorFactoryListener editorFactoryListener = new CCEditorFactoryListener(); - EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, myProject); - VirtualFile[] files = FileEditorManager.getInstance(myProject).getOpenFiles(); - for (VirtualFile file : files) { - if (CCProjectService.getInstance(myProject).isTaskFile(file)) { - FileEditorManager.getInstance(myProject).closeFile(file); - continue; - } - FileEditor fileEditor = FileEditorManager.getInstance(myProject).getSelectedEditor(file); - if (fileEditor instanceof PsiAwareTextEditorImpl) { - Editor editor = ((PsiAwareTextEditorImpl)fileEditor).getEditor(); - editorFactoryListener.editorCreated(new EditorFactoryEvent(new EditorFactoryImpl(ProjectManager.getInstance()), editor)); - } - } - } - } - }); } public void projectClosed() { VirtualFileManager.getInstance().removeVirtualFileListener(myTaskFileLifeListener); - if (myListener != null) { - VirtualFileManager.getInstance().removeVirtualFileListener(myTaskFileLifeListener); - } } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java index 2b42574ea946..aec7f6490863 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -7,12 +7,11 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileAdapter; import com.intellij.openapi.vfs.VirtualFileEvent; +import com.intellij.util.Function; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.Task; -import com.jetbrains.edu.learning.courseFormat.TaskFile; +import com.jetbrains.edu.learning.courseFormat.*; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -25,7 +24,7 @@ public class CCVirtualFileListener extends VirtualFileAdapter { @Override public void fileCreated(@NotNull VirtualFileEvent event) { VirtualFile createdFile = event.getFile(); - Project project = ProjectUtil.guessProjectForContentFile(createdFile); + Project project = ProjectUtil.guessProjectForFile(createdFile); if (project == null) { return; } @@ -77,4 +76,77 @@ public class CCVirtualFileListener extends VirtualFileAdapter { LOG.info("Failed to copy created task file to resources " + createdFile.getPath()); } } + + @Override + public void fileDeleted(@NotNull VirtualFileEvent event) { + VirtualFile removedFile = event.getFile(); + if (removedFile.getPath().contains(CCUtils.GENERATED_FILES_FOLDER)) { + return; + } + + Project project = ProjectUtil.guessProjectForFile(removedFile); + if (project == null) { + return; + } + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + return; + } + final TaskFile taskFile = StudyUtils.getTaskFile(project, removedFile); + if (taskFile != null) { + deleteTaskFile(removedFile, taskFile); + return; + } + if (removedFile.getName().contains(EduNames.TASK)) { + deleteTask(course, removedFile); + } + if (removedFile.getName().contains(EduNames.LESSON)) { + deleteLesson(course, removedFile, project); + } + } + + private static void deleteLesson(@NotNull final Course course, @NotNull final VirtualFile removedLessonFile, Project project) { + Lesson removedLesson = course.getLesson(removedLessonFile.getName()); + if (removedLesson == null) { + return; + } + VirtualFile courseDir = project.getBaseDir(); + CCUtils.updateHigherElements(courseDir.getChildren(), new Function() { + @Override + public StudyItem fun(VirtualFile file) { + return course.getLesson(file.getName()); + } + }, removedLesson.getIndex(), EduNames.LESSON, -1); + course.getLessons().remove(removedLesson); + } + + private static void deleteTask(@NotNull final Course course, @NotNull final VirtualFile removedTask) { + VirtualFile lessonDir = removedTask.getParent(); + if (lessonDir == null || !lessonDir.getName().contains(EduNames.LESSON)) { + return; + } + final Lesson lesson = course.getLesson(lessonDir.getName()); + if (lesson == null) { + return; + } + Task task = lesson.getTask(removedTask.getName()); + if (task == null) { + return; + } + CCUtils.updateHigherElements(lessonDir.getChildren(), new Function() { + @Override + public StudyItem fun(VirtualFile file) { + return lesson.getTask(file.getName()); + } + }, task.getIndex(), EduNames.TASK, -1); + lesson.getTaskList().remove(task); + } + + private static void deleteTaskFile(@NotNull final VirtualFile removedTaskFile, TaskFile taskFile) { + Task task = taskFile.getTask(); + if (task == null) { + return; + } + task.getTaskFiles().remove(removedTaskFile.getName()); + } } From f4e88fa2356357cd9eea8266316adca5b50a13ec Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Mon, 21 Mar 2016 15:14:48 +0300 Subject: [PATCH 15/65] Update tweeting api in study plugins * Create separate extension point to configure twitter * Show tweet panel before asking to authorize * Add input verifier to twitter panel (cherry picked from commit f7f46eb) --- .../student/resources/META-INF/plugin.xml | 1 + .../learning/StudyBasePluginConfigurator.java | 42 --- .../edu/learning/StudyPluginConfigurator.java | 46 --- .../StudyTwitterPluginConfigurator.java | 59 ++++ .../jetbrains/edu/learning/StudyUtils.java | 16 +- .../learning/twitter/StudyTwitterAction.java | 36 +-- .../learning/twitter/StudyTwitterUtils.java | 281 ++++++++++++------ 7 files changed, 268 insertions(+), 213 deletions(-) create mode 100644 python/educational-core/student/src/com/jetbrains/edu/learning/StudyTwitterPluginConfigurator.java diff --git a/python/educational-core/student/resources/META-INF/plugin.xml b/python/educational-core/student/resources/META-INF/plugin.xml index 68aca8e54232..c413fdbf17be 100644 --- a/python/educational-core/student/resources/META-INF/plugin.xml +++ b/python/educational-core/student/resources/META-INF/plugin.xml @@ -37,6 +37,7 @@ + diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java index cd204d70c63c..4fde0a889748 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java @@ -7,10 +7,8 @@ import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.edu.learning.actions.*; -import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.learning.twitter.StudyTwitterUtils; import com.jetbrains.edu.learning.ui.StudyToolWindow; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -97,44 +95,4 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur public StudyAfterCheckAction[] getAfterCheckActions() { return null; } - - @NotNull - @Override - public String getConsumerKey(@NotNull Project project) { - return ""; - } - - @NotNull - @Override - public String getConsumerSecret(@NotNull Project project) { - return ""; - } - - @Override - public void storeTwitterTokens(@NotNull Project project, @NotNull String accessToken, @NotNull String tokenSecret) { - // do nothing - } - - @NotNull - @Override - public String getTwitterTokenSecret(@NotNull Project project) { - return ""; - } - - @NotNull - @Override - public String getTwitterAccessToken(@NotNull Project project) { - return ""; - } - - @Override - public boolean askToTweet(@NotNull Project project, Task solvedTask, StudyStatus statusBeforeCheck) { - return false; - } - - @Nullable - @Override - public StudyTwitterUtils.TwitterDialogPanel getTweetDialogPanel(@NotNull Task solvedTask) { - return null; - } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java index 4aa1f272acb5..09cddf9b8e28 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyPluginConfigurator.java @@ -5,10 +5,7 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.project.Project; import com.jetbrains.edu.learning.actions.StudyAfterCheckAction; -import com.jetbrains.edu.learning.courseFormat.StudyStatus; -import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.settings.ModifiableSettingsPanel; -import com.jetbrains.edu.learning.twitter.StudyTwitterUtils; import com.jetbrains.edu.learning.ui.StudyToolWindow; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,7 +18,6 @@ public interface StudyPluginConfigurator { /** * Provide action group that should be placed on the tool window toolbar. - * @return */ @NotNull DefaultActionGroup getActionGroup(Project project); @@ -37,7 +33,6 @@ public interface StudyPluginConfigurator { FileEditorManagerListener getFileEditorManagerListener(@NotNull final Project project, @NotNull final StudyToolWindow toolWindow); /** - * * @return parameter for CodeMirror script. Available languages: @see <@linktourl http://codemirror.net/mode/> */ @NotNull String getDefaultHighlightingMode(); @@ -49,47 +44,6 @@ public interface StudyPluginConfigurator { @Nullable ModifiableSettingsPanel getSettingsPanel(); - - /** - * To implement tweeting you should register you app in twitter. For registered application twitter provide - * consumer key and consumer secret, that are used for authorize by OAuth. - * @return consumer key for current educational plugin - */ - @NotNull String getConsumerKey(@NotNull final Project project); - - /** - * To implement tweeting you should register you app in twitter. For registered application twitter provide - * consumer key and consumer secret, that are used for authorize by OAuth. - * @return consumer secret for current educational plugin - */ - @NotNull String getConsumerSecret(@NotNull final Project project); - - /** - * The plugin implemented tweeting should define policy when user will be asked to tweet. - *@param statusBeforeCheck @return - */ - boolean askToTweet(@NotNull final Project project, Task solvedTask, StudyStatus statusBeforeCheck); - - /** - * Stores access token and token secret, obtained by authorizing PyCharm. - */ - void storeTwitterTokens(@NotNull final Project project, @NotNull final String accessToken, @NotNull final String tokenSecret); - - /** - * @return stored access token - */ - @NotNull String getTwitterAccessToken(@NotNull Project project); - - /** - * @return stored token secret - */ - @NotNull String getTwitterTokenSecret(@NotNull Project project); - - /** - * @return panel that will be shown to user in ask to tweet dialog. - */ - @Nullable - StudyTwitterUtils.TwitterDialogPanel getTweetDialogPanel(@NotNull Task solvedTask); boolean accept(@NotNull final Project project); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTwitterPluginConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTwitterPluginConfigurator.java new file mode 100644 index 000000000000..ea9b8b4caa55 --- /dev/null +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyTwitterPluginConfigurator.java @@ -0,0 +1,59 @@ +package com.jetbrains.edu.learning; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.project.Project; +import com.jetbrains.edu.learning.courseFormat.StudyStatus; +import com.jetbrains.edu.learning.courseFormat.Task; +import com.jetbrains.edu.learning.twitter.StudyTwitterUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface StudyTwitterPluginConfigurator { + ExtensionPointName EP_NAME = ExtensionPointName.create("Edu.studyTwitterPluginConfigurator"); + + /** + * To implement tweeting you should register you app in twitter. For registered application twitter provide + * consumer key and consumer secret, that are used for authorize by OAuth. + * @return consumer key for current educational plugin + */ + @NotNull + String getConsumerKey(@NotNull final Project project); + + /** + * To implement tweeting you should register you app in twitter. For registered application twitter provide + * consumer key and consumer secret, that are used for authorize by OAuth. + * @return consumer secret for current educational plugin + */ + @NotNull String getConsumerSecret(@NotNull final Project project); + + /** + * The plugin implemented tweeting should define policy when user will be asked to tweet. + *@param statusBeforeCheck @return + */ + boolean askToTweet(@NotNull final Project project, Task solvedTask, StudyStatus statusBeforeCheck); + + /** + * Stores access token and token secret, obtained by authorizing PyCharm. + */ + void storeTwitterTokens(@NotNull final Project project, @NotNull final String accessToken, @NotNull final String tokenSecret); + + /** + * @return stored access token + */ + @NotNull String getTwitterAccessToken(@NotNull Project project); + + /** + * @return stored token secret + */ + @NotNull String getTwitterTokenSecret(@NotNull Project project); + + /** + * @return panel that will be shown to user in ask to tweet dialog. + */ + @Nullable + StudyTwitterUtils.TwitterDialogPanel getTweetDialogPanel(@NotNull Task solvedTask); + + void setAskToTweet(@NotNull Project project, boolean askToTweet); + + boolean accept(@NotNull final Project project); +} diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index 80fbb6a339b4..f0d68010a76d 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -36,12 +36,12 @@ import com.intellij.ui.JBColor; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.content.Content; import com.intellij.util.ui.UIUtil; +import com.jetbrains.edu.learning.checker.StudyExecutor; +import com.jetbrains.edu.learning.checker.StudyTestRunner; import com.jetbrains.edu.learning.core.EduAnswerPlaceholderDeleteHandler; import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.learning.checker.StudyExecutor; -import com.jetbrains.edu.learning.checker.StudyTestRunner; import com.jetbrains.edu.learning.courseFormat.*; import com.jetbrains.edu.learning.editor.StudyEditor; import com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory; @@ -464,6 +464,18 @@ public class StudyUtils { return null; } + @Nullable + public static StudyTwitterPluginConfigurator getTwitterConfigurator(@NotNull final Project project) { + StudyTwitterPluginConfigurator[] extensions = StudyTwitterPluginConfigurator.EP_NAME.getExtensions(); + for (StudyTwitterPluginConfigurator extension: extensions) { + if (extension.accept(project)) { + return extension; + } + } + return null; + } + + public static String getTaskText(@NotNull final Project project) { TaskFile taskFile = getSelectedTaskFile(project); if (taskFile == null) { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java index dd74afa0d273..b07a411d0b56 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java @@ -2,14 +2,11 @@ package com.jetbrains.edu.learning.twitter; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.jetbrains.edu.learning.StudyPluginConfigurator; -import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.StudyTwitterPluginConfigurator; import com.jetbrains.edu.learning.actions.StudyAfterCheckAction; import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.Task; import org.jetbrains.annotations.NotNull; -import twitter4j.Twitter; -import twitter4j.TwitterException; /** * Action that provide tweeting functionality to plugin. @@ -20,30 +17,17 @@ import twitter4j.TwitterException; */ public class StudyTwitterAction extends StudyAfterCheckAction { Logger LOG = Logger.getInstance(StudyTwitterAction.class); + private StudyTwitterPluginConfigurator myConfigurator; + + public StudyTwitterAction(@NotNull final StudyTwitterPluginConfigurator configurator) { + myConfigurator = configurator; + } + @Override public void run(@NotNull Project project, @NotNull Task solvedTask, StudyStatus statusBeforeCheck) { - try { - StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project); - if (configurator == null) { - LOG.warn("Plugin configurator not found"); - return; - } - - if (configurator.askToTweet(project, solvedTask, statusBeforeCheck)) { - boolean isAuthorized = !configurator.getTwitterAccessToken(project).isEmpty(); - Twitter twitter = StudyTwitterUtils.getTwitter(configurator.getConsumerKey(project), configurator.getConsumerSecret(project)); - StudyTwitterUtils.configureTwitter(twitter, project, isAuthorized); - StudyTwitterUtils.TwitterDialogPanel panel = configurator.getTweetDialogPanel(solvedTask); - if (panel != null) { - StudyTwitterUtils.showPostTweetDialogAndPostTweet(twitter, panel); - } - else { - LOG.warn("Plugin didn't provide twitter panel"); - } - } - } - catch (TwitterException e) { - LOG.warn(e.getMessage()); + + if (myConfigurator.askToTweet(project, solvedTask, statusBeforeCheck)) { + StudyTwitterUtils.createTwitterDialogAndShow(project, myConfigurator, solvedTask); } } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterUtils.java index 3fdab6b6a761..1192e7bea612 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterUtils.java @@ -4,13 +4,17 @@ import com.intellij.ide.BrowserUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogBuilder; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.InputValidatorEx; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.components.JBScrollPane; -import com.jetbrains.edu.learning.StudyPluginConfigurator; +import com.jetbrains.edu.learning.StudyTwitterPluginConfigurator; import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.courseFormat.Task; +import org.apache.http.HttpStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import twitter4j.StatusUpdate; @@ -24,6 +28,7 @@ import twitter4j.conf.ConfigurationBuilder; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import java.awt.*; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -32,32 +37,10 @@ import java.io.InputStream; public class StudyTwitterUtils { private static final Logger LOG = Logger.getInstance(StudyTwitterUtils.class); - - /** - * Configure twitter instance: authorize if needed or set access token and token secret provided by configurator. - * @param twitter - * @param project - * @param isAuthorized - * @throws TwitterException - */ - public static void configureTwitter(@NotNull final Twitter twitter, @NotNull final Project project, - final boolean isAuthorized) throws TwitterException { - if (!isAuthorized) { - authorize(project, twitter); - } - else { - StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project); - if (configurator != null) { - getTwitterForAuthorizedApp(twitter, configurator.getTwitterAccessToken(project), configurator.getTwitterTokenSecret(project)); - } - } - } - + /** * Set consumer key and secret. - * @param consumerKey - * @param consumerSecret - * @return + * @return Twitter instance with consumer key and secret set. */ @NotNull public static Twitter getTwitter(@NotNull final String consumerKey, @NotNull final String consumerSecret) { @@ -69,116 +52,222 @@ public class StudyTwitterUtils { /** * Set access token and token secret in Twitter instance - * @param twitter - * @param accessToken - * @param tokenSecret */ - private static void getTwitterForAuthorizedApp(Twitter twitter, @NotNull String accessToken, - @NotNull String tokenSecret) { + private static void setAuthInfoInTwitter(Twitter twitter, @NotNull String accessToken, + @NotNull String tokenSecret) { AccessToken token = new AccessToken(accessToken, tokenSecret); twitter.setOAuthAccessToken(token); } - /** - * Authorize user and save tokens by StudyPluginConfigurator#storeTwitterTokens - * @param project - * @param twitter - * @throws TwitterException - */ - public static void authorize(@NotNull final Project project, @NotNull final Twitter twitter) throws TwitterException { - RequestToken requestToken = twitter.getOAuthRequestToken(); - BrowserUtil.browse(requestToken.getAuthorizationURL()); - + public static void createTwitterDialogAndShow(@NotNull Project project, + @NotNull final StudyTwitterPluginConfigurator configurator, + @NotNull Task task) { ApplicationManager.getApplication().invokeLater(() -> { - String pin = Messages.showInputDialog("Twitter PIN:", "Twitter Authorization", null, "", null); - try { - AccessToken token; - if (pin != null && pin.length() > 0) { - token = twitter.getOAuthAccessToken(requestToken, pin); + DialogWrapper.DoNotAskOption doNotAskOption = createDoNotAskOption(project, configurator); + StudyTwitterUtils.TwitterDialogPanel panel = configurator.getTweetDialogPanel(task); + if (panel != null) { + TwitterDialogWrapper wrapper = new TwitterDialogWrapper(project, panel, doNotAskOption); + wrapper.setDoNotAskOption(doNotAskOption); + panel.addTextFieldVerifier(createTextFieldLengthDocumentListener(wrapper, panel)); + + if (wrapper.showAndGet()) { + try { + boolean isAuthorized = !configurator.getTwitterAccessToken(project).isEmpty(); + Twitter twitter = getTwitter(configurator.getConsumerKey(project), configurator.getConsumerSecret(project)); + if (!isAuthorized) { + authorizeAndUpdateStatus(project, twitter, panel); + } + else { + setAuthInfoInTwitter(twitter, configurator.getTwitterAccessToken(project), configurator.getTwitterTokenSecret(project)); + updateStatus(panel, twitter); + } + } + catch (TwitterException | IOException e) { + LOG.warn(e.getMessage()); + Messages.showErrorDialog("Status wasn\'t updated. Please, check internet connection and try again", "Twitter"); + } } else { - token = twitter.getOAuthAccessToken(); - } - StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project); - if (configurator != null) { - configurator.storeTwitterTokens(project, token.getToken(), token.getTokenSecret()); - } - else { - LOG.warn("Plugin configurator not found"); - } - } - catch (TwitterException e) { - if (401 == e.getStatusCode()) { - LOG.warn("Unable to get the access token."); - } - else { - LOG.warn(e.getMessage()); + LOG.warn("Panel is null"); } } }); } + + private static DialogWrapper.DoNotAskOption createDoNotAskOption(@NotNull final Project project, + @NotNull final StudyTwitterPluginConfigurator configurator) { + return new DialogWrapper.DoNotAskOption() { + @Override + public boolean isToBeShown() { + return true; + } + + @Override + public void setToBeShown(boolean toBeShown, int exitCode) { + if (exitCode == DialogWrapper.CANCEL_EXIT_CODE || exitCode == DialogWrapper.OK_EXIT_CODE) { + configurator.setAskToTweet(project, toBeShown); + } + } + + @Override + public boolean canBeHidden() { + return true; + } + + @Override + public boolean shouldSaveOptionsOnCancel() { + return true; + } + + @NotNull + @Override + public String getDoNotShowMessage() { + return "Never ask me to tweet"; + } + }; + } + + /** + * Post on twitter media and text from panel + * @param panel shown to user and used to provide data to post + */ + public static void updateStatus(StudyTwitterUtils.TwitterDialogPanel panel, Twitter twitter) throws IOException, TwitterException { + StatusUpdate update = new StatusUpdate(panel.getMessage()); + InputStream e = panel.getMediaSource(); + if (e != null) { + File imageFile = FileUtil.createTempFile("twitter_media", panel.getMediaExtension()); + FileUtil.copy(e, new FileOutputStream(imageFile)); + update.media(imageFile); + } + + twitter.updateStatus(update); + BrowserUtil.browse("https://twitter.com/"); + } + /** * Show twitter dialog, asking user to tweet about his achievements. Post tweet with provided by panel * media and text. * As a result of succeeded tweet twitter website is opened in default browser. - * @param twitter - * @param twitterDialogPanel */ - public static void showPostTweetDialogAndPostTweet(@NotNull Twitter twitter, @NotNull final TwitterDialogPanel twitterDialogPanel) { + public static void authorizeAndUpdateStatus(@NotNull final Project project, @NotNull final Twitter twitter, + @NotNull final StudyTwitterUtils.TwitterDialogPanel panel) throws TwitterException { + RequestToken requestToken = twitter.getOAuthRequestToken(); + BrowserUtil.browse(requestToken.getAuthorizationURL()); + ApplicationManager.getApplication().invokeLater(() -> { - DialogBuilder builder = new DialogBuilder(); - twitterDialogPanel.addTextFieldVerifier(createTextFieldLengthDocumentListener(builder, twitterDialogPanel)); - builder.title("Twitter"); - builder.addOkAction().setText("Tweet"); - builder.addCancelAction(); - builder.setCenterPanel(new JBScrollPane(twitterDialogPanel)); - builder.resizable(true); - if (builder.showAndGet()) { - StatusUpdate update = new StatusUpdate(twitterDialogPanel.getMessage()); + String pin = createAndShowPinDialog(); + if (pin != null) { try { - InputStream inputStream = twitterDialogPanel.getMediaSource(); - if (inputStream != null) { - File imageFile = FileUtil.createTempFile("twitter_media", "gif"); - - FileUtil.copy(inputStream, new FileOutputStream(imageFile)); - update.media(imageFile); + AccessToken token = twitter.getOAuthAccessToken(requestToken, pin); + StudyTwitterPluginConfigurator configurator = StudyUtils.getTwitterConfigurator(project); + if (configurator != null) { + configurator.storeTwitterTokens(project, token.getToken(), token.getTokenSecret()); + updateStatus(panel, twitter); + } + else { + LOG.warn("No twitter configurator is provided for the plugin"); } - twitter.updateStatus(update); - BrowserUtil.browse("https://twitter.com/"); } - catch (IOException | TwitterException e) { + catch (TwitterException e) { + if (e.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { + LOG.warn("Unable to get the access token."); + LOG.warn(e.getMessage()); + } + } + catch (IOException e) { LOG.warn(e.getMessage()); - Messages.showErrorDialog("Status wasn't updated. Please, check internet connection and try again", "Twitter"); } } }); } + public static String createAndShowPinDialog() { + return Messages.showInputDialog("Twitter PIN:", "Twitter Authorization", null, "", new InputValidatorEx() { + @Nullable + @Override + public String getErrorText(String inputString) { + inputString = inputString.trim(); + if (inputString.isEmpty()) { + return "PIN shouldn't be empty."; + } + if (!isNumeric(inputString)) { + return "PIN should be numeric."; + } + return null; + } + + @Override + public boolean checkInput(String inputString) { + return getErrorText(inputString) == null; + } + + @Override + public boolean canClose(String inputString) { + return true; + } + + private boolean isNumeric(@NotNull final String string) { + for (char c: string.toCharArray()) { + if (!StringUtil.isDecimalDigit(c)) { + return false; + } + } + return true; + } + }); + } + /** * Listener updates label indicating remaining symbols number like in twitter. - * @param builder - * @param panel - * @return */ - public static DocumentListener createTextFieldLengthDocumentListener(@NotNull DialogBuilder builder, @NotNull final TwitterDialogPanel panel) { + private static DocumentListener createTextFieldLengthDocumentListener(@NotNull TwitterDialogWrapper builder, @NotNull final StudyTwitterUtils.TwitterDialogPanel panel) { return new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { int length = e.getDocument().getLength(); if (length > 140 || length == 0) { - builder.setOkActionEnabled(false); + builder.setOKActionEnabled(false); panel.getRemainSymbolsLabel().setText("" + String.valueOf(140 - length) + ""); - } - else { - builder.setOkActionEnabled(true); + } else { + builder.setOKActionEnabled(true); panel.getRemainSymbolsLabel().setText(String.valueOf(140 - length)); } - + } }; } + /** + * Dialog wrapper class with DoNotAsl option for asking user to tweet. + * */ + private static class TwitterDialogWrapper extends DialogWrapper { + private StudyTwitterUtils.TwitterDialogPanel myPanel; + + TwitterDialogWrapper(@Nullable Project project, @NotNull StudyTwitterUtils.TwitterDialogPanel panel, DoNotAskOption doNotAskOption) { + super(project); + setTitle("Twitter"); + setDoNotAskOption(doNotAskOption); + setOKButtonText("Tweet"); + setCancelButtonText("No"); + setResizable(true); + Dimension preferredSize = panel.getPreferredSize(); + setSize((int) preferredSize.getHeight(), (int) preferredSize.getWidth()); + myPanel = panel; + init(); + } + + public void setOKActionEnabled(boolean isEnabled) { + super.setOKActionEnabled(isEnabled); + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + return new JBScrollPane(myPanel); + } + } + /** * Class provides structure for twitter dialog panel */ @@ -186,25 +275,23 @@ public class StudyTwitterUtils { /** * Provides tweet text - * @return */ @NotNull public abstract String getMessage(); /** - * * @return Input stream of media should be posted or null if there's nothing to post */ @Nullable public abstract InputStream getMediaSource(); + + @Nullable public abstract String getMediaExtension(); /** - * * @return label that will be used to show remained symbol number */ @NotNull public abstract JLabel getRemainSymbolsLabel(); /** * Api to add document listener to field containing tweet text - * @param documentListener */ public abstract void addTextFieldVerifier(@NotNull final DocumentListener documentListener); From 558bf752c22ae5945f45184787e43b47e1d8bf8d Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Mon, 21 Mar 2016 15:22:47 +0300 Subject: [PATCH 16/65] Remove obsolete dependencies from student and educational-core (cherry picked from commit a326837) --- python/educational-core/educational-core.iml | 5 ----- python/educational-core/student/student.iml | 1 - 2 files changed, 6 deletions(-) diff --git a/python/educational-core/educational-core.iml b/python/educational-core/educational-core.iml index 26234628d69d..aa1983234de3 100644 --- a/python/educational-core/educational-core.iml +++ b/python/educational-core/educational-core.iml @@ -8,11 +8,6 @@ - - - - - \ No newline at end of file diff --git a/python/educational-core/student/student.iml b/python/educational-core/student/student.iml index 348ee0a814c1..80c21a26244e 100644 --- a/python/educational-core/student/student.iml +++ b/python/educational-core/student/student.iml @@ -11,7 +11,6 @@ - From adc71565b8ffcd4897623d23058efd91c64f0195 Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Tue, 22 Mar 2016 16:51:08 +0300 Subject: [PATCH 17/65] Show content without code highlighting if configurator wasn't found (cherry picked from commit 3d5feb8) --- .../src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java | 3 +-- .../src/com/jetbrains/edu/learning/ui/StudyToolWindow.java | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java index 790725070af8..fd7a12a5e01e 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyBrowserWindow.java @@ -126,8 +126,7 @@ class StudyBrowserWindow extends JFrame { public void loadContent(@NotNull final String content, @Nullable StudyPluginConfigurator configurator) { if (configurator == null) { - Platform.runLater(() -> myEngine.loadContent("Seems like desired plugin doesn't installed")); - LOG.warn("No StudyPluginConfigurator is provided for the plugin"); + Platform.runLater(() -> myEngine.loadContent(content)); } else { String withCodeHighlighting = createHtmlWithCodeHighlighting(content, configurator); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java index 96817aa4a794..feb06b72159a 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java @@ -97,9 +97,6 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D myContentPanel.add(entry.getKey(), entry.getValue()); } } - else { - LOG.warn("No StudyPluginConfigurator is provided for the plugin"); - } } public void dispose() { From 940bf15182ac9060546e2d16efd2edc626ce9583 Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Thu, 24 Mar 2016 12:52:28 +0300 Subject: [PATCH 18/65] Minor Rename study settings (cherry picked from commit 4ed5e0f) --- python/educational-core/student/resources/META-INF/plugin.xml | 2 +- .../com/jetbrains/edu/learning/settings/StudyConfigurable.java | 2 +- .../com/jetbrains/edu/learning/twitter/StudyTwitterAction.java | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/python/educational-core/student/resources/META-INF/plugin.xml b/python/educational-core/student/resources/META-INF/plugin.xml index c413fdbf17be..f9042db9c577 100644 --- a/python/educational-core/student/resources/META-INF/plugin.xml +++ b/python/educational-core/student/resources/META-INF/plugin.xml @@ -79,7 +79,7 @@ + displayName="Education"/> diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java b/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java index eff51e506e35..990dd8f2cbf4 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/settings/StudyConfigurable.java @@ -50,7 +50,7 @@ public class StudyConfigurable implements SearchableConfigurable { @Nls @Override public String getDisplayName() { - return "Educational"; + return "Education"; } @NotNull diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java index b07a411d0b56..df03c7de7e21 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java @@ -1,6 +1,5 @@ package com.jetbrains.edu.learning.twitter; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.jetbrains.edu.learning.StudyTwitterPluginConfigurator; import com.jetbrains.edu.learning.actions.StudyAfterCheckAction; @@ -16,7 +15,6 @@ import org.jetbrains.annotations.NotNull; * methods in StudyPluginConfigurator instance of your plugin. */ public class StudyTwitterAction extends StudyAfterCheckAction { - Logger LOG = Logger.getInstance(StudyTwitterAction.class); private StudyTwitterPluginConfigurator myConfigurator; public StudyTwitterAction(@NotNull final StudyTwitterPluginConfigurator configurator) { From 8db217b524e949f312fcdf9345de519c93eae203 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Fri, 8 Apr 2016 16:30:28 +0300 Subject: [PATCH 19/65] fix unpack course action --- .../coursecreator/actions/CCFromCourseArchive.java | 12 +++++++----- .../edu/learning/courseFormat/AnswerPlaceholder.java | 4 ++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java index a7c6a91dc52e..7c45e53a920e 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java @@ -22,10 +22,11 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.platform.templates.github.ZipUtil; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduDocumentListener; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.coursecreator.CCProjectService; import com.jetbrains.edu.learning.courseFormat.*; import com.jetbrains.edu.learning.oldCourseFormat.OldCourse; import org.jetbrains.annotations.NotNull; @@ -58,7 +59,6 @@ public class CCFromCourseArchive extends DumbAwareAction { } final String basePath = project.getBasePath(); if (basePath == null) return; - final CCProjectService service = CCProjectService.getInstance(project); Reader reader = null; try { ZipUtil.unzip(null, new File(basePath), new File(virtualFile.getPath()), null, null, true); @@ -77,7 +77,8 @@ public class CCFromCourseArchive extends DumbAwareAction { course = EduUtils.transformOldCourse(oldCourse); } - service.setCourse(course); + StudyTaskManager.getInstance(project).setCourse(course); + course.setCourseMode(CCUtils.COURSE_MODE); project.getBaseDir().refresh(false, true); int index = 1; int taskIndex = 1; @@ -94,7 +95,7 @@ public class CCFromCourseArchive extends DumbAwareAction { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - createAnswerFile(project, taskDir, taskDir, entry); + createAnswerFile(project, taskDir, entry); } }); } @@ -103,6 +104,7 @@ public class CCFromCourseArchive extends DumbAwareAction { index += 1; taskIndex = 1; } + course.initCourse(true); } catch (FileNotFoundException e) { LOG.error(e.getMessage()); @@ -128,7 +130,6 @@ public class CCFromCourseArchive extends DumbAwareAction { public static void createAnswerFile(@NotNull final Project project, @NotNull final VirtualFile userFileDir, - @NotNull final VirtualFile answerFileDir, @NotNull final Map.Entry taskFileEntry) { final String name = taskFileEntry.getKey(); final TaskFile taskFile = taskFileEntry.getValue(); @@ -185,6 +186,7 @@ public class CCFromCourseArchive extends DumbAwareAction { public void run() { final String text = document.getText(TextRange.create(offset, offset + answerPlaceholder.getLength())); answerPlaceholder.setTaskText(text); + answerPlaceholder.init(); final VirtualFile hints = project.getBaseDir().findChild(EduNames.HINTS); if (hints != null) { final String hintFile = answerPlaceholder.getHint(); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java index e086091d6d8c..d4bbf56287f7 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java @@ -156,6 +156,10 @@ public class AnswerPlaceholder { mySelected = selected; } + public void init() { + setInitialState(new MyInitialState(line, possibleAnswer.length(), start)); + } + public static class MyInitialState { public int myLine = -1; public int myLength = -1; From 59764b415c1779c1c70674871a60f8690186a210 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Fri, 8 Apr 2016 16:33:38 +0300 Subject: [PATCH 20/65] fix serialization --- .../edu/coursecreator/ui/CCCreateAnswerPlaceholderDialog.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderDialog.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderDialog.java index 5f984acf1d95..68470f1e40df 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderDialog.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderDialog.java @@ -53,6 +53,8 @@ public class CCCreateAnswerPlaceholderDialog extends DialogWrapper { myAnswerPlaceholder.setTaskText(StringUtil.notNullize(answerPlaceholderText)); myAnswerPlaceholder.setLength(StringUtil.notNullize(answerPlaceholderText).length()); myAnswerPlaceholder.setHint(myPanel.getHintText()); + AnswerPlaceholder.MyInitialState initialState = new AnswerPlaceholder.MyInitialState(myAnswerPlaceholder.getLine(), answerPlaceholderText.length(), myAnswerPlaceholder.getStart()); + myAnswerPlaceholder.setInitialState(initialState); super.doOKAction(); } From cee89f6661d40ede42e64386b65e013f722a884c Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Sun, 10 Apr 2016 11:44:42 +0300 Subject: [PATCH 21/65] group actions in action groups --- .../resources/META-INF/plugin.xml | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index 2e95149ee8a6..f4ed102a7bb9 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -27,10 +27,6 @@ - - - - com.jetbrains.edu.coursecreator.CCProjectComponent @@ -47,21 +43,29 @@ - - - - - - + + + + + + + + + + + + + + @@ -74,26 +78,7 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 6a0dcfa7c40987b764069ef499cd643df70ac8fe Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Sun, 10 Apr 2016 11:48:27 +0300 Subject: [PATCH 22/65] commit changes to pattern document before study check action --- .../resources/META-INF/plugin.xml | 1 + .../CCStudyCheckActionListener.java | 57 +++++++ .../coursecreator/CCVirtualFileListener.java | 140 +++++++++--------- .../student/resources/META-INF/plugin.xml | 1 + .../learning/StudyCheckActionListener.java | 10 ++ .../jetbrains/edu/learning/StudyUtils.java | 16 ++ .../learning/actions/StudyCheckAction.java | 5 + .../jetbrains/edu/learning/core/EduNames.java | 1 + 8 files changed, 163 insertions(+), 68 deletions(-) create mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyCheckActionListener.java create mode 100644 python/educational-core/student/src/com/jetbrains/edu/learning/StudyCheckActionListener.java diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index f4ed102a7bb9..0cf48fbdd13e 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -25,6 +25,7 @@ + diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyCheckActionListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyCheckActionListener.java new file mode 100644 index 000000000000..a3a50fb127a1 --- /dev/null +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyCheckActionListener.java @@ -0,0 +1,57 @@ +package com.jetbrains.edu.coursecreator; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.DocumentUtil; +import com.jetbrains.edu.learning.StudyCheckActionListener; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.courseFormat.Task; +import com.jetbrains.edu.learning.courseFormat.TaskFile; + +import java.util.Map; + +public class CCStudyCheckActionListener implements StudyCheckActionListener { + @Override + public void beforeCheck(AnActionEvent event) { + Project project = event.getProject(); + if (project == null) { + return; + } + VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(event.getDataContext()); + if (virtualFile == null) { + return; + } + + TaskFile taskFile = StudyUtils.getTaskFile(project, virtualFile); + if (taskFile == null) { + return; + } + + Task task = taskFile.getTask(); + VirtualFile taskDir = StudyUtils.getTaskDir(virtualFile); + if (taskDir == null) { + return; + } + Map files = task.getTaskFiles(); + for (Map.Entry entry : files.entrySet()) { + String name = entry.getKey(); + VirtualFile child = taskDir.findChild(name); + if (child == null) { + continue; + } + Document patternDocument = StudyUtils.getPatternDocument(entry.getValue(), name); + Document document = FileDocumentManager.getInstance().getDocument(virtualFile); + if (document == null || patternDocument == null) { + return; + } + DocumentUtil.writeInRunUndoTransparentAction(() -> { + patternDocument.replaceString(0, patternDocument.getTextLength(), document.getCharsSequence()); + FileDocumentManager.getInstance().saveDocument(patternDocument); + }); + } + } +} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java index aec7f6490863..0f1d76cf38f8 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -37,7 +37,11 @@ public class CCVirtualFileListener extends VirtualFileAdapter { return; } - if (CCUtils.isTestsFile(project, createdFile) || EduNames.TASK_HTML.equals(createdFile.getName())) { + String name = createdFile.getName(); + if (CCUtils.isTestsFile(project, createdFile) + || EduNames.TASK_HTML.equals(name) + || name.contains(EduNames.WINDOW_POSTFIX) + || name.contains(EduNames.WINDOWS_POSTFIX)) { return; } @@ -45,14 +49,14 @@ public class CCVirtualFileListener extends VirtualFileAdapter { if (taskVF == null) { return; } - Task task = StudyUtils.getTask(project,taskVF); + Task task = StudyUtils.getTask(project, taskVF); if (task == null) { return; } createResourceFile(createdFile, course, taskVF); - task.addTaskFile(createdFile.getName(), 1); + task.addTaskFile(name, 1); } private static void createResourceFile(VirtualFile createdFile, Course course, VirtualFile taskVF) { @@ -77,76 +81,76 @@ public class CCVirtualFileListener extends VirtualFileAdapter { } } - @Override - public void fileDeleted(@NotNull VirtualFileEvent event) { - VirtualFile removedFile = event.getFile(); - if (removedFile.getPath().contains(CCUtils.GENERATED_FILES_FOLDER)) { - return; - } - - Project project = ProjectUtil.guessProjectForFile(removedFile); - if (project == null) { - return; - } - Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course == null) { - return; - } - final TaskFile taskFile = StudyUtils.getTaskFile(project, removedFile); - if (taskFile != null) { - deleteTaskFile(removedFile, taskFile); - return; - } - if (removedFile.getName().contains(EduNames.TASK)) { - deleteTask(course, removedFile); - } - if (removedFile.getName().contains(EduNames.LESSON)) { - deleteLesson(course, removedFile, project); - } + @Override + public void fileDeleted(@NotNull VirtualFileEvent event) { + VirtualFile removedFile = event.getFile(); + if (removedFile.getPath().contains(CCUtils.GENERATED_FILES_FOLDER)) { + return; } - private static void deleteLesson(@NotNull final Course course, @NotNull final VirtualFile removedLessonFile, Project project) { - Lesson removedLesson = course.getLesson(removedLessonFile.getName()); - if (removedLesson == null) { - return; - } - VirtualFile courseDir = project.getBaseDir(); - CCUtils.updateHigherElements(courseDir.getChildren(), new Function() { - @Override - public StudyItem fun(VirtualFile file) { - return course.getLesson(file.getName()); - } - }, removedLesson.getIndex(), EduNames.LESSON, -1); - course.getLessons().remove(removedLesson); + Project project = ProjectUtil.guessProjectForFile(removedFile); + if (project == null) { + return; } + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + return; + } + final TaskFile taskFile = StudyUtils.getTaskFile(project, removedFile); + if (taskFile != null) { + deleteTaskFile(removedFile, taskFile); + return; + } + if (removedFile.getName().contains(EduNames.TASK)) { + deleteTask(course, removedFile); + } + if (removedFile.getName().contains(EduNames.LESSON)) { + deleteLesson(course, removedFile, project); + } + } - private static void deleteTask(@NotNull final Course course, @NotNull final VirtualFile removedTask) { - VirtualFile lessonDir = removedTask.getParent(); - if (lessonDir == null || !lessonDir.getName().contains(EduNames.LESSON)) { - return; - } - final Lesson lesson = course.getLesson(lessonDir.getName()); - if (lesson == null) { - return; - } - Task task = lesson.getTask(removedTask.getName()); - if (task == null) { - return; - } - CCUtils.updateHigherElements(lessonDir.getChildren(), new Function() { - @Override - public StudyItem fun(VirtualFile file) { - return lesson.getTask(file.getName()); - } - }, task.getIndex(), EduNames.TASK, -1); - lesson.getTaskList().remove(task); + private static void deleteLesson(@NotNull final Course course, @NotNull final VirtualFile removedLessonFile, Project project) { + Lesson removedLesson = course.getLesson(removedLessonFile.getName()); + if (removedLesson == null) { + return; } + VirtualFile courseDir = project.getBaseDir(); + CCUtils.updateHigherElements(courseDir.getChildren(), new Function() { + @Override + public StudyItem fun(VirtualFile file) { + return course.getLesson(file.getName()); + } + }, removedLesson.getIndex(), EduNames.LESSON, -1); + course.getLessons().remove(removedLesson); + } - private static void deleteTaskFile(@NotNull final VirtualFile removedTaskFile, TaskFile taskFile) { - Task task = taskFile.getTask(); - if (task == null) { - return; - } - task.getTaskFiles().remove(removedTaskFile.getName()); + private static void deleteTask(@NotNull final Course course, @NotNull final VirtualFile removedTask) { + VirtualFile lessonDir = removedTask.getParent(); + if (lessonDir == null || !lessonDir.getName().contains(EduNames.LESSON)) { + return; } + final Lesson lesson = course.getLesson(lessonDir.getName()); + if (lesson == null) { + return; + } + Task task = lesson.getTask(removedTask.getName()); + if (task == null) { + return; + } + CCUtils.updateHigherElements(lessonDir.getChildren(), new Function() { + @Override + public StudyItem fun(VirtualFile file) { + return lesson.getTask(file.getName()); + } + }, task.getIndex(), EduNames.TASK, -1); + lesson.getTaskList().remove(task); + } + + private static void deleteTaskFile(@NotNull final VirtualFile removedTaskFile, TaskFile taskFile) { + Task task = taskFile.getTask(); + if (task == null) { + return; + } + task.getTaskFiles().remove(removedTaskFile.getName()); + } } diff --git a/python/educational-core/student/resources/META-INF/plugin.xml b/python/educational-core/student/resources/META-INF/plugin.xml index f9042db9c577..09972c848d73 100644 --- a/python/educational-core/student/resources/META-INF/plugin.xml +++ b/python/educational-core/student/resources/META-INF/plugin.xml @@ -38,6 +38,7 @@ + diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyCheckActionListener.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyCheckActionListener.java new file mode 100644 index 000000000000..14b3b502d014 --- /dev/null +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyCheckActionListener.java @@ -0,0 +1,10 @@ +package com.jetbrains.edu.learning; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.extensions.ExtensionPointName; + +public interface StudyCheckActionListener { + ExtensionPointName EP_NAME = ExtensionPointName.create("Edu.studyCheckActionListener"); + + void beforeCheck(AnActionEvent event); +} diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index f0d68010a76d..5c64769542d6 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -529,4 +529,20 @@ public class StudyUtils { } return lesson.getTask(taskVF.getName()); } + + @Nullable + public static VirtualFile getTaskDir(@NotNull VirtualFile taskFile) { + VirtualFile parent = taskFile.getParent(); + if (parent == null) { + return null; + } + String name = parent.getName(); + if (name.contains(EduNames.TASK)) { + return parent; + } + if (EduNames.SRC.equals(name)) { + return parent.getParent(); + } + return null; + } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java index 5c42608382f1..a3b0295dbe41 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java @@ -3,11 +3,13 @@ package com.jetbrains.edu.learning.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.KeyboardShortcut; import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Ref; +import com.jetbrains.edu.learning.StudyCheckActionListener; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.checker.StudyCheckUtils; import icons.InteractiveLearningIcons; @@ -36,6 +38,9 @@ public abstract class StudyCheckAction extends StudyActionWithShortcut { StudyCheckUtils.showTestResultPopUp("Checking is not available while indexing is in progress", MessageType.WARNING.getPopupBackground(), project); return; } + for (StudyCheckActionListener listener : Extensions.getExtensions(StudyCheckActionListener.EP_NAME)) { + listener.beforeCheck(e); + } check(project); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java index 34ef6f000899..e076fdd92212 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java @@ -43,6 +43,7 @@ public class EduNames { public static final String PYCHARM = "PyCharm"; public static String PLACEHOLDER = "Answer Placeholder"; + public static String SRC = "src"; private EduNames() { } From f23ef59f7e3e65f69b35fa399534bbcff14379ba Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Sun, 10 Apr 2016 16:33:47 +0300 Subject: [PATCH 23/65] fix refresh actions for course creator projects --- .../resources/META-INF/plugin.xml | 2 +- ...stener.java => CCStudyActionListener.java} | 12 +++++- .../coursecreator/CCVirtualFileListener.java | 3 +- .../actions/CCAddAnswerPlaceholder.java | 40 +++++++++++++++++-- .../CCDeleteAllAnswerPlaceholdersAction.java | 2 +- .../actions/CCFromCourseArchive.java | 4 +- .../coursecreator/actions/CCShowPreview.java | 2 +- .../ui/CCCreateAnswerPlaceholderDialog.java | 2 - .../student/resources/META-INF/plugin.xml | 2 +- ...Listener.java => StudyActionListener.java} | 4 +- ...udyAnswerPlaceholderExtendWordHandler.java | 2 +- .../jetbrains/edu/learning/StudyUtils.java | 8 +--- .../learning/actions/StudyCheckAction.java | 4 +- .../actions/StudyFillPlaceholdersAction.java | 2 +- .../StudyRefreshAnswerPlaceholder.java | 7 +++- .../actions/StudyRefreshTaskFileAction.java | 13 ++++-- .../edu/learning/checker/StudyCheckUtils.java | 6 +-- .../learning/checker/StudySmartChecker.java | 4 +- .../core/EduAnswerPlaceholderPainter.java | 20 +++++----- .../learning/core/EduDocumentListener.java | 14 +------ .../jetbrains/edu/learning/core/EduNames.java | 1 + .../jetbrains/edu/learning/core/EduUtils.java | 9 ++++- .../courseFormat/AnswerPlaceholder.java | 28 ++++++++++++- .../edu/learning/courseFormat/TaskFile.java | 2 +- .../editor/StudyEditorFactoryListener.java | 10 ++--- 25 files changed, 135 insertions(+), 68 deletions(-) rename python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/{CCStudyCheckActionListener.java => CCStudyActionListener.java} (78%) rename python/educational-core/student/src/com/jetbrains/edu/learning/{StudyCheckActionListener.java => StudyActionListener.java} (55%) diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index 0cf48fbdd13e..def669884579 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -25,7 +25,7 @@ - + diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyCheckActionListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java similarity index 78% rename from python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyCheckActionListener.java rename to python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java index a3a50fb127a1..921f97697115 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyCheckActionListener.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java @@ -7,14 +7,16 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.DocumentUtil; -import com.jetbrains.edu.learning.StudyCheckActionListener; +import com.jetbrains.edu.learning.StudyActionListener; import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.core.EduUtils; +import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.courseFormat.TaskFile; import java.util.Map; -public class CCStudyCheckActionListener implements StudyCheckActionListener { +public class CCStudyActionListener implements StudyActionListener { @Override public void beforeCheck(AnActionEvent event) { Project project = event.getProject(); @@ -52,6 +54,12 @@ public class CCStudyCheckActionListener implements StudyCheckActionListener { patternDocument.replaceString(0, patternDocument.getTextLength(), document.getCharsSequence()); FileDocumentManager.getInstance().saveDocument(patternDocument); }); + TaskFile target = new TaskFile(); + TaskFile.copy(taskFile, target); + for (AnswerPlaceholder placeholder : target.getAnswerPlaceholders()) { + placeholder.setUseLength(false); + } + EduUtils.createStudentDocument(project, target, child, patternDocument); } } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java index 0f1d76cf38f8..967d885cdf2e 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -41,7 +41,8 @@ public class CCVirtualFileListener extends VirtualFileAdapter { if (CCUtils.isTestsFile(project, createdFile) || EduNames.TASK_HTML.equals(name) || name.contains(EduNames.WINDOW_POSTFIX) - || name.contains(EduNames.WINDOWS_POSTFIX)) { + || name.contains(EduNames.WINDOWS_POSTFIX) + || name.contains(EduNames.ANSWERS_POSTFIX)) { return; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java index d7835cb5db04..5eae370909ee 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAnswerPlaceholder.java @@ -5,15 +5,18 @@ import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.ui.JBColor; +import com.intellij.util.DocumentUtil; import com.jetbrains.edu.coursecreator.ui.CCCreateAnswerPlaceholderDialog; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.TaskFile; import org.jetbrains.annotations.NotNull; @@ -57,6 +60,7 @@ public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction { final AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder(); answerPlaceholder.setLine(lineNumber); answerPlaceholder.setStart(realStart); + answerPlaceholder.setUseLength(false); String selectedText = model.getSelectedText(); answerPlaceholder.setPossibleAnswer(selectedText); @@ -70,9 +74,37 @@ public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction { int index = taskFile.getAnswerPlaceholders().size() + 1; answerPlaceholder.setIndex(index); taskFile.addAnswerPlaceholder(answerPlaceholder); + answerPlaceholder.setTaskFile(taskFile); taskFile.sortAnswerPlaceholders(); - EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, false, JBColor.BLUE); - EduAnswerPlaceholderPainter.createGuardedBlocks(editor, answerPlaceholder, false); + + + computeInitialState(project, file, taskFile, document); + + EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, JBColor.BLUE); + EduAnswerPlaceholderPainter.createGuardedBlocks(editor, answerPlaceholder); + } + + private static void computeInitialState(Project project, PsiFile file, TaskFile taskFile, Document document) { + Document patternDocument = StudyUtils.getPatternDocument(taskFile, file.getName()); + if (patternDocument == null) { + return; + } + DocumentUtil.writeInRunUndoTransparentAction(() -> { + patternDocument.replaceString(0, patternDocument.getTextLength(), document.getCharsSequence()); + FileDocumentManager.getInstance().saveDocument(patternDocument); + }); + TaskFile target = new TaskFile(); + TaskFile.copy(taskFile, target); + List placeholders = target.getAnswerPlaceholders(); + for (AnswerPlaceholder placeholder : placeholders) { + placeholder.setUseLength(false); + } + EduUtils.createStudentDocument(project, target, file.getVirtualFile(), patternDocument); + + for (int i = 0; i < placeholders.size(); i++) { + AnswerPlaceholder fromPlaceholder = placeholders.get(i); + taskFile.getAnswerPlaceholders().get(i).setInitialState(fromPlaceholder); + } } @Override @@ -98,8 +130,8 @@ public class CCAddAnswerPlaceholder extends CCAnswerPlaceholderAction { answerPlaceholders.remove(answerPlaceholder); final Editor editor = state.getEditor(); editor.getMarkupModel().removeAllHighlighters(); - StudyUtils.drawAllWindows(editor, taskFile, false); - EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, false); + StudyUtils.drawAllWindows(editor, taskFile); + EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java index aaabc9777eca..0916e1b678f4 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCDeleteAllAnswerPlaceholdersAction.java @@ -76,7 +76,7 @@ public class CCDeleteAllAnswerPlaceholdersAction extends DumbAwareAction { private static void updateView(@NotNull final Editor editor, @NotNull final TaskFile taskFile) { editor.getMarkupModel().removeAllHighlighters(); - StudyUtils.drawAllWindows(editor, taskFile, false); + StudyUtils.drawAllWindows(editor, taskFile); } @Override diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java index 7c45e53a920e..97fdb1ec2e57 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java @@ -184,7 +184,7 @@ public class CCFromCourseArchive extends DumbAwareAction { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - final String text = document.getText(TextRange.create(offset, offset + answerPlaceholder.getLength())); + final String text = document.getText(TextRange.create(offset, offset + answerPlaceholder.getRealLength())); answerPlaceholder.setTaskText(text); answerPlaceholder.init(); final VirtualFile hints = project.getBaseDir().findChild(EduNames.HINTS); @@ -200,7 +200,7 @@ public class CCFromCourseArchive extends DumbAwareAction { } } - document.replaceString(offset, offset + answerPlaceholder.getLength(), answerPlaceholder.getPossibleAnswer()); + document.replaceString(offset, offset + answerPlaceholder.getRealLength(), answerPlaceholder.getPossibleAnswer()); FileDocumentManager.getInstance().saveDocument(document); } }); diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java index dd97b6f7f337..39a2ce7f4e0d 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java @@ -148,7 +148,7 @@ public class CCShowPreview extends DumbAwareAction { } }); for (AnswerPlaceholder answerPlaceholder : taskFileCopy.getAnswerPlaceholders()) { - EduAnswerPlaceholderPainter.drawAnswerPlaceholder(createdEditor, answerPlaceholder, true, JBColor.BLUE); + EduAnswerPlaceholderPainter.drawAnswerPlaceholder(createdEditor, answerPlaceholder, JBColor.BLUE); } JPanel header = new JPanel(); header.setLayout(new BoxLayout(header, BoxLayout.Y_AXIS)); diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderDialog.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderDialog.java index 68470f1e40df..5f984acf1d95 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderDialog.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/ui/CCCreateAnswerPlaceholderDialog.java @@ -53,8 +53,6 @@ public class CCCreateAnswerPlaceholderDialog extends DialogWrapper { myAnswerPlaceholder.setTaskText(StringUtil.notNullize(answerPlaceholderText)); myAnswerPlaceholder.setLength(StringUtil.notNullize(answerPlaceholderText).length()); myAnswerPlaceholder.setHint(myPanel.getHintText()); - AnswerPlaceholder.MyInitialState initialState = new AnswerPlaceholder.MyInitialState(myAnswerPlaceholder.getLine(), answerPlaceholderText.length(), myAnswerPlaceholder.getStart()); - myAnswerPlaceholder.setInitialState(initialState); super.doOKAction(); } diff --git a/python/educational-core/student/resources/META-INF/plugin.xml b/python/educational-core/student/resources/META-INF/plugin.xml index 09972c848d73..ff7ddbab656a 100644 --- a/python/educational-core/student/resources/META-INF/plugin.xml +++ b/python/educational-core/student/resources/META-INF/plugin.xml @@ -38,7 +38,7 @@ - + diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyCheckActionListener.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionListener.java similarity index 55% rename from python/educational-core/student/src/com/jetbrains/edu/learning/StudyCheckActionListener.java rename to python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionListener.java index 14b3b502d014..525adc2eddd3 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyCheckActionListener.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyActionListener.java @@ -3,8 +3,8 @@ package com.jetbrains.edu.learning; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.extensions.ExtensionPointName; -public interface StudyCheckActionListener { - ExtensionPointName EP_NAME = ExtensionPointName.create("Edu.studyCheckActionListener"); +public interface StudyActionListener { + ExtensionPointName EP_NAME = ExtensionPointName.create("Edu.studyActionListener"); void beforeCheck(AnActionEvent event); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyAnswerPlaceholderExtendWordHandler.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyAnswerPlaceholderExtendWordHandler.java index 8ebc8f4dadd6..ad364dfc02f2 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyAnswerPlaceholderExtendWordHandler.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyAnswerPlaceholderExtendWordHandler.java @@ -59,6 +59,6 @@ public class StudyAnswerPlaceholderExtendWordHandler implements ExtendWordSelect Document document = FileDocumentManager.getInstance().getDocument(file); assert document != null; int startOffset = placeholder.getRealStartOffset(document); - return Collections.singletonList(new TextRange(startOffset, startOffset + placeholder.getLength())); + return Collections.singletonList(new TextRange(startOffset, startOffset + placeholder.getRealLength())); } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index 5c64769542d6..590bf97c79aa 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -301,22 +301,18 @@ public class StudyUtils { } public static void drawAllWindows(Editor editor, TaskFile taskFile) { - drawAllWindows(editor, taskFile, true); - } - - public static void drawAllWindows(Editor editor, TaskFile taskFile, boolean useLength) { editor.getMarkupModel().removeAllHighlighters(); final Project project = editor.getProject(); if (project == null) return; final StudyTaskManager taskManager = StudyTaskManager.getInstance(project); for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) { final JBColor color = taskManager.getColor(answerPlaceholder); - EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, useLength, color); + EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, color); } final Document document = editor.getDocument(); EditorActionManager.getInstance() .setReadonlyFragmentModificationHandler(document, new EduAnswerPlaceholderDeleteHandler(editor)); - EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, useLength); + EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile); editor.getColorsScheme().setColor(EditorColors.READONLY_FRAGMENT_BACKGROUND_COLOR, null); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java index a3b0295dbe41..623c7326972a 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java @@ -9,7 +9,7 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Ref; -import com.jetbrains.edu.learning.StudyCheckActionListener; +import com.jetbrains.edu.learning.StudyActionListener; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.checker.StudyCheckUtils; import icons.InteractiveLearningIcons; @@ -38,7 +38,7 @@ public abstract class StudyCheckAction extends StudyActionWithShortcut { StudyCheckUtils.showTestResultPopUp("Checking is not available while indexing is in progress", MessageType.WARNING.getPopupBackground(), project); return; } - for (StudyCheckActionListener listener : Extensions.getExtensions(StudyCheckActionListener.EP_NAME)) { + for (StudyActionListener listener : Extensions.getExtensions(StudyActionListener.EP_NAME)) { listener.beforeCheck(e); } check(project); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java index e65c8a02bd6d..54c8e2c4ac08 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java @@ -36,7 +36,7 @@ public class StudyFillPlaceholdersAction extends AnAction { continue; } int offset = placeholder.getRealStartOffset(document); - document.deleteString(offset, offset + placeholder.getLength()); + document.deleteString(offset, offset + placeholder.getRealLength()); document.insertString(offset, answer); } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java index 42a7674c384b..7daa54735398 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java @@ -6,9 +6,11 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; +import com.jetbrains.edu.learning.StudyActionListener; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.TaskFile; import com.jetbrains.edu.learning.StudyState; @@ -30,6 +32,9 @@ public class StudyRefreshAnswerPlaceholder extends DumbAwareAction { if (project == null) { return; } + for (StudyActionListener listener : Extensions.getExtensions(StudyActionListener.EP_NAME)) { + listener.beforeCheck(e); + } final AnswerPlaceholder answerPlaceholder = getAnswerPlaceholder(e); if (answerPlaceholder == null) { return; @@ -51,7 +56,7 @@ public class StudyRefreshAnswerPlaceholder extends DumbAwareAction { public void run() { Document document = studyState.getEditor().getDocument(); int offset = answerPlaceholder.getRealStartOffset(document); - document.deleteString(offset, offset + answerPlaceholder.getLength()); + document.deleteString(offset, offset + answerPlaceholder.getRealLength()); document.insertString(offset, text); } }); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java index 2a421abdb131..fc8acd144103 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java @@ -9,6 +9,7 @@ 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.extensions.Extensions; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; @@ -19,13 +20,14 @@ import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.problems.WolfTheProblemSolver; +import com.jetbrains.edu.learning.StudyActionListener; +import com.jetbrains.edu.learning.StudyState; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.TaskFile; -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 com.jetbrains.edu.learning.navigation.StudyNavigator; import org.jetbrains.annotations.NotNull; @@ -73,7 +75,7 @@ public class StudyRefreshTaskFileAction extends StudyActionWithShortcut { WolfTheProblemSolver.getInstance(project).clearProblems(studyState.getVirtualFile()); taskFile.setHighlightErrors(false); StudyUtils.drawAllWindows(editor, taskFile); - EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile, true); + EduAnswerPlaceholderPainter.createGuardedBlocks(editor, taskFile); ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { @@ -147,6 +149,9 @@ public class StudyRefreshTaskFileAction extends StudyActionWithShortcut { public void actionPerformed(@NotNull AnActionEvent event) { final Project project = event.getProject(); if (project != null) { + for (StudyActionListener listener : Extensions.getExtensions(StudyActionListener.EP_NAME)) { + listener.beforeCheck(event); + } refresh(project); } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java index 9fe0ae84ae6b..33c626a05bcb 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java @@ -21,6 +21,7 @@ import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.StatusBarEx; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.jetbrains.edu.learning.core.EduDocumentListener; +import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.Task; @@ -38,7 +39,6 @@ import java.util.List; import java.util.Map; public class StudyCheckUtils { - private static final String ANSWERS_POSTFIX = "_answers"; private static final Logger LOG = Logger.getInstance(StudyCheckUtils.class); private StudyCheckUtils() { @@ -143,7 +143,7 @@ public class StudyCheckUtils { VirtualFile copy = null; try { - copy = file.copy(taskDir, taskDir, file.getNameWithoutExtension() + ANSWERS_POSTFIX + "." + file.getExtension()); + copy = file.copy(taskDir, taskDir, file.getNameWithoutExtension() + EduNames.ANSWERS_POSTFIX + "." + file.getExtension()); final FileDocumentManager documentManager = FileDocumentManager.getInstance(); final Document document = documentManager.getDocument(copy); if (document != null) { @@ -155,7 +155,7 @@ public class StudyCheckUtils { continue; } final int start = answerPlaceholder.getRealStartOffset(document); - final int end = start + answerPlaceholder.getLength(); + final int end = start + answerPlaceholder.getRealLength(); final String text = answerPlaceholder.getPossibleAnswer(); document.replaceString(start, end, text); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java index 7cd660635d84..14870203abac 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/checker/StudySmartChecker.java @@ -54,10 +54,10 @@ public class StudySmartChecker { EduDocumentListener listener = new EduDocumentListener(windowTaskFile); windowDocument.addDocumentListener(listener); int start = placeholder.getRealStartOffset(windowDocument); - int end = start + placeholder.getLength(); + int end = start + placeholder.getRealLength(); final AnswerPlaceholder userAnswerPlaceholder = usersTaskFile.getAnswerPlaceholders().get(placeholder.getIndex()); int userStart = userAnswerPlaceholder.getRealStartOffset(usersDocument); - int userEnd = userStart + userAnswerPlaceholder.getLength(); + int userEnd = userStart + userAnswerPlaceholder.getRealLength(); String text = usersDocument.getText(new TextRange(userStart, userEnd)); windowDocument.replaceString(start, end, text); ApplicationManager.getApplication().runWriteAction(() -> { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduAnswerPlaceholderPainter.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduAnswerPlaceholderPainter.java index 528b58e26102..81fcf85fb989 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduAnswerPlaceholderPainter.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduAnswerPlaceholderPainter.java @@ -26,9 +26,9 @@ public class EduAnswerPlaceholderPainter { } public static void drawAnswerPlaceholder(@NotNull final Editor editor, @NotNull final AnswerPlaceholder placeholder, - boolean useLength, @NotNull final JBColor color) { + @NotNull final JBColor color) { final Document document = editor.getDocument(); - if (useLength && !placeholder.isValid(document)) { + if (!placeholder.isValid(document)) { return; } EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme(); @@ -37,10 +37,8 @@ public class EduAnswerPlaceholderPainter { final Project project = editor.getProject(); assert project != null; final int startOffset = placeholder.getRealStartOffset(document); - final int length = placeholder.getLength(); - final int replacementLength = placeholder.getPossibleAnswerLength(); - int highlighterLength = useLength ? length : replacementLength; - final int endOffset = startOffset + highlighterLength; + final int length = placeholder.getRealLength(); + final int endOffset = startOffset + length; textAttributes.setEffectColor(color); RangeHighlighter highlighter = editor.getMarkupModel().addRangeHighlighter(startOffset, endOffset, PLACEHOLDERS_LAYER, @@ -56,20 +54,20 @@ public class EduAnswerPlaceholderPainter { } - public static void createGuardedBlocks(@NotNull final Editor editor, TaskFile taskFile, boolean useLength) { + public static void createGuardedBlocks(@NotNull final Editor editor, TaskFile taskFile) { for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) { - createGuardedBlocks(editor, answerPlaceholder, useLength); + createGuardedBlocks(editor, answerPlaceholder); } } - public static void createGuardedBlocks(@NotNull final Editor editor, AnswerPlaceholder placeholder, boolean useLength) { + public static void createGuardedBlocks(@NotNull final Editor editor, AnswerPlaceholder placeholder) { Document document = editor.getDocument(); if (document instanceof DocumentImpl) { DocumentImpl documentImpl = (DocumentImpl)document; List blocks = documentImpl.getGuardedBlocks(); - if (useLength && !placeholder.isValid(document)) return; + if (!placeholder.isValid(document)) return; int start = placeholder.getRealStartOffset(document); - final int length = useLength ? placeholder.getLength() : placeholder.getPossibleAnswerLength(); + final int length = placeholder.getRealLength(); int end = start + length; if (start != 0) { createGuardedBlock(editor, blocks, start - 1, start); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduDocumentListener.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduDocumentListener.java index 77e02bb15154..8e43bf57b26b 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduDocumentListener.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduDocumentListener.java @@ -18,29 +18,19 @@ import java.util.List; public class EduDocumentListener extends DocumentAdapter { private final TaskFile myTaskFile; private final boolean myTrackLength; - private final boolean usePossibleAnswerLength; private final List myAnswerPlaceholders = new ArrayList(); public EduDocumentListener(TaskFile taskFile) { myTaskFile = taskFile; myTrackLength = true; - usePossibleAnswerLength = false; } public EduDocumentListener(TaskFile taskFile, boolean trackLength) { myTaskFile = taskFile; myTrackLength = trackLength; - usePossibleAnswerLength = false; } - public EduDocumentListener(TaskFile taskFile, boolean trackLength, boolean usePossibleAnswerLength) { - myTaskFile = taskFile; - myTrackLength = trackLength; - this.usePossibleAnswerLength = usePossibleAnswerLength; - } - - //remembering old end before document change because of problems // with fragments containing "\n" @Override @@ -53,7 +43,7 @@ public class EduDocumentListener extends DocumentAdapter { myAnswerPlaceholders.clear(); for (AnswerPlaceholder answerPlaceholder : myTaskFile.getAnswerPlaceholders()) { int twStart = answerPlaceholder.getRealStartOffset(document); - int length = usePossibleAnswerLength ? answerPlaceholder.getPossibleAnswerLength() : answerPlaceholder.getLength(); + int length = answerPlaceholder.getRealLength(); int twEnd = twStart + length; myAnswerPlaceholders.add(new AnswerPlaceholderWrapper(answerPlaceholder, twStart, twEnd)); } @@ -85,7 +75,7 @@ public class EduDocumentListener extends DocumentAdapter { int length = twEnd - twStart; answerPlaceholder.setLine(line); answerPlaceholder.setStart(start); - if (usePossibleAnswerLength) { + if (!answerPlaceholder.getUseLength()) { answerPlaceholder.setPossibleAnswer(document.getText(TextRange.create(twStart, twStart + length))); } else if (myTrackLength) { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java index e076fdd92212..a6062cb25339 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduNames.java @@ -32,6 +32,7 @@ public class EduNames { public static final String USER_TEST_OUTPUT = "output"; public static final String WINDOW_POSTFIX = "_window."; public static final String WINDOWS_POSTFIX = "_windows"; + public static final String ANSWERS_POSTFIX = "_answers"; public static final String USER_TESTS = "userTests"; public static final String TESTS_FILE = "tests.py"; public static final String TEST_HELPER = "test_helper.py"; diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java index 4b4870673a23..b095bc94815e 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java @@ -95,7 +95,7 @@ public class EduUtils { fileWindows = taskDir.createChildData(taskFile, name); printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath())); for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) { - int length = useLength ? answerPlaceholder.getLength() : answerPlaceholder.getPossibleAnswerLength(); + int length = answerPlaceholder.getRealLength(); if (!answerPlaceholder.isValid(document, length)) { printWriter.println("#educational_plugin_window = "); continue; @@ -192,6 +192,13 @@ public class EduUtils { }); } }, "Create Student File", "Create Student File"); + createStudentDocument(project, taskFile, file, document); + } + + public static void createStudentDocument(@NotNull Project project, + @NotNull TaskFile taskFile, + VirtualFile file, + final Document document) { EduDocumentListener listener = new EduDocumentListener(taskFile, false); document.addDocumentListener(listener); taskFile.sortAnswerPlaceholders(); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java index d4bbf56287f7..72f2b422b7f8 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java @@ -25,6 +25,7 @@ public class AnswerPlaceholder { private MyInitialState myInitialState; private StudyStatus myStatus = StudyStatus.Uninitialized; private boolean mySelected = false; + private boolean myUseLength = true; @Transient private TaskFile myTaskFile; @@ -45,6 +46,9 @@ public class AnswerPlaceholder { myIndex = index; } + /** + * in actions {@link AnswerPlaceholder#getRealLength()} should be used + */ public int getLength() { return length; } @@ -138,6 +142,9 @@ public class AnswerPlaceholder { line = myInitialState.myLine; start = myInitialState.myStart; length = myInitialState.myLength; + if (!getUseLength()) { + possibleAnswer = myTaskText; + } } public StudyStatus getStatus() { @@ -157,7 +164,26 @@ public class AnswerPlaceholder { } public void init() { - setInitialState(new MyInitialState(line, possibleAnswer.length(), start)); + setInitialState(new MyInitialState(line, myTaskText.length(), start)); + } + + public boolean getUseLength() { + return myUseLength; + } + + /** + * @return length or possible answer length + */ + public int getRealLength() { + return myUseLength ? getLength() : getPossibleAnswerLength(); + } + + public void setUseLength(boolean useLength) { + myUseLength = useLength; + } + + public void setInitialState(AnswerPlaceholder placeholder) { + setInitialState(new MyInitialState(placeholder.line, placeholder.length, placeholder.start)); } public static class MyInitialState { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java index ceb8dd92ac2c..0bd0fd22cca1 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/TaskFile.java @@ -95,7 +95,7 @@ public class TaskFile { for (AnswerPlaceholder placeholder : myAnswerPlaceholders) { if (placeholder.getLine() <= line) { int realStartOffset = placeholder.getRealStartOffset(document); - int placeholderLength = useAnswerLength ? placeholder.getPossibleAnswerLength() : placeholder.getLength(); + int placeholderLength = placeholder.getRealLength(); final int length = placeholderLength > 0 ? placeholderLength : 0; int endOffset = realStartOffset + length; if (realStartOffset <= offset && offset <= endOffset) { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java b/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java index 55a784a534cb..d345ddf22086 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/editor/StudyEditorFactoryListener.java @@ -16,12 +16,12 @@ import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.problems.WolfTheProblemSolver; import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduDocumentListener; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.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; @@ -48,7 +48,7 @@ public class StudyEditorFactoryListener implements EditorFactoryListener { return; } int startOffset = answerPlaceholder.getRealStartOffset(editor.getDocument()); - editor.getSelectionModel().setSelection(startOffset, startOffset + answerPlaceholder.getLength()); + editor.getSelectionModel().setSelection(startOffset, startOffset + answerPlaceholder.getRealLength()); answerPlaceholder.setSelected(true); } } @@ -84,12 +84,12 @@ public class StudyEditorFactoryListener implements EditorFactoryListener { return; } + StudyEditor.addDocumentListener(document, new EduDocumentListener(taskFile, true)); + if (!taskFile.getAnswerPlaceholders().isEmpty()) { StudyNavigator.navigateToFirstAnswerPlaceholder(editor, taskFile); boolean isStudyProject = EduNames.STUDY.equals(course.getCourseType()); - StudyEditor.addDocumentListener(document, new EduDocumentListener(taskFile, true, - !isStudyProject)); - StudyUtils.drawAllWindows(editor, taskFile, isStudyProject); + StudyUtils.drawAllWindows(editor, taskFile); if (isStudyProject) { editor.addEditorMouseListener(new WindowSelectionListener(taskFile)); } From a841a21c6475dd6abb3c55e077de4b9438ae849c Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Sun, 10 Apr 2016 16:51:29 +0300 Subject: [PATCH 24/65] turn off smart checker for course creator --- .../com/jetbrains/edu/learning/PyStudyCheckAction.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java index 43f5fc5645f4..fdb110718b34 100644 --- a/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java +++ b/python/educational-python/student-python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java @@ -16,6 +16,7 @@ import com.jetbrains.edu.learning.checker.StudyCheckTask; import com.jetbrains.edu.learning.checker.StudyCheckUtils; import com.jetbrains.edu.learning.checker.StudyTestRunner; import com.jetbrains.edu.learning.checker.StudyTestsOutputParser; +import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.courseFormat.TaskFile; @@ -103,9 +104,11 @@ public class PyStudyCheckAction extends StudyCheckAction { myTaskManger.setStatus(taskFile, StudyStatus.Failed); continue; } - CommandProcessor.getInstance().runUndoTransparentAction(() -> ApplicationManager.getApplication().runWriteAction(() -> { - StudyCheckUtils.runSmartTestProcess(myTaskDir, testRunner, name, taskFile, project); - })); + if (EduNames.STUDY.equals(myTaskManger.getCourse().getCourseMode())) { + CommandProcessor.getInstance().runUndoTransparentAction(() -> ApplicationManager.getApplication().runWriteAction(() -> { + StudyCheckUtils.runSmartTestProcess(myTaskDir, testRunner, name, taskFile, project); + })); + } } StudyCheckUtils.showTestResultPopUp(testsOutput.getMessage(), MessageType.ERROR.getPopupBackground(), project); StudyCheckUtils.navigateToFailedPlaceholder(myStudyState, myTask, myTaskDir, project); From 0cbea727948969ef96a0069f06d638e5ae4e7736 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Mon, 18 Apr 2016 12:24:06 +0300 Subject: [PATCH 25/65] do not use old service --- .../CCRefactoringElementListenerProvider.java | 30 +++++++++++++++---- .../jetbrains/edu/coursecreator/CCUtils.java | 24 +++++++++++++++ .../coursecreator/CCVirtualFileListener.java | 28 +---------------- .../jetbrains/edu/learning/StudyUtils.java | 13 ++++++-- .../PyCCReferenceResolveProvider.java | 4 ++- 5 files changed, 63 insertions(+), 36 deletions(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java index ed9b404e04a5..7dbd894d8980 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java @@ -16,24 +16,30 @@ package com.jetbrains.edu.coursecreator; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.refactoring.listeners.RefactoringElementAdapter; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.refactoring.listeners.RefactoringElementListenerProvider; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.coursecreator.actions.CCRunTestsAction; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.util.Map; public class CCRefactoringElementListenerProvider implements RefactoringElementListenerProvider { + private static final Logger LOG = Logger.getInstance(CCRefactoringElementListenerProvider.class); + @Nullable @Override public RefactoringElementListener getListener(PsiElement element) { @@ -62,8 +68,7 @@ public class CCRefactoringElementListenerProvider implements RefactoringElementL private static void tryToRenameTaskFile(PsiFile file, String oldName) { final PsiDirectory taskDir = file.getContainingDirectory(); - final CCProjectService service = CCProjectService.getInstance(file.getProject()); - Course course = service.getCourse(); + Course course = StudyTaskManager.getInstance(file.getProject()).getCourse(); if (course == null) { return; } @@ -82,16 +87,29 @@ public class CCRefactoringElementListenerProvider implements RefactoringElementL if (task == null) { return; } + Map taskFiles = task.getTaskFiles(); + TaskFile taskFile = task.getTaskFile(oldName); + if (taskFile == null) { + return; + } ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - CCRunTestsAction.clearTestEnvironment(taskDir.getVirtualFile(), taskDir.getProject()); + VirtualFile patternFile = StudyUtils.getPatternFile(taskFile, oldName); + if (patternFile != null) { + try { + patternFile.delete(CCRefactoringElementListenerProvider.class); + } + catch (IOException e) { + LOG.info(e); + } + } } }); - Map taskFiles = task.getTaskFiles(); - TaskFile taskFile = task.getTaskFile(oldName); + taskFiles.remove(oldName); taskFiles.put(file.getName(), taskFile); + CCUtils.createResourceFile(file.getVirtualFile(), course, taskDir.getVirtualFile()); } @Override diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java index 139a15be6845..78ad05d7aaa0 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java @@ -14,6 +14,7 @@ import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.psi.PsiDirectory; @@ -25,6 +26,7 @@ import com.jetbrains.edu.learning.courseFormat.StudyItem; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -190,4 +192,26 @@ public class CCUtils { } return manager.isTestFile(file); } + + public static void createResourceFile(VirtualFile createdFile, Course course, VirtualFile taskVF) { + VirtualFile lessonVF = taskVF.getParent(); + if (lessonVF == null) { + return; + } + + String taskResourcesPath = FileUtil.join(course.getCourseDirectory(), lessonVF.getName(), taskVF.getName()); + File taskResourceFile = new File(taskResourcesPath); + if (!taskResourceFile.exists()) { + if (!taskResourceFile.mkdirs()) { + LOG.info("Failed to create resources for task " + taskResourcesPath); + } + } + try { + File toFile = new File(taskResourceFile, createdFile.getName()); + FileUtil.copy(new File(createdFile.getPath()), toFile); + } + catch (IOException e) { + LOG.info("Failed to copy created task file to resources " + createdFile.getPath()); + } + } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java index 967d885cdf2e..3c3be598ca7f 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -3,7 +3,6 @@ package com.jetbrains.edu.coursecreator; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectUtil; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileAdapter; import com.intellij.openapi.vfs.VirtualFileEvent; @@ -14,9 +13,6 @@ import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.*; import org.jetbrains.annotations.NotNull; -import java.io.File; -import java.io.IOException; - public class CCVirtualFileListener extends VirtualFileAdapter { private static final Logger LOG = Logger.getInstance(CCVirtualFileListener.class); @@ -55,33 +51,11 @@ public class CCVirtualFileListener extends VirtualFileAdapter { return; } - createResourceFile(createdFile, course, taskVF); + CCUtils.createResourceFile(createdFile, course, taskVF); task.addTaskFile(name, 1); } - private static void createResourceFile(VirtualFile createdFile, Course course, VirtualFile taskVF) { - VirtualFile lessonVF = taskVF.getParent(); - if (lessonVF == null) { - return; - } - - String taskResourcesPath = FileUtil.join(course.getCourseDirectory(), lessonVF.getName(), taskVF.getName()); - File taskResourceFile = new File(taskResourcesPath); - if (!taskResourceFile.exists()) { - if (!taskResourceFile.mkdirs()) { - LOG.info("Failed to create resources for task " + taskResourcesPath); - } - } - try { - File toFile = new File(taskResourceFile, createdFile.getName()); - FileUtil.copy(new File(createdFile.getPath()), toFile); - } - catch (IOException e) { - LOG.info("Failed to copy created task file to resources " + createdFile.getPath()); - } - } - @Override public void fileDeleted(@NotNull VirtualFileEvent event) { VirtualFile removedFile = event.getFile(); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index 590bf97c79aa..fcb9943c56c5 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -354,20 +354,29 @@ public class StudyUtils { @Nullable public static Document getPatternDocument(@NotNull final TaskFile taskFile, String name) { + VirtualFile patternFile = getPatternFile(taskFile, name); + if (patternFile == null) { + return null; + } + return FileDocumentManager.getInstance().getDocument(patternFile); + } + + @Nullable + public static VirtualFile getPatternFile(@NotNull TaskFile taskFile, String name) { Task task = taskFile.getTask(); String lessonDir = EduNames.LESSON + String.valueOf(task.getLesson().getIndex()); String taskDir = EduNames.TASK + String.valueOf(task.getIndex()); Course course = task.getLesson().getCourse(); File resourceFile = new File(course.getCourseDirectory()); if (!resourceFile.exists()) { - return null; + return null; } String patternPath = FileUtil.join(resourceFile.getPath(), lessonDir, taskDir, name); VirtualFile patternFile = VfsUtil.findFileByIoFile(new File(patternPath), true); if (patternFile == null) { return null; } - return FileDocumentManager.getInstance().getDocument(patternFile); + return patternFile; } public static boolean isRenameableOrMoveable(@NotNull final Project project, @NotNull final Course course, @NotNull final PsiElement element) { diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCReferenceResolveProvider.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCReferenceResolveProvider.java index 95cf9321df3b..e1bb8ee267d6 100644 --- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCReferenceResolveProvider.java +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCReferenceResolveProvider.java @@ -1,5 +1,6 @@ package com.jetbrains.edu.coursecreator; +import com.intellij.openapi.project.Project; import com.jetbrains.python.edu.PyEduUtils; import com.jetbrains.python.psi.PyQualifiedExpression; import com.jetbrains.python.psi.resolve.PyReferenceResolveProvider; @@ -13,7 +14,8 @@ public class PyCCReferenceResolveProvider implements PyReferenceResolveProvider @NotNull @Override public List resolveName(@NotNull final PyQualifiedExpression element) { - if (CCProjectService.getInstance(element.getProject()).getCourse() == null) { + Project project = element.getProject(); + if (!CCUtils.isCourseCreator(project)) { return Collections.emptyList(); } return PyEduUtils.getResolveResultFromContainingDirectory(element); From 2f01baafbabb2c7a44d1a8c36dfaf0c265d2f6b1 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Mon, 18 Apr 2016 13:42:33 +0300 Subject: [PATCH 26/65] add ability to hide file from student --- .../resources/META-INF/plugin.xml | 6 +- .../actions/CCAddAsTaskFile.java | 42 ++---- .../actions/CCCreateTaskFile.java | 129 ------------------ .../actions/CCHideFromStudent.java | 45 ++++++ .../actions/CCTaskFileActionBase.java | 59 ++++++++ 5 files changed, 114 insertions(+), 167 deletions(-) delete mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java create mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java create mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionBase.java diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index def669884579..ed0795f78ba3 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -47,12 +47,10 @@ - - - - + + diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java index fa5423922e37..c62bd5e1e069 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java @@ -1,46 +1,20 @@ package com.jetbrains.edu.coursecreator.actions; -import com.intellij.ide.projectView.ProjectView; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Task; -public class CCAddAsTaskFile extends AnAction { - @Override - public void actionPerformed(final AnActionEvent e) { - Project project = e.getProject(); - if (project == null) { - return; - } - final VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); - if (file == null) { - return; - } - Task task = StudyUtils.getTask(project, file); - if (task == null) { - return; - } +public class CCAddAsTaskFile extends CCTaskFileActionBase { + + protected void performAction(VirtualFile file, Task task, Course course, Project project) { task.addTaskFile(file.getName(), task.getTaskFiles().size()); - ProjectView.getInstance(project).refresh(); + CCUtils.createResourceFile(file, course, StudyUtils.getTaskDir(file)); } - - @Override - public void update(AnActionEvent e) { - Project project = e.getProject(); - Presentation presentation = e.getPresentation(); - if (project == null) { - presentation.setEnabledAndVisible(false); - return; - } - VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); - if (file == null || file.isDirectory() || StudyUtils.getTaskFile(project, file) != null) { - presentation.setEnabledAndVisible(false); - } + protected boolean isAvailable(Project project, VirtualFile file) { + return StudyUtils.getTaskFile(project, file) == null && !CCUtils.isTestsFile(project, file); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java deleted file mode 100644 index 88e14494ef39..000000000000 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateTaskFile.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.jetbrains.edu.coursecreator.actions; - -import com.intellij.icons.AllIcons; -import com.intellij.ide.IdeView; -import com.intellij.ide.fileTemplates.FileTemplate; -import com.intellij.ide.fileTemplates.FileTemplateUtil; -import com.intellij.ide.projectView.ProjectView; -import com.intellij.ide.util.DirectoryChooserUtil; -import com.intellij.ide.util.EditorHelper; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.LangDataKeys; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiElement; -import com.jetbrains.edu.learning.StudyTaskManager; -import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.Lesson; -import com.jetbrains.edu.learning.courseFormat.Task; -import com.jetbrains.edu.coursecreator.CCLanguageManager; -import com.jetbrains.edu.coursecreator.CCUtils; -import com.jetbrains.edu.coursecreator.ui.CreateTaskFileDialog; -import org.jetbrains.annotations.NotNull; - -import static com.intellij.openapi.ui.DialogWrapper.OK_EXIT_CODE; - -public class CCCreateTaskFile extends DumbAwareAction { - - public CCCreateTaskFile() { - super("Task File", "Create new Task File", AllIcons.FileTypes.Text); - } - - @Override - public void actionPerformed(final AnActionEvent e) { - final IdeView view = e.getData(LangDataKeys.IDE_VIEW); - final Project project = e.getData(CommonDataKeys.PROJECT); - - if (view == null || project == null) { - return; - } - final PsiDirectory taskDir = DirectoryChooserUtil.getOrChooseDirectory(view); - if (taskDir == null) return; - PsiDirectory lessonDir = taskDir.getParent(); - if (lessonDir == null) { - return; - } - final Course course = StudyTaskManager.getInstance(project).getCourse(); - final Lesson lesson = course.getLesson(lessonDir.getName()); - final Task task = lesson.getTask(taskDir.getName()); - - final int index = task.getTaskFiles().size() + 1; - String generatedName = "file" + index; - CreateTaskFileDialog dialog = new CreateTaskFileDialog(project, generatedName, course); - dialog.show(); - if (dialog.getExitCode() != OK_EXIT_CODE) { - return; - } - final String name = dialog.getFileName(); - if (name == null) return; - FileType type = dialog.getFileType(); - if (type == null) { - return; - } - final CCLanguageManager CCLanguageManager = CCUtils.getStudyLanguageManager(course); - if (CCLanguageManager == null) { - return; - } - final String extension = type.getDefaultExtension(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final FileTemplate taskTemplate = CCLanguageManager.getTaskFileTemplateForExtension(project, extension); - final String taskFileName = name + "." + extension; - try { - if (taskTemplate == null) { - VirtualFile file = taskDir.getVirtualFile().createChildData(this, taskFileName); - ProjectView.getInstance(project).select(file, file, false); - FileEditorManager.getInstance(project).openFile(file, true); - } - else { - final PsiElement taskFile = FileTemplateUtil.createFromTemplate(taskTemplate, taskFileName, null, taskDir); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - EditorHelper.openInEditor(taskFile, false); - view.selectElement(taskFile); - } - }); - } - task.addTaskFile(taskFileName, index); - } - catch (Exception ignored) { - } - } - }); - } - - @Override - public void update(@NotNull AnActionEvent event) { - final Presentation presentation = event.getPresentation(); - presentation.setEnabledAndVisible(false); - final Project project = event.getData(CommonDataKeys.PROJECT); - if (project == null) { - return; - } - final IdeView view = event.getData(LangDataKeys.IDE_VIEW); - if (view == null) { - return; - } - - final PsiDirectory[] directories = view.getDirectories(); - if (directories.length == 0) { - return; - } - final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view); - final Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course != null && directory != null && !directory.getName().contains(EduNames.TASK)) { - return; - } - presentation.setEnabledAndVisible(true); - } -} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java new file mode 100644 index 000000000000..07cd46cfdf20 --- /dev/null +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java @@ -0,0 +1,45 @@ +package com.jetbrains.edu.coursecreator.actions; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.Task; +import com.jetbrains.edu.learning.courseFormat.TaskFile; + +import java.io.IOException; +import java.util.Map; + +public class CCHideFromStudent extends CCTaskFileActionBase { + + private static final Logger LOG = Logger.getInstance(CCHideFromStudent.class); + + @Override + protected void performAction(VirtualFile file, Task task, Course course, Project project) { + Map taskFiles = task.getTaskFiles(); + TaskFile taskFile = StudyUtils.getTaskFile(project, file); + if (taskFile == null) { + return; + } + String name = file.getName(); + VirtualFile patternFile = StudyUtils.getPatternFile(taskFile, name); + ApplicationManager.getApplication().runWriteAction(() -> { + if (patternFile != null) { + try { + patternFile.delete(CCHideFromStudent.class); + } + catch (IOException e) { + LOG.info(e); + } + } + }); + taskFiles.remove(name); + } + + @Override + protected boolean isAvailable(Project project, VirtualFile file) { + return StudyUtils.getTaskFile(project, file) != null; + } +} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionBase.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionBase.java new file mode 100644 index 000000000000..4f0632e82ee8 --- /dev/null +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCTaskFileActionBase.java @@ -0,0 +1,59 @@ +package com.jetbrains.edu.coursecreator.actions; + +import com.intellij.ide.projectView.ProjectView; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.Task; + +public abstract class CCTaskFileActionBase extends AnAction { + + @Override + public void actionPerformed(final AnActionEvent e) { + Project project = e.getProject(); + if (project == null) { + return; + } + final VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); + if (file == null) { + return; + } + VirtualFile taskVF = file.getParent(); + if (taskVF == null) { + return; + } + Task task = StudyUtils.getTask(project, taskVF); + if (task == null) { + return; + } + Course course = StudyTaskManager.getInstance(project).getCourse(); + performAction(file, task, course, project); + ProjectView.getInstance(project).refresh(); + } + + protected abstract void performAction(VirtualFile file, Task task, Course course, Project project); + + + @Override + public void update(AnActionEvent e) { + Project project = e.getProject(); + Presentation presentation = e.getPresentation(); + if (project == null || !CCUtils.isCourseCreator(project)) { + presentation.setEnabledAndVisible(false); + return; + } + VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext()); + if (file == null || file.isDirectory() || !isAvailable(project, file)) { + presentation.setEnabledAndVisible(false); + } + } + + protected abstract boolean isAvailable(Project project, VirtualFile file); +} From 70d306893d2846f24761e40e00f01ebaff64d0e9 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Wed, 20 Apr 2016 17:51:31 +0300 Subject: [PATCH 27/65] replace run tests action with run configuration --- .../coursecreator/CCStudyActionListener.java | 31 +-- .../jetbrains/edu/coursecreator/CCUtils.java | 39 ++- .../actions/CCRunTestsAction.java | 222 ------------------ .../resources/META-INF/plugin.xml | 15 +- .../edu/coursecreator/PyCCRunTests.java | 20 -- .../actions/PyCCRunTestsAction.java | 62 ----- .../run/PyCCCommandLineState.java | 89 +++++++ .../run/PyCCRunTestConfiguration.java | 80 +++++++ .../run/PyCCRunTestsConfigurationFactory.java | 19 ++ .../PyCCRunTestsConfigurationProducer.java | 94 ++++++++ .../run/PyCCRunTestsConfigurationType.java | 41 ++++ .../coursecreator/run/PyCCSettingEditor.form | 34 +++ .../coursecreator/run/PyCCSettingsEditor.java | 69 ++++++ 13 files changed, 462 insertions(+), 353 deletions(-) delete mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java delete mode 100644 python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCRunTests.java delete mode 100644 python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/actions/PyCCRunTestsAction.java create mode 100644 python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCCommandLineState.java create mode 100644 python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestConfiguration.java create mode 100644 python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationFactory.java create mode 100644 python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java create mode 100644 python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationType.java create mode 100644 python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingEditor.form create mode 100644 python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingsEditor.java diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java index 921f97697115..945026bd1ff9 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCStudyActionListener.java @@ -2,20 +2,13 @@ package com.jetbrains.edu.coursecreator; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.DocumentUtil; import com.jetbrains.edu.learning.StudyActionListener; import com.jetbrains.edu.learning.StudyUtils; -import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.courseFormat.TaskFile; -import java.util.Map; - public class CCStudyActionListener implements StudyActionListener { @Override public void beforeCheck(AnActionEvent event) { @@ -38,28 +31,6 @@ public class CCStudyActionListener implements StudyActionListener { if (taskDir == null) { return; } - Map files = task.getTaskFiles(); - for (Map.Entry entry : files.entrySet()) { - String name = entry.getKey(); - VirtualFile child = taskDir.findChild(name); - if (child == null) { - continue; - } - Document patternDocument = StudyUtils.getPatternDocument(entry.getValue(), name); - Document document = FileDocumentManager.getInstance().getDocument(virtualFile); - if (document == null || patternDocument == null) { - return; - } - DocumentUtil.writeInRunUndoTransparentAction(() -> { - patternDocument.replaceString(0, patternDocument.getTextLength(), document.getCharsSequence()); - FileDocumentManager.getInstance().saveDocument(patternDocument); - }); - TaskFile target = new TaskFile(); - TaskFile.copy(taskFile, target); - for (AnswerPlaceholder placeholder : target.getAnswerPlaceholders()) { - placeholder.setUseLength(false); - } - EduUtils.createStudentDocument(project, target, child, patternDocument); - } + CCUtils.createResources(project, task, taskDir); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java index 78ad05d7aaa0..f6dd7417a32d 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java @@ -6,6 +6,8 @@ import com.intellij.ide.projectView.actions.MarkRootActionBase; import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.DumbModePermission; import com.intellij.openapi.project.DumbService; @@ -18,20 +20,18 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.psi.PsiDirectory; +import com.intellij.util.DocumentUtil; import com.intellij.util.Function; import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.StudyItem; +import com.jetbrains.edu.learning.courseFormat.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; +import java.util.*; public class CCUtils { private static final Logger LOG = Logger.getInstance(CCUtils.class); @@ -214,4 +214,31 @@ public class CCUtils { LOG.info("Failed to copy created task file to resources " + createdFile.getPath()); } } + + + public static void createResources(Project project, Task task, VirtualFile taskDir) { + Map files = task.getTaskFiles(); + for (Map.Entry entry : files.entrySet()) { + String name = entry.getKey(); + VirtualFile child = taskDir.findChild(name); + if (child == null) { + continue; + } + Document patternDocument = StudyUtils.getPatternDocument(entry.getValue(), name); + Document document = FileDocumentManager.getInstance().getDocument(child); + if (document == null || patternDocument == null) { + return; + } + DocumentUtil.writeInRunUndoTransparentAction(() -> { + patternDocument.replaceString(0, patternDocument.getTextLength(), document.getCharsSequence()); + FileDocumentManager.getInstance().saveDocument(patternDocument); + }); + TaskFile target = new TaskFile(); + TaskFile.copy(entry.getValue(), target); + for (AnswerPlaceholder placeholder : target.getAnswerPlaceholders()) { + placeholder.setUseLength(false); + } + EduUtils.createStudentDocument(project, target, child, patternDocument); + } + } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java deleted file mode 100644 index f6982733db5b..000000000000 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCRunTestsAction.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2000-2014 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.coursecreator.actions; - -import com.intellij.execution.Location; -import com.intellij.execution.actions.ConfigurationContext; -import com.intellij.icons.AllIcons; -import com.intellij.ide.fileTemplates.FileTemplate; -import com.intellij.openapi.actionSystem.AnAction; -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.fileEditor.FileDocumentManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.Lesson; -import com.jetbrains.edu.learning.courseFormat.Task; -import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.coursecreator.CCLanguageManager; -import com.jetbrains.edu.coursecreator.CCProjectService; -import com.jetbrains.edu.coursecreator.CCUtils; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.util.Map; - -public abstract class CCRunTestsAction extends AnAction { - private static final Logger LOG = Logger.getInstance(CCRunTestsAction.class.getName()); - - public CCRunTestsAction() { - getTemplatePresentation().setIcon(AllIcons.Actions.Lightning); - } - - @Override - public void update(@NotNull AnActionEvent e) { - final Presentation presentation = e.getPresentation(); - if (!CCProjectService.setCCActionAvailable(e)) { - presentation.setEnabledAndVisible(false); - return; - } - - presentation.setEnabledAndVisible(false); - - final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext()); - Location location = context.getLocation(); - if (location == null) { - return; - } - PsiElement psiElement = location.getPsiElement(); - PsiFile psiFile = psiElement.getContainingFile(); - Project project = e.getProject(); - if (project == null || psiFile == null) { - return; - } - TaskFile taskFile = CCProjectService.getInstance(project).getTaskFile(psiFile.getVirtualFile()); - if (taskFile == null) { - return; - } - presentation.setEnabledAndVisible(true); - presentation.setText("Run tests from '" + FileUtil.getNameWithoutExtension(psiFile.getName()) + "'"); - } - - public void actionPerformed(@NotNull AnActionEvent e) { - final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext()); - run(context); - } - - private void run(final @NotNull ConfigurationContext context) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final Project project = context.getProject(); - PsiElement location = context.getPsiLocation(); - final Course course = CCProjectService.getInstance(project).getCourse(); - if (course == null || location == null) { - return; - } - PsiFile psiFile = location.getContainingFile(); - final VirtualFile virtualFile = psiFile.getVirtualFile(); - final VirtualFile taskDir = virtualFile.getParent(); - if (taskDir == null) { - return; - } - VirtualFile lessonDir = taskDir.getParent(); - Lesson lesson = course.getLesson(lessonDir.getName()); - if (lesson == null) { - return; - } - final Task task = lesson.getTask(taskDir.getName()); - if (task == null) { - return; - } - clearTestEnvironment(taskDir, project); - CCLanguageManager manager = CCUtils.getStudyLanguageManager(course); - if (manager == null) { - return; - } - for (final Map.Entry entry : task.getTaskFiles().entrySet()) { - final String name = entry.getKey(); - createTaskFileForTest(taskDir, name, entry.getValue(), project); - } - FileTemplate testsTemplate = manager.getTestsTemplate(project); - if (testsTemplate == null) { - return; - } - VirtualFile testFile = taskDir.findChild(testsTemplate.getName() + "." + testsTemplate.getExtension()); - if (testFile == null) { - return; - } - executeTests(project, virtualFile, taskDir, testFile); - } - }); - } - - private static void createTaskFileForTest(@NotNull final VirtualFile taskDir, final String fileName, @NotNull final TaskFile taskFile, - @NotNull final Project project) { - final VirtualFile answerFile = taskDir.findChild(fileName); - if (answerFile == null) { - LOG.debug("could not find answer file " + fileName); - return; - } - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - final FileDocumentManager documentManager = FileDocumentManager.getInstance(); - documentManager.saveAllDocuments(); - } - }); - EduUtils.flushWindows(taskFile, answerFile, false); - createResourceFiles(answerFile, project); - } - - public static void clearTestEnvironment(@NotNull final VirtualFile taskDir, @NotNull final Project project) { - try { - VirtualFile ideaDir = project.getBaseDir().findChild(".idea"); - if (ideaDir == null) { - LOG.debug("idea directory doesn't exist"); - return; - } - VirtualFile courseResourceDir = ideaDir.findChild(EduNames.COURSE); - if (courseResourceDir != null) { - courseResourceDir.delete(project); - } - VirtualFile[] taskDirChildren = taskDir.getChildren(); - for (VirtualFile file : taskDirChildren) { - if (file.getName().contains(EduNames.WINDOWS_POSTFIX)) { - file.delete(project); - } - } - } - catch (IOException e) { - LOG.error(e); - } - } - - protected abstract void executeTests(@NotNull final Project project, - @NotNull final VirtualFile virtualFile, - @NotNull final VirtualFile taskDir, - @NotNull final VirtualFile testFile); - - //some tests could compare task files after user modifications with initial task files - private static void createResourceFiles(@NotNull final VirtualFile file, @NotNull final Project project) { - VirtualFile taskDir = file.getParent(); - int index = EduUtils.getIndex(taskDir.getName(), EduNames.TASK); - VirtualFile lessonDir = taskDir.getParent(); - int lessonIndex = EduUtils.getIndex(lessonDir.getName(), EduNames.LESSON); - Course course = CCProjectService.getInstance(project).getCourse(); - if (course == null) { - return; - } - VirtualFile ideaDir = project.getBaseDir().findChild(".idea"); - assert ideaDir != null; - try { - VirtualFile courseResourceDir = findOrCreateDir(project, ideaDir, EduNames.COURSE); - VirtualFile lessonResourceDir = findOrCreateDir(project, courseResourceDir, lessonDir.getName()); - VirtualFile taskResourceDir = findOrCreateDir(project, lessonResourceDir, taskDir.getName()); - if (EduUtils.indexIsValid(lessonIndex, course.getLessons())) { - Lesson lesson = course.getLessons().get(lessonIndex); - if (EduUtils.indexIsValid(index, lesson.getTaskList())) { - Task task = lesson.getTaskList().get(index); - for (Map.Entry entry : task.getTaskFiles().entrySet()) { - TaskFile taskFile = new TaskFile(); - TaskFile.copy(entry.getValue(), taskFile); - EduUtils.createStudentFileFromAnswer(project, taskResourceDir, taskDir, entry.getKey(), taskFile); - } - } - } - } - catch (IOException e) { - LOG.error(e); - } - } - - private static VirtualFile findOrCreateDir(@NotNull final Project project, @NotNull final VirtualFile dir, String name) - throws IOException { - VirtualFile targetDir = dir.findChild(name); - if (targetDir == null) { - targetDir = dir.createChildDirectory(project, name); - } - return targetDir; - } -} diff --git a/python/educational-python/course-creator-python/resources/META-INF/plugin.xml b/python/educational-python/course-creator-python/resources/META-INF/plugin.xml index e87961c59b40..2399560d07b7 100644 --- a/python/educational-python/course-creator-python/resources/META-INF/plugin.xml +++ b/python/educational-python/course-creator-python/resources/META-INF/plugin.xml @@ -21,27 +21,16 @@ + + - - - - - - - - - - - - - \ No newline at end of file diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCRunTests.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCRunTests.java deleted file mode 100644 index 5af7f8b164e8..000000000000 --- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/PyCCRunTests.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.jetbrains.edu.coursecreator; - -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.project.Project; -import com.jetbrains.edu.coursecreator.actions.PyCCRunTestsAction; -import com.jetbrains.python.edu.PyExecuteFileExtensionPoint; -import org.jetbrains.annotations.NotNull; - -public class PyCCRunTests implements PyExecuteFileExtensionPoint { - - @NotNull - public AnAction getRunAction() { - return new PyCCRunTestsAction(); - } - - @Override - public boolean accept(Project project) { - return CCProjectService.getInstance(project).getCourse() != null; - } -} \ No newline at end of file diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/actions/PyCCRunTestsAction.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/actions/PyCCRunTestsAction.java deleted file mode 100644 index ebda0f8976f1..000000000000 --- a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/actions/PyCCRunTestsAction.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2000-2014 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.coursecreator.actions; - -import com.intellij.execution.Executor; -import com.intellij.execution.ProgramRunnerUtil; -import com.intellij.execution.RunManager; -import com.intellij.execution.RunnerAndConfigurationSettings; -import com.intellij.execution.configurations.ConfigurationFactory; -import com.intellij.execution.executors.DefaultRunExecutor; -import com.intellij.ide.projectView.ProjectView; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileManager; -import com.intellij.util.PathUtil; -import com.jetbrains.python.run.PythonConfigurationType; -import com.jetbrains.python.run.PythonRunConfiguration; -import org.jetbrains.annotations.NotNull; - -public class PyCCRunTestsAction extends CCRunTestsAction { - - @Override - protected void executeTests(@NotNull final Project project, - @NotNull final VirtualFile virtualFile, - @NotNull final VirtualFile taskDir, - @NotNull final VirtualFile testFile) { - final ConfigurationFactory factory = PythonConfigurationType.getInstance().getConfigurationFactories()[0]; - final RunnerAndConfigurationSettings settings = - RunManager.getInstance(project).createRunConfiguration("test", factory); - - final PythonRunConfiguration configuration = (PythonRunConfiguration)settings.getConfiguration(); - configuration.setScriptName(testFile.getPath()); - configuration.setWorkingDirectory(taskDir.getPath()); - String taskFileName = virtualFile.getName(); - VirtualFile userFile = taskDir.findChild(taskFileName); - if (userFile == null) { - return; - } - VirtualFile ideaDir = project.getBaseDir().findChild(".idea"); - if (ideaDir == null) { - return; - } - VirtualFileManager.getInstance().refreshWithoutFileWatcher(true); - ProjectView.getInstance(project).refresh(); - configuration.setScriptParameters(PathUtil.toSystemDependentName(project.getBasePath()) + " " + PathUtil.toSystemDependentName(userFile.getPath())); - Executor executor = DefaultRunExecutor.getRunExecutorInstance(); - ProgramRunnerUtil.executeConfiguration(project, settings, executor); - } -} diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCCommandLineState.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCCommandLineState.java new file mode 100644 index 000000000000..0bde8098b28f --- /dev/null +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCCommandLineState.java @@ -0,0 +1,89 @@ +package com.jetbrains.edu.coursecreator.run; + +import com.intellij.execution.ExecutionException; +import com.intellij.execution.ExecutionResult; +import com.intellij.execution.Executor; +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.execution.configurations.ParamsGroup; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.checker.StudyCheckUtils; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.core.EduUtils; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.Task; +import com.jetbrains.python.run.CommandLinePatcher; +import com.jetbrains.python.run.PythonCommandLineState; +import org.jetbrains.annotations.NotNull; + +public class PyCCCommandLineState extends PythonCommandLineState { + private final PyCCRunTestConfiguration myRunConfiguration; + private final VirtualFile myTaskDir; + private final Task myTask; + + public PyCCCommandLineState(PyCCRunTestConfiguration runConfiguration, + ExecutionEnvironment env) { + super(runConfiguration, env); + myRunConfiguration = runConfiguration; + + VirtualFile testsFile = LocalFileSystem.getInstance().findFileByPath(myRunConfiguration.getPathToTest()); + assert testsFile != null; + myTaskDir = StudyUtils.getTaskDir(testsFile); + assert myTaskDir != null; + myTask = StudyUtils.getTask(myRunConfiguration.getProject(), myTaskDir); + assert myTask != null; + } + + @Override + protected void buildCommandLineParameters(GeneralCommandLine commandLine) { + ParamsGroup group = commandLine.getParametersList().getParamsGroup(GROUP_SCRIPT); + assert group != null; + + Project project = myRunConfiguration.getProject(); + Course course = StudyTaskManager.getInstance(project).getCourse(); + assert course != null; + + group.addParameter(myRunConfiguration.getPathToTest()); + group.addParameter(course.getCourseDirectory()); + + group.addParameter(getFirstTaskFilePath()); + } + + @NotNull + private String getFirstTaskFilePath() { + String firstTaskFileName = StudyUtils.getFirst(myTask.getTaskFiles().keySet()); + return myTaskDir.findChild(EduNames.SRC) != null ? + FileUtil.join(myTaskDir.getPath(), EduNames.SRC, firstTaskFileName) : + FileUtil.join(myTaskDir.getPath(), firstTaskFileName); + } + + @Override + public ExecutionResult execute(Executor executor, CommandLinePatcher... patchers) throws ExecutionException { + CCUtils.createResources(myRunConfiguration.getProject(), myTask, myTaskDir); + ApplicationManager.getApplication().runWriteAction(() -> StudyCheckUtils.flushWindows(myTask, myTaskDir)); + + return super.execute(executor, patchers); + } + + @Override + protected ProcessHandler doCreateProcess(GeneralCommandLine commandLine) throws ExecutionException { + ProcessHandler handler = super.doCreateProcess(commandLine); + handler.addProcessListener(new ProcessAdapter() { + @Override + public void processTerminated(ProcessEvent event) { + ApplicationManager.getApplication().invokeLater(() -> EduUtils.deleteWindowDescriptions(myTask, myTaskDir)); + } + }); + return handler; + } +} diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestConfiguration.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestConfiguration.java new file mode 100644 index 000000000000..aca074e73274 --- /dev/null +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestConfiguration.java @@ -0,0 +1,80 @@ +package com.jetbrains.edu.coursecreator.run; + +import com.intellij.execution.ExecutionException; +import com.intellij.execution.Executor; +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.RunProfileState; +import com.intellij.execution.configurations.RuntimeConfigurationException; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.JDOMExternalizerUtil; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.python.run.AbstractPythonRunConfiguration; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class PyCCRunTestConfiguration extends AbstractPythonRunConfiguration { + + public static final String PATH_ATTR = "studyTest"; + private Project myProject; + private String myPathToTest; + + public PyCCRunTestConfiguration(Project project, ConfigurationFactory factory) { + super(project, factory); + myProject = project; + } + + @Nullable + @Override + public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws ExecutionException { + return new PyCCCommandLineState(this, environment); + } + + @Override + protected SettingsEditor createConfigurationEditor() { + return new PyCCSettingsEditor(myProject); + } + + public String getPathToTest() { + return myPathToTest; + } + + public void setPathToTest(String pathToTest) { + myPathToTest = pathToTest; + } + + @Override + public void readExternal(Element element) throws InvalidDataException { + super.readExternal(element); + myPathToTest = JDOMExternalizerUtil.readField(element, PATH_ATTR); + } + + @Override + public void writeExternal(Element element) throws WriteExternalException { + super.writeExternal(element); + JDOMExternalizerUtil.writeField(element, PATH_ATTR, myPathToTest); + } + + @Override + public void checkConfiguration() throws RuntimeConfigurationException { + super.checkConfiguration(); + String message = "Select valid path to the file with tests"; + VirtualFile testsFile = LocalFileSystem.getInstance().findFileByPath(myPathToTest); + if (testsFile == null) { + throw new RuntimeConfigurationException(message); + } + VirtualFile taskDir = StudyUtils.getTaskDir(testsFile); + if (taskDir == null) { + throw new RuntimeConfigurationException(message); + } + if (StudyUtils.getTask(myProject, taskDir) == null) { + throw new RuntimeConfigurationException(message); + } + } +} diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationFactory.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationFactory.java new file mode 100644 index 000000000000..1d2de895d0a2 --- /dev/null +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationFactory.java @@ -0,0 +1,19 @@ +package com.jetbrains.edu.coursecreator.run; + +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +public class PyCCRunTestsConfigurationFactory extends ConfigurationFactory { + protected PyCCRunTestsConfigurationFactory(@NotNull ConfigurationType type) { + super(type); + } + + @NotNull + @Override + public RunConfiguration createTemplateConfiguration(@NotNull Project project) { + return new PyCCRunTestConfiguration(project, this); + } +} diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java new file mode 100644 index 000000000000..53ca0c996cc2 --- /dev/null +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationProducer.java @@ -0,0 +1,94 @@ +package com.jetbrains.edu.coursecreator.run; + +import com.intellij.execution.Location; +import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.execution.actions.RunConfigurationProducer; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.courseFormat.Task; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PyCCRunTestsConfigurationProducer extends RunConfigurationProducer { + protected PyCCRunTestsConfigurationProducer() { + super(PyCCRunTestsConfigurationType.getInstance()); + } + + @Override + protected boolean setupConfigurationFromContext(PyCCRunTestConfiguration configuration, + ConfigurationContext context, + Ref sourceElement) { + Project project = context.getProject(); + if (!CCUtils.isCourseCreator(project)) { + return false; + } + + String testsPath = getTestPath(context); + if (testsPath == null) { + return false; + } + VirtualFile testsFile = LocalFileSystem.getInstance().findFileByPath(testsPath); + if (testsFile == null) { + return false; + } + + String generatedName = generateName(testsFile, project); + if (generatedName == null) { + return false; + } + + configuration.setPathToTest(testsPath); + configuration.setName(generatedName); + return true; + } + + @Nullable + private static String generateName(@NotNull VirtualFile testsFile, @NotNull Project project) { + VirtualFile taskDir = StudyUtils.getTaskDir(testsFile); + if (taskDir == null) { + return null; + } + Task task = StudyUtils.getTask(project, taskDir); + if (task == null) { + return null; + } + return task.getLesson().getName() + "/" + task.getName(); + } + + @Nullable + private static String getTestPath(@NotNull ConfigurationContext context) { + Location location = context.getLocation(); + if (location == null) { + return null; + } + VirtualFile file = location.getVirtualFile(); + if (file == null) { + return null; + } + VirtualFile taskDir = StudyUtils.getTaskDir(file); + if (taskDir == null) { + return null; + } + + String testsPath = taskDir.findChild(EduNames.SRC) != null ? + FileUtil.join(taskDir.getPath(), EduNames.SRC, EduNames.TESTS_FILE) : + FileUtil.join(taskDir.getPath(), EduNames.TESTS_FILE); + return file.getPath().equals(testsPath) ? testsPath : null; + } + + @Override + public boolean isConfigurationFromContext(PyCCRunTestConfiguration configuration, ConfigurationContext context) { + String path = getTestPath(context); + if (path == null) { + return false; + } + return path.equals(configuration.getPathToTest()); + } +} diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationType.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationType.java new file mode 100644 index 000000000000..ac05cf1d8ca4 --- /dev/null +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCRunTestsConfigurationType.java @@ -0,0 +1,41 @@ +package com.jetbrains.edu.coursecreator.run; + +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.execution.configurations.ConfigurationTypeUtil; +import com.intellij.icons.AllIcons; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +public class PyCCRunTestsConfigurationType implements ConfigurationType { + @Override + public String getDisplayName() { + return "Run Study Tests"; + } + + @Override + public String getConfigurationTypeDescription() { + return "Study Test Runner"; + } + + @Override + public Icon getIcon() { + return AllIcons.Actions.Lightning; + } + + @NotNull + @Override + public String getId() { + return "ccruntests"; + } + + @Override + public ConfigurationFactory[] getConfigurationFactories() { + return new ConfigurationFactory[]{new PyCCRunTestsConfigurationFactory(this)}; + } + + public static PyCCRunTestsConfigurationType getInstance() { + return ConfigurationTypeUtil.findConfigurationType(PyCCRunTestsConfigurationType.class); + } +} diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingEditor.form b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingEditor.form new file mode 100644 index 000000000000..c84b034ed12f --- /dev/null +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingEditor.form @@ -0,0 +1,34 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingsEditor.java b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingsEditor.java new file mode 100644 index 000000000000..806f6a02ad5e --- /dev/null +++ b/python/educational-python/course-creator-python/src/com/jetbrains/edu/coursecreator/run/PyCCSettingsEditor.java @@ -0,0 +1,69 @@ +package com.jetbrains.edu.coursecreator.run; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.jetbrains.python.run.AbstractPyCommonOptionsForm; +import com.jetbrains.python.run.AbstractPythonRunConfiguration; +import com.jetbrains.python.run.PyCommonOptionsFormData; +import com.jetbrains.python.run.PyCommonOptionsFormFactory; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +public class PyCCSettingsEditor extends SettingsEditor { + private AbstractPyCommonOptionsForm myForm; + private Project myProject; + private JTextField myPathToTestFileField; + private JPanel myPanel; + + public PyCCSettingsEditor(Project project) { + myProject = project; + } + + @Override + protected void resetEditorFrom(PyCCRunTestConfiguration s) { + AbstractPythonRunConfiguration.copyParams(s, myForm); + myPathToTestFileField.setText(s.getPathToTest()); + } + + @Override + protected void applyEditorTo(PyCCRunTestConfiguration s) throws ConfigurationException { + AbstractPythonRunConfiguration.copyParams(myForm, s); + s.setPathToTest(myPathToTestFileField.getText()); + } + + @NotNull + @Override + protected JComponent createEditor() { + final JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(myPanel, BorderLayout.NORTH); + myForm = createEnvPanel(); + mainPanel.add(myForm.getMainPanel(), BorderLayout.SOUTH); + return mainPanel; + } + + + @NotNull + private AbstractPyCommonOptionsForm createEnvPanel() { + return PyCommonOptionsFormFactory.getInstance().createForm(new PyCommonOptionsFormData() { + @Override + public Project getProject() { + return myProject; + } + + @Override + public List getValidModules() { + return AbstractPythonRunConfiguration.getValidModules(myProject); + } + + @Override + public boolean showConfigureInterpretersLink() { + return false; + } + }); + } +} From 66ddc0382ba140e1defe94d03f213bbf39c6ab28 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Thu, 21 Apr 2016 14:26:26 +0300 Subject: [PATCH 28/65] return CCProjectService for migration from old versions --- .../resources/META-INF/plugin.xml | 1 + .../edu/coursecreator/CCProjectService.java | 120 +----------------- 2 files changed, 3 insertions(+), 118 deletions(-) diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index ed0795f78ba3..421b23fef48e 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -16,6 +16,7 @@ com.jetbrains.edu.interactivelearning + diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java index ba9886692671..2ff6f8051033 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectService.java @@ -15,140 +15,24 @@ */ package com.jetbrains.edu.coursecreator; -import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.JBColor; import com.intellij.util.xmlb.XmlSerializerUtil; -import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; -import com.jetbrains.edu.learning.core.EduDocumentListener; -import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.learning.courseFormat.*; +import com.jetbrains.edu.learning.courseFormat.Course; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; @State(name = "CCProjectService", storages = @Storage("course_service.xml")) public class CCProjectService implements PersistentStateComponent { private Course myCourse; - private static final Map myDocumentListeners = new HashMap(); - - @Nullable - public TaskFile getTaskFile(@NotNull final VirtualFile virtualFile) { - VirtualFile taskDir = virtualFile.getParent(); - if (taskDir == null) { - return null; - } - String taskDirName = taskDir.getName(); - if (!taskDirName.contains(EduNames.TASK)) { - return null; - } - VirtualFile lessonDir = taskDir.getParent(); - if (lessonDir == null) { - return null; - } - String lessonDirName = lessonDir.getName(); - if (!lessonDirName.contains(EduNames.LESSON)) { - return null; - } - Lesson lesson = myCourse.getLesson(lessonDirName); - if (lesson == null) { - return null; - } - Task task = lesson.getTask(taskDir.getName()); - if (task == null) { - return null; - } - return task.getTaskFile(virtualFile.getName()); - } - - public void drawAnswerPlaceholders(@NotNull final VirtualFile virtualFile, @NotNull final Editor editor) { - TaskFile taskFile = getTaskFile(virtualFile); - if (taskFile == null) { - return; - } - List answerPlaceholders = taskFile.getAnswerPlaceholders(); - for (AnswerPlaceholder answerPlaceholder : answerPlaceholders) { - EduAnswerPlaceholderPainter.drawAnswerPlaceholder(editor, answerPlaceholder, false, JBColor.BLUE); - } - } - - public static void addDocumentListener(Document document, EduDocumentListener listener) { - myDocumentListeners.put(document, listener); - } - - public static EduDocumentListener getListener(Document document) { - return myDocumentListeners.get(document); - } - - public static void removeListener(Document document) { - myDocumentListeners.remove(document); - } - - @Nullable - public Task getTask(VirtualFile file) { - if (myCourse == null || file == null) { - return null; - } - VirtualFile taskDir = file.getParent(); - if (taskDir != null) { - String taskDirName = taskDir.getName(); - if (taskDirName.contains(EduNames.TASK)) { - VirtualFile lessonDir = taskDir.getParent(); - if (lessonDir != null) { - String lessonDirName = lessonDir.getName(); - int lessonIndex = EduUtils.getIndex(lessonDirName, EduNames.LESSON); - List lessons = myCourse.getLessons(); - if (!EduUtils.indexIsValid(lessonIndex, lessons)) { - return null; - } - Lesson lesson = lessons.get(lessonIndex); - int taskIndex = EduUtils.getIndex(taskDirName, EduNames.TASK); - List tasks = lesson.getTaskList(); - if (!EduUtils.indexIsValid(taskIndex, tasks)) { - return null; - } - return tasks.get(taskIndex); - } - } - } - return null; - } - - public boolean isTaskFile(VirtualFile file) { - Task task = getTask(file); - return task != null && task.isTaskFile(file.getName()); - } - - public static boolean setCCActionAvailable(@NotNull AnActionEvent e) { - final Project project = e.getProject(); - if (project == null) { - return false; - } - if (getInstance(project).getCourse() == null) { - EduUtils.enableAction(e, false); - return false; - } - EduUtils.enableAction(e, true); - return true; - } - public Course getCourse() { return myCourse; } - public void setCourse(@NotNull final Course course) { + public void setCourse(Course course) { myCourse = course; } From 20ddc22d04dfeaca0a238288d4d1cc7f18a1d281 Mon Sep 17 00:00:00 2001 From: "liana.bakradze" Date: Thu, 21 Apr 2016 14:31:02 +0300 Subject: [PATCH 29/65] move course to another service for old projects --- .../edu/coursecreator/CCProjectComponent.java | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java index 2b91b9509dc2..b5a23ba917ed 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java @@ -1,17 +1,40 @@ package com.jetbrains.edu.coursecreator; -import com.intellij.openapi.components.ProjectComponent; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFileManager; +import com.jetbrains.edu.learning.StudyProjectComponent; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.courseFormat.Course; import org.jetbrains.annotations.NotNull; -public class CCProjectComponent implements ProjectComponent { - private final CCVirtualFileListener myTaskFileLifeListener = new CCVirtualFileListener(); +import java.io.File; + +public class CCProjectComponent extends AbstractProjectComponent { + private final CCVirtualFileListener myTaskFileLifeListener = new CCVirtualFileListener(); + private final Project myProject; + + protected CCProjectComponent(Project project) { + super(project); + myProject = project; + } public void initComponent() { VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); } - public void disposeComponent() { + public void migrateIfNeeded() { + Course studyCourse = StudyTaskManager.getInstance(myProject).getCourse(); + Course course = CCProjectService.getInstance(myProject).getCourse(); + if (studyCourse == null && course != null) { + course.setCourseMode(CCUtils.COURSE_MODE); + File coursesDir = new File(PathManager.getConfigPath(), "courses"); + File courseDir = new File(coursesDir, course.getName() + "-" + myProject.getName()); + course.setCourseDirectory(courseDir.getPath()); + StudyTaskManager.getInstance(myProject).setCourse(course); + StudyProjectComponent.getInstance(myProject).registerStudyToolWindow(course); + } } @NotNull @@ -20,6 +43,7 @@ public class CCProjectComponent implements ProjectComponent { } public void projectOpened() { + migrateIfNeeded(); VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); } From 26da3c75093d0b6a8d717b9b6027450606f9a055 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Fri, 22 Apr 2016 16:21:39 +0300 Subject: [PATCH 30/65] always use watch icon when watches in variables enabled --- .../debugger/ui/impl/DebuggerTreeRenderer.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java index f307ac919ddb..74d0410d7fa0 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/DebuggerTreeRenderer.java @@ -27,7 +27,11 @@ import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; import com.intellij.util.PlatformIcons; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XDebuggerManager; +import com.intellij.xdebugger.impl.XDebugSessionImpl; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; +import com.intellij.xdebugger.impl.ui.XDebugSessionTab; import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; import com.intellij.xdebugger.impl.ui.tree.ValueMarkup; import org.jetbrains.annotations.NotNull; @@ -128,6 +132,18 @@ public class DebuggerTreeRenderer extends ColoredTreeCellRenderer { nodeIcon = AllIcons.Debugger.Value; } } + + // if watches in variables enabled, always use watch icon + if (valueDescriptor instanceof WatchItemDescriptor && nodeIcon != AllIcons.Debugger.Watch) { + XDebugSession session = XDebuggerManager.getInstance(valueDescriptor.getProject()).getCurrentSession(); + if (session != null) { + XDebugSessionTab tab = ((XDebugSessionImpl)session).getSessionTab(); + if (tab != null && tab.isWatchesInVariables()) { + nodeIcon = AllIcons.Debugger.Watch; + } + } + } + final Icon valueIcon = valueDescriptor.getValueIcon(); if (nodeIcon != null && valueIcon != null) { nodeIcon = new RowIcon(nodeIcon, valueIcon); From a4f00f54194860a1a896961fd874757d583b8863 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Fri, 22 Apr 2016 16:51:41 +0300 Subject: [PATCH 31/65] jetbrains.dic: +comparison --- spellchecker/src/com/intellij/spellchecker/jetbrains.dic | 1 + 1 file changed, 1 insertion(+) diff --git a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index ae4e810d6df2..acdc832f0da1 100644 --- a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -92,6 +92,7 @@ codesign commandline committer commonjs +comparision concat cond conf From fa3aa57d95221d85ab75f8d52c90176d73e97b0c Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 22 Apr 2016 17:04:57 +0300 Subject: [PATCH 32/65] EA-81297 - NPE: ColorAndFontOptions.getPanels --- .../com/intellij/application/options/colors/FontOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java b/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java index 7ac5e87668fb..6a14e51b5b72 100644 --- a/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java +++ b/platform/lang-impl/src/com/intellij/application/options/colors/FontOptions.java @@ -211,7 +211,7 @@ public class FontOptions extends JPanel implements OptionsPanel{ Object source = event.getSource(); if (source instanceof FontComboBox) { FontComboBox combo = (FontComboBox)source; - if (combo.isEnabled() && combo.getSelectedItem() != null) { + if (combo.isEnabled() && combo.isShowing() && combo.getSelectedItem() != null) { syncFontFamilies(); } } From 2659e52d6aa73677049373c39c67e6b9642233b7 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Fri, 22 Apr 2016 17:49:59 +0300 Subject: [PATCH 33/65] smTest: better naming --- ...eralIdBasedToSMTRunnerEventsConvertor.java | 3 +- .../GeneralToSMTRunnerEventsConvertor.java | 2 +- .../sm/runner/events/TestFailedEvent.java | 28 +++++++++++++------ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java index 8cbb3fc8bcea..a84cefa94b4c 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java @@ -270,7 +270,8 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP String stackTrace = testFailedEvent.getStacktrace(); if (comparisonFailureActualText != null && comparisonFailureExpectedText != null) { testProxy.setTestComparisonFailed(failureMessage, stackTrace, - comparisonFailureActualText, comparisonFailureExpectedText, testFailedEvent.getFilePath()); + comparisonFailureActualText, comparisonFailureExpectedText, + testFailedEvent.getExpectedFilePath()); } else if (comparisonFailureActualText == null && comparisonFailureExpectedText == null) { testProxy.setTestFailed(failureMessage, stackTrace, testFailedEvent.isTestError()); } else { diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java index b8a37e359518..f663eac29541 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java @@ -409,7 +409,7 @@ public class GeneralToSMTRunnerEventsConvertor extends GeneralTestEventsProcesso if (comparisionFailureActualText != null && comparisionFailureExpectedText != null) { testProxy.setTestComparisonFailed(localizedMessage, stackTrace, comparisionFailureActualText, comparisionFailureExpectedText, - testFailedEvent.getFilePath(), testFailedEvent.getActualFilePath()); + testFailedEvent.getExpectedFilePath(), testFailedEvent.getActualFilePath()); } else if (comparisionFailureActualText == null && comparisionFailureExpectedText == null) { testProxy.setTestFailed(localizedMessage, stackTrace, isTestError); diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFailedEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFailedEvent.java index 9065828abdc7..a24f824c129c 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFailedEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFailedEvent.java @@ -27,17 +27,20 @@ public class TestFailedEvent extends TreeNodeEvent { private final boolean myTestError; private final String myComparisonFailureActualText; private final String myComparisonFailureExpectedText; - private final String myFilePath; + private final String myExpectedFilePath; private final String myActualFilePath; private final long myDurationMillis; public TestFailedEvent(@NotNull TestFailed testFailed, boolean testError) { this(testFailed, testError, null); } - public TestFailedEvent(@NotNull TestFailed testFailed, boolean testError, String filePath) { - this(testFailed, testError, filePath, null); + public TestFailedEvent(@NotNull TestFailed testFailed, boolean testError, @Nullable String expectedFilePath) { + this(testFailed, testError, expectedFilePath, null); } - public TestFailedEvent(@NotNull TestFailed testFailed, boolean testError, String filePath, String actualFilePath) { + public TestFailedEvent(@NotNull TestFailed testFailed, + boolean testError, + @Nullable String expectedFilePath, + @Nullable String actualFilePath) { super(testFailed.getTestName(), TreeNodeEvent.getNodeId(testFailed)); if (testFailed.getFailureMessage() == null) throw new NullPointerException(); myLocalizedFailureMessage = testFailed.getFailureMessage(); @@ -45,7 +48,7 @@ public class TestFailedEvent extends TreeNodeEvent { myTestError = testError; myComparisonFailureActualText = testFailed.getActual(); myComparisonFailureExpectedText = testFailed.getExpected(); - myFilePath = filePath; + myExpectedFilePath = expectedFilePath; myActualFilePath = actualFilePath; myDurationMillis = parseDuration(testFailed.getAttributes().get("duration")); } @@ -85,7 +88,7 @@ public class TestFailedEvent extends TreeNodeEvent { boolean testError, @Nullable String comparisonFailureActualText, @Nullable String comparisonFailureExpectedText, - @Nullable String expectedTextFilePath, + @Nullable String expectedFilePath, long durationMillis) { super(testName, id); myLocalizedFailureMessage = localizedFailureMessage; @@ -93,7 +96,7 @@ public class TestFailedEvent extends TreeNodeEvent { myTestError = testError; myComparisonFailureActualText = comparisonFailureActualText; myComparisonFailureExpectedText = comparisonFailureExpectedText; - myFilePath = expectedTextFilePath; + myExpectedFilePath = expectedFilePath; myActualFilePath = null; myDurationMillis = durationMillis; } @@ -131,10 +134,19 @@ public class TestFailedEvent extends TreeNodeEvent { append(buf, "comparisonFailureExpectedText", myComparisonFailureExpectedText); } + /** + * @deprecated use {@link #getExpectedFilePath()} instead + */ public String getFilePath() { - return myFilePath; + return myExpectedFilePath; } + @Nullable + public String getExpectedFilePath() { + return myExpectedFilePath; + } + + @Nullable public String getActualFilePath() { return myActualFilePath; } From 9e7c4e5568e63ffe375951ea96039fb5cf0d7329 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 14:44:10 +0200 Subject: [PATCH 34/65] combine inline parameter with change signature refactoring EA-80956 - E: BaseRefactoringProcessor.run --- .../InlineParameterExpressionProcessor.java | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineParameterExpressionProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineParameterExpressionProcessor.java index 5ae0546f216f..f5eb4cc76bb7 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineParameterExpressionProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineParameterExpressionProcessor.java @@ -16,8 +16,8 @@ package com.intellij.refactoring.inline; import com.intellij.codeInsight.ExceptionUtil; -import com.intellij.codeInspection.sameParameterValue.SameParameterValueInspection; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; @@ -26,12 +26,18 @@ import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.BaseRefactoringProcessor; +import com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase; +import com.intellij.refactoring.changeSignature.JavaChangeInfo; +import com.intellij.refactoring.changeSignature.JavaChangeInfoImpl; +import com.intellij.refactoring.changeSignature.ParameterInfoImpl; +import com.intellij.refactoring.util.CanonicalTypes; import com.intellij.refactoring.util.InlineUtil; import com.intellij.refactoring.util.RefactoringUIUtil; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewDescriptor; import com.intellij.usageView.UsageViewUtil; +import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -53,6 +59,9 @@ public class InlineParameterExpressionProcessor extends BaseRefactoringProcessor private final PsiCodeBlock myCallingBlock; private final boolean myCreateLocal; + private JavaChangeInfo myChangeInfo; + private UsageInfo[] myChangeSignatureUsages; + public InlineParameterExpressionProcessor(final PsiCallExpression methodCall, final PsiMethod method, final PsiParameter parameter, @@ -147,6 +156,28 @@ public class InlineParameterExpressionProcessor extends BaseRefactoringProcessor } } + + final PsiParameter[] parameters = myMethod.getParameterList().getParameters(); + final List psiParameters = new ArrayList(); + int paramIdx = 0; + final String paramName = myParameter.getName(); + for (PsiParameter param : parameters) { + if (!Comparing.strEqual(paramName, param.getName())) { + psiParameters.add(new ParameterInfoImpl(paramIdx, param.getName(), param.getType())); + } + paramIdx++; + } + + PsiType returnType = myMethod.getReturnType(); + myChangeInfo = new JavaChangeInfoImpl(VisibilityUtil.getVisibilityModifier(myMethod.getModifierList()), myMethod, myMethod.getName(), + returnType != null ? CanonicalTypes.createTypeWrapper(returnType) : null, + psiParameters.toArray(new ParameterInfoImpl[psiParameters.size()]), + null, + false, + Collections.emptySet(), + Collections.emptySet() ); + myChangeSignatureUsages = ChangeSignatureProcessorBase.findUsages(myChangeInfo); + final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]); return UsageViewUtil.removeDuplicatedUsages(usageInfos); } @@ -267,7 +298,7 @@ public class InlineParameterExpressionProcessor extends BaseRefactoringProcessor } } - SameParameterValueInspection.InlineParameterValueFix.removeParameter(myMethod, myParameter); + ChangeSignatureProcessorBase.doChangeSignature(myChangeInfo, myChangeSignatureUsages); if (!thrownExceptions.isEmpty()) { for (PsiClassType exception : thrownExceptions) { From 856640c9f0518ea1842eb0e3ed43dcb1bf123081 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 14:50:31 +0200 Subject: [PATCH 35/65] collect smartpointers to survive reformat on writeAction ended EA-80355 - PIEAE: CompositePsiElement.getContainingFile --- .../CreateConstructorParameterFromFieldFix.java | 14 ++++++++------ .../ex/GlobalInspectionContextBase.java | 8 +++++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java index 5ef6d1737af4..97bb45cb531c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateConstructorParameterFromFieldFix.java @@ -125,7 +125,7 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction { } } }); - final List cleanupElements = new ArrayList(); + final List> cleanupElements = new ArrayList<>(); final List filtered = filterConstructorsIfFieldAlreadyAssigned(constructors, getField()); if (filtered.size() > 1) { final PsiMethodMember[] members = new PsiMethodMember[filtered.size()]; @@ -188,7 +188,7 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction { fieldsToFix.clear(); } } - GlobalInspectionContextBase.cleanupElements(project, null, cleanupElements.toArray(new PsiElement[cleanupElements.size()])); + GlobalInspectionContextBase.cleanupElements(project, null, cleanupElements); } @NotNull @@ -237,7 +237,8 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction { final PsiFile file, final Editor editor, final PsiMethod constructor, - final PsiField[] fields, final List cleanupElements) throws IncorrectOperationException { + final PsiField[] fields, + final List> cleanupElements) throws IncorrectOperationException { final PsiParameterList parameterList = constructor.getParameterList(); final PsiParameter[] parameters = parameterList.getParameters(); ParameterInfoImpl[] newParamInfos = new ParameterInfoImpl[parameters.length + fields.length]; @@ -328,13 +329,14 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction { } private static boolean doCreate(Project project, Editor editor, PsiParameter[] parameters, SmartPsiElementPointer constructorPointer, - ParameterInfoImpl[] parameterInfos, Map fields, List cleanupElements) { + ParameterInfoImpl[] parameterInfos, Map fields, List> cleanupElements) { PsiMethod constructor = (PsiMethod)constructorPointer.getElement(); assert constructor != null; PsiParameter[] newParameters = constructor.getParameterList().getParameters(); if (newParameters == parameters) return false; //user must have canceled dialog // do not introduce assignment in chained constructor if (JavaHighlightUtil.getChainedConstructors(constructor) == null) { + final SmartPointerManager manager = SmartPointerManager.getInstance(project); boolean created = false; for (PsiField field : fields.keySet()) { final String defaultParamName = fields.get(field); @@ -343,10 +345,10 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction { continue; } NullableNotNullManager.getInstance(field.getProject()).copyNotNullAnnotation(field, parameter); - cleanupElements.add(parameter); + cleanupElements.add(manager.createSmartPsiElementPointer(parameter)); final PsiElement assignmentStatement = AssignFieldFromParameterAction.addFieldAssignmentStatement(project, field, parameter, editor); if (assignmentStatement != null) { - cleanupElements.add(assignmentStatement); + cleanupElements.add(manager.createSmartPsiElementPointer(assignmentStatement)); } created = true; } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java index d506f8d1c1db..496aa8f55ac2 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextBase.java @@ -412,6 +412,12 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G elements.add(manager.createSmartPsiElementPointer(element)); } + cleanupElements(project, runnable, elements); + } + + public static void cleanupElements(@NotNull final Project project, + @Nullable final Runnable runnable, + final List> elements) { Runnable cleanupRunnable = new Runnable() { @Override public void run() { @@ -441,7 +447,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G } } - public void close(boolean noSuspisiousCodeFound) { + public void close(boolean noSuspisiousCodeFound) { cleanup(); } From f7f379e5e61f6da27ab30fa9351bbfef49c5cae1 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 15:05:48 +0200 Subject: [PATCH 36/65] EA-80364 - PIEAE: StubBasedPsiElementBase.getContainingFile --- .../impl/search/SPIReferencesSearcher.java | 63 +++++-------------- 1 file changed, 17 insertions(+), 46 deletions(-) diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/SPIReferencesSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/SPIReferencesSearcher.java index 94ba3199fa09..959e9814c8d1 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/SPIReferencesSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/SPIReferencesSearcher.java @@ -16,10 +16,8 @@ package com.intellij.psi.impl.search; import com.intellij.lang.spi.SPILanguage; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.QueryExecutorBase; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.search.FilenameIndex; import com.intellij.psi.search.GlobalSearchScope; @@ -30,73 +28,46 @@ import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; public class SPIReferencesSearcher extends QueryExecutorBase { + public SPIReferencesSearcher() { + super(true); + } + @Override public void processQuery(@NotNull final ReferencesSearch.SearchParameters p, @NotNull final Processor consumer) { - final SearchScope scope = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public SearchScope compute() { - return p.getEffectiveSearchScope(); - } - }); - if (!(scope instanceof GlobalSearchScope)) return; - final PsiElement element = p.getElementToSearch(); + if (!element.isValid()) return; + + final SearchScope scope = p.getEffectiveSearchScope(); + if (!(scope instanceof GlobalSearchScope)) return; + if (element instanceof PsiClass) { final PsiClass aClass = (PsiClass)element; - final String jvmClassName = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return ClassUtil.getJVMClassName(aClass); - } - }); + final String jvmClassName = ClassUtil.getJVMClassName(aClass); if (jvmClassName == null) return; - final PsiFile[] files = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiFile[] compute() { - return FilenameIndex.getFilesByName(aClass.getProject(), jvmClassName, (GlobalSearchScope)scope); - } - }); + final PsiFile[] files = FilenameIndex.getFilesByName(aClass.getProject(), jvmClassName, (GlobalSearchScope)scope); for (PsiFile file : files) { if (file.getLanguage() == SPILanguage.INSTANCE) { final PsiReference reference = file.getReference(); if (reference != null) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - consumer.process(reference); - } - }); + consumer.process(reference); } } } - } else if (element instanceof PsiPackage) { + } + else if (element instanceof PsiPackage) { final String qualifiedName = ((PsiPackage)element).getQualifiedName(); final Project project = element.getProject(); - final String[] filenames = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String[] compute() { - return FilenameIndex.getAllFilenames(project); - } - }); + final String[] filenames = FilenameIndex.getAllFilenames(project); for (final String filename : filenames) { if (filename.startsWith(qualifiedName + ".")) { - final PsiFile[] files = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiFile[] compute() { - return FilenameIndex.getFilesByName(project, filename, (GlobalSearchScope)scope); - } - }); + final PsiFile[] files = FilenameIndex.getFilesByName(project, filename, (GlobalSearchScope)scope); for (PsiFile file : files) { if (file.getLanguage() == SPILanguage.INSTANCE) { final PsiReference[] references = file.getReferences(); for (final PsiReference reference : references) { if (reference.getCanonicalText().equals(qualifiedName)) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - public void run() { - consumer.process(reference); - } - }); + consumer.process(reference); } } } From 1a2b94105eab621ce62393452b9e6ebaa13bef81 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 15:57:58 +0200 Subject: [PATCH 37/65] EA-78630 - CCE: TrivialFunctionalExpressionUsageInspection$ReplaceWithLambdaBodyFix.replaceWithLambdaBody --- .../beforeCodeBlockWithReturnInSwitch.java | 13 + ...alFunctionalExpressionUsageInspection.java | 313 ++++++++++-------- 2 files changed, 182 insertions(+), 144 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeCodeBlockWithReturnInSwitch.java diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeCodeBlockWithReturnInSwitch.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeCodeBlockWithReturnInSwitch.java new file mode 100644 index 000000000000..02526bad681f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/trivialFunctionalExpressionUsage/beforeCodeBlockWithReturnInSwitch.java @@ -0,0 +1,13 @@ +// "Replace method call on lambda with lambda body" "false" +import java.util.function.Supplier; + +class Test { + { + System.out.println(((Supplier)() -> { + switch () { + default: + return ""; + } + }).get()); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/intellij/codeInspection/TrivialFunctionalExpressionUsageInspection.java b/plugins/InspectionGadgets/src/com/intellij/codeInspection/TrivialFunctionalExpressionUsageInspection.java index 2e3814f14768..74d527aab46d 100644 --- a/plugins/InspectionGadgets/src/com/intellij/codeInspection/TrivialFunctionalExpressionUsageInspection.java +++ b/plugins/InspectionGadgets/src/com/intellij/codeInspection/TrivialFunctionalExpressionUsageInspection.java @@ -39,36 +39,35 @@ public class TrivialFunctionalExpressionUsageInspection extends BaseJavaBatchLoc @Override public void visitMethodReferenceExpression(final PsiMethodReferenceExpression expression) { - doCheckMethodCallOnFunctionalExpression(expression, new Condition() { - @Override - public boolean value(PsiElement element) { - return expression.resolve() != null; - } - }); + doCheckMethodCallOnFunctionalExpression(expression, element -> expression.resolve() != null); } @Override public void visitLambdaExpression(final PsiLambdaExpression expression) { - doCheckMethodCallOnFunctionalExpression(expression, new Condition() { - @Override - public boolean value(PsiElement ggParent) { - final PsiElement body = expression.getBody(); - if (!(body instanceof PsiCodeBlock) || - ((PsiCodeBlock)body).getStatements().length == 1) { - return true; - } - final List returnExpressions = LambdaUtil.getReturnExpressions(expression); - if (returnExpressions.size() > 1) { - return false; - } - final PsiElement callParent = ggParent.getParent(); - if (returnExpressions.isEmpty()) { - return callParent instanceof PsiStatement; - } - return callParent instanceof PsiStatement || - callParent instanceof PsiLocalVariable || - callParent instanceof PsiExpression && PsiTreeUtil.getParentOfType(callParent, PsiStatement.class) != null; + doCheckMethodCallOnFunctionalExpression(expression, ggParent -> { + final PsiElement callParent = ggParent.getParent(); + + final PsiElement body = expression.getBody(); + if (!(body instanceof PsiCodeBlock)) { + return callParent instanceof PsiStatement || callParent instanceof PsiLocalVariable || expression.isValueCompatible(); } + + if (((PsiCodeBlock)body).getStatements().length == 1) { + return callParent instanceof PsiStatement + || callParent instanceof PsiLocalVariable + || ((PsiCodeBlock)body).getStatements()[0] instanceof PsiReturnStatement && expression.isValueCompatible(); + } + + final List returnExpressions = LambdaUtil.getReturnExpressions(expression); + if (returnExpressions.size() > 1) { + return false; + } + + if (returnExpressions.isEmpty()) { + return callParent instanceof PsiStatement; + } + return callParent instanceof PsiStatement || + callParent instanceof PsiLocalVariable; }); } @@ -76,20 +75,17 @@ public class TrivialFunctionalExpressionUsageInspection extends BaseJavaBatchLoc public void visitAnonymousClass(final PsiAnonymousClass aClass) { if (AnonymousCanBeLambdaInspection.canBeConvertedToLambda(aClass, false, Collections.emptySet())) { final PsiElement newExpression = aClass.getParent(); - doCheckMethodCallOnFunctionalExpression(new Condition() { - @Override - public boolean value(PsiElement ggParent) { - final PsiMethod method = aClass.getMethods()[0]; - final PsiCodeBlock body = method.getBody(); - final PsiReturnStatement[] returnStatements = PsiUtil.findReturnStatements(body); - if (returnStatements.length > 1) { - return false; - } - final PsiElement callParent = ggParent.getParent(); - return callParent instanceof PsiStatement || - callParent instanceof PsiLocalVariable; + doCheckMethodCallOnFunctionalExpression(ggParent -> { + final PsiMethod method = aClass.getMethods()[0]; + final PsiCodeBlock body = method.getBody(); + final PsiReturnStatement[] returnStatements = PsiUtil.findReturnStatements(body); + if (returnStatements.length > 1) { + return false; } - }, newExpression, aClass.getBaseClassType(), "Replace call with method body"); + final PsiElement callParent = ggParent.getParent(); + return callParent instanceof PsiStatement || + callParent instanceof PsiLocalVariable; + }, newExpression, aClass.getBaseClassType(), new ReplaceAnonymousWithLambdaBodyFix()); } } @@ -99,16 +95,15 @@ public class TrivialFunctionalExpressionUsageInspection extends BaseJavaBatchLoc if (parent instanceof PsiTypeCastExpression) { final PsiType interfaceType = ((PsiTypeCastExpression)parent).getType(); doCheckMethodCallOnFunctionalExpression(elementContainerCondition, parent, interfaceType, - "Replace method call " + - (expression instanceof PsiLambdaExpression ? "on lambda with lambda body" - : "on method reference with corresponding method call")); + expression instanceof PsiLambdaExpression ? new ReplaceWithLambdaBodyFix() + : new ReplaceWithMethodReferenceFix()); } } private void doCheckMethodCallOnFunctionalExpression(Condition elementContainerCondition, PsiElement parent, PsiType interfaceType, - String quickFixName) { + LocalQuickFix fix) { final PsiElement gParent = PsiUtil.skipParenthesizedExprUp(parent.getParent()); if (gParent instanceof PsiReferenceExpression) { final PsiElement ggParent = gParent.getParent(); @@ -123,8 +118,6 @@ public class TrivialFunctionalExpressionUsageInspection extends BaseJavaBatchLoc final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(interfaceType); if (resolveMethod == interfaceMethod || interfaceMethod != null && MethodSignatureUtil.isSuperMethod(interfaceMethod, resolveMethod)) { - final ReplaceWithLambdaBodyFix fix = - new ReplaceWithLambdaBodyFix(quickFixName); holder.registerProblem(referenceNameElement, "Method call can be simplified", fix); } } @@ -134,25 +127,145 @@ public class TrivialFunctionalExpressionUsageInspection extends BaseJavaBatchLoc }; } - private static class ReplaceWithLambdaBodyFix implements LocalQuickFix { - private String myName; + private static void replaceWithLambdaBody(PsiMethodCallExpression callExpression, PsiLambdaExpression element) { + inlineCallArguments(callExpression, element); - public ReplaceWithLambdaBodyFix(String name) { - myName = name; + final PsiElement body = element.getBody(); + if (body instanceof PsiExpression) { + callExpression.replace(body); } + else if (body instanceof PsiCodeBlock) { + final PsiElement parent = callExpression.getParent(); + if (parent instanceof PsiStatement) { + final PsiElement gParent = parent.getParent(); + restoreComments(gParent, parent, body); + for (PsiStatement statement : ((PsiCodeBlock)body).getStatements()) { + PsiElement toInsert; + if (statement instanceof PsiReturnStatement) { + toInsert = ((PsiReturnStatement)statement).getReturnValue(); + } + else { + toInsert = statement; + } - @Nls - @NotNull - @Override - public String getName() { - return getFamilyName(); + if (toInsert != null) { + gParent.addBefore(toInsert, parent); + } + } + parent.delete(); + } + else { + final PsiStatement[] statements = ((PsiCodeBlock)body).getStatements(); + if (statements.length > 0) { + final PsiStatement anchor = PsiTreeUtil.getParentOfType(parent, PsiStatement.class); + if (anchor != null) { + final PsiElement gParent = anchor.getParent(); + restoreComments(gParent, anchor, body); + for (int i = 0; i < statements.length - 1; i++) { + gParent.addBefore(statements[i], anchor); + } + } + PsiStatement statement = statements[statements.length - 1]; + final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue(); + if (returnValue != null) { + callExpression.replace(returnValue); + } + } + } } + } + + private static void restoreComments(PsiElement gParent, PsiElement parent, PsiElement body) { + for (PsiElement comment : PsiTreeUtil.findChildrenOfType(body, PsiComment.class)) { + gParent.addBefore(comment, parent); + } + } + + private static void inlineCallArguments(PsiMethodCallExpression callExpression, PsiLambdaExpression element) { + final PsiExpression[] args = callExpression.getArgumentList().getExpressions(); + final PsiParameter[] parameters = element.getParameterList().getParameters(); + for (int i = 0; i < parameters.length; i++) { + final PsiParameter parameter = parameters[i]; + final PsiExpression initializer = args[i]; + for (PsiReference reference : ReferencesSearch.search(parameter)) { + final PsiElement referenceElement = reference.getElement(); + if (referenceElement instanceof PsiJavaCodeReferenceElement) { + InlineUtil.inlineVariable(parameter, initializer, (PsiJavaCodeReferenceElement)referenceElement); + } + } + } + } + + private static class ReplaceWithLambdaBodyFix extends ReplaceFix { @Nls @NotNull @Override public String getFamilyName() { - return myName; + return "Replace method call on lambda with lambda body"; + } + + @Override + protected void fixExpression(PsiMethodCallExpression callExpression, PsiExpression qualifierExpression) { + if (qualifierExpression instanceof PsiTypeCastExpression) { + final PsiExpression element = ((PsiTypeCastExpression)qualifierExpression).getOperand(); + if (element instanceof PsiLambdaExpression) { + replaceWithLambdaBody(callExpression, (PsiLambdaExpression)element); + } + } + } + } + + private static class ReplaceWithMethodReferenceFix extends ReplaceFix { + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Replace method call on method reference with corresponding method call"; + } + + @Override + protected void fixExpression(PsiMethodCallExpression callExpression, PsiExpression qualifierExpression) { + if (qualifierExpression instanceof PsiTypeCastExpression) { + final PsiExpression element = ((PsiTypeCastExpression)qualifierExpression).getOperand(); + if (element instanceof PsiMethodReferenceExpression) { + final PsiLambdaExpression lambdaExpression = + LambdaRefactoringUtil.convertMethodReferenceToLambda((PsiMethodReferenceExpression)element, false, true); + if (lambdaExpression != null) { + replaceWithLambdaBody(callExpression, lambdaExpression); + } + } + } + } + } + + private static class ReplaceAnonymousWithLambdaBodyFix extends ReplaceFix { + + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Replace call with method body"; + } + + @Override + protected void fixExpression(PsiMethodCallExpression callExpression, PsiExpression qualifierExpression) { + final PsiExpression cast = AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(qualifierExpression, true, false); + if (cast instanceof PsiTypeCastExpression) { + final PsiExpression lambdaExpression = ((PsiTypeCastExpression)cast).getOperand(); + if (lambdaExpression instanceof PsiLambdaExpression) { + replaceWithLambdaBody(callExpression, (PsiLambdaExpression)lambdaExpression); + } + } + } + } + + private static abstract class ReplaceFix implements LocalQuickFix { + @Nls + @NotNull + @Override + public String getName() { + return getFamilyName(); } @Override @@ -161,98 +274,10 @@ public class TrivialFunctionalExpressionUsageInspection extends BaseJavaBatchLoc if (!FileModificationService.getInstance().preparePsiElementForWrite(psiElement)) return; final PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType(psiElement, PsiMethodCallExpression.class); if (callExpression != null) { - final PsiExpression qualifierExpression = PsiUtil.skipParenthesizedExprDown(callExpression.getMethodExpression().getQualifierExpression()); - if (qualifierExpression instanceof PsiTypeCastExpression) { - final PsiExpression element = ((PsiTypeCastExpression)qualifierExpression).getOperand(); - if (element instanceof PsiLambdaExpression) { - replaceWithLambdaBody(callExpression, (PsiLambdaExpression)element); - } - else if (element instanceof PsiMethodReferenceExpression) { - final PsiLambdaExpression lambdaExpression = - LambdaRefactoringUtil.convertMethodReferenceToLambda((PsiMethodReferenceExpression)element, false, true); - if (lambdaExpression != null) { - replaceWithLambdaBody(callExpression, lambdaExpression); - } - } - } - else if (qualifierExpression instanceof PsiNewExpression) { - final PsiExpression cast = AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(qualifierExpression, true, false); - if (cast instanceof PsiTypeCastExpression) { - final PsiExpression lambdaExpression = ((PsiTypeCastExpression)cast).getOperand(); - if (lambdaExpression instanceof PsiLambdaExpression) { - replaceWithLambdaBody(callExpression, (PsiLambdaExpression)lambdaExpression); - } - } - } + fixExpression(callExpression, PsiUtil.skipParenthesizedExprDown(callExpression.getMethodExpression().getQualifierExpression())); } } - private static void replaceWithLambdaBody(PsiMethodCallExpression callExpression, PsiLambdaExpression element) { - inlineCallArguments(callExpression, element); - - final PsiElement body = element.getBody(); - if (body instanceof PsiExpression) { - callExpression.replace(body); - } - else if (body instanceof PsiCodeBlock) { - final PsiElement parent = callExpression.getParent(); - if (parent instanceof PsiStatement) { - final PsiElement gParent = parent.getParent(); - restoreComments(gParent, parent, body); - for (PsiStatement statement : ((PsiCodeBlock)body).getStatements()) { - PsiElement toInsert; - if (statement instanceof PsiReturnStatement) { - toInsert = ((PsiReturnStatement)statement).getReturnValue(); - } - else { - toInsert = statement; - } - - if (toInsert != null) { - gParent.addBefore(toInsert, parent); - } - } - parent.delete(); - } - else { - final PsiStatement[] statements = ((PsiCodeBlock)body).getStatements(); - if (statements.length > 0) { - final PsiStatement anchor = PsiTreeUtil.getParentOfType(parent, PsiStatement.class); - if (anchor != null) { - final PsiElement gParent = anchor.getParent(); - restoreComments(gParent, anchor, body); - for (int i = 0; i < statements.length - 1; i++) { - gParent.addBefore(statements[i], anchor); - } - } - final PsiExpression returnValue = ((PsiReturnStatement)statements[statements.length - 1]).getReturnValue(); - if (returnValue != null) { - callExpression.replace(returnValue); - } - } - } - } - } - - private static void restoreComments(PsiElement gParent, PsiElement parent, PsiElement body) { - for (PsiElement comment : PsiTreeUtil.findChildrenOfType(body, PsiComment.class)) { - gParent.addBefore(comment, parent); - } - } - - private static void inlineCallArguments(PsiMethodCallExpression callExpression, PsiLambdaExpression element) { - final PsiExpression[] args = callExpression.getArgumentList().getExpressions(); - final PsiParameter[] parameters = element.getParameterList().getParameters(); - for (int i = 0; i < parameters.length; i++) { - final PsiParameter parameter = parameters[i]; - final PsiExpression initializer = args[i]; - for (PsiReference reference : ReferencesSearch.search(parameter)) { - final PsiElement referenceElement = reference.getElement(); - if (referenceElement instanceof PsiJavaCodeReferenceElement) { - InlineUtil.inlineVariable(parameter, initializer, (PsiJavaCodeReferenceElement)referenceElement); - } - } - } - } + protected abstract void fixExpression(PsiMethodCallExpression callExpression, PsiExpression qualifierExpression); } } From b1645e3ae5ea3db8a92dc2af6716d8c3a24bca54 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 16:15:16 +0200 Subject: [PATCH 38/65] reuse utility method; ensure unknown functional type reduced to Object before create new psi EA-75452 - IOE: PsiJavaParserFacadeImpl.createTypeElementFromText --- .../src/com/intellij/refactoring/util/VariableData.java | 7 +++++-- .../daemon/impl/quickfix/CreateFromUsageUtils.java | 5 +---- .../daemon/impl/quickfix/CreateLocalFromUsageFix.java | 3 +++ .../com/intellij/refactoring/util/RefactoringUtil.java | 6 ++---- .../src/com/intellij/psi/impl/TypeCorrector.java | 2 +- .../createLocalFromUsage/afterFromLambdaParameter.java | 8 ++++++++ .../createLocalFromUsage/beforeFromLambdaParameter.java | 8 ++++++++ 7 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterFromLambdaParameter.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeFromLambdaParameter.java diff --git a/java/java-analysis-impl/src/com/intellij/refactoring/util/VariableData.java b/java/java-analysis-impl/src/com/intellij/refactoring/util/VariableData.java index d367ceb0e768..5c7d95416bb1 100644 --- a/java/java-analysis-impl/src/com/intellij/refactoring/util/VariableData.java +++ b/java/java-analysis-impl/src/com/intellij/refactoring/util/VariableData.java @@ -15,7 +15,10 @@ */ package com.intellij.refactoring.util; -import com.intellij.psi.*; +import com.intellij.psi.LambdaUtil; +import com.intellij.psi.PsiType; +import com.intellij.psi.PsiVariable; +import com.intellij.psi.SmartTypePointerManager; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,7 +35,7 @@ public class VariableData extends AbstractVariableData { public VariableData(@Nullable PsiVariable var, PsiType type) { variable = var; if (var != null) { - if (type instanceof PsiLambdaParameterType || type instanceof PsiLambdaExpressionType || type instanceof PsiMethodReferenceType) { + if (LambdaUtil.notInferredType(type)) { type = PsiType.getJavaLangObject(var.getManager(), GlobalSearchScope.allScope(var.getProject())); } this.type = SmartTypePointerManager.getInstance(var.getProject()).createSmartTypePointer(type).getType(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java index 039e9f82f165..fafe647b4137 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java @@ -261,10 +261,7 @@ public class CreateFromUsageUtils { names = new String[]{"p" + i}; } - if (argType == null || PsiType.NULL.equals(argType) || - argType instanceof PsiLambdaExpressionType || - argType instanceof PsiLambdaParameterType || - argType instanceof PsiMethodReferenceType) { + if (argType == null || PsiType.NULL.equals(argType) || LambdaUtil.notInferredType(argType)) { argType = PsiType.getJavaLangObject(psiManager, resolveScope); } else if (argType instanceof PsiDisjunctionType) { argType = ((PsiDisjunctionType)argType).getLeastUpperBound(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java index aca399d6b20e..bae4cd9e8bee 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java @@ -78,6 +78,9 @@ public class CreateLocalFromUsageFix extends CreateVarFromUsageFix { final SmartTypePointer defaultType = SmartTypePointerManager.getInstance(project).createSmartTypePointer(expectedTypes[0]); final PsiType preferredType = TypeSelectorManagerImpl.getPreferredType(expectedTypes, expectedTypes[0]); PsiType type = preferredType != null ? preferredType : expectedTypes[0]; + if (LambdaUtil.notInferredType(type)) { + type = PsiType.getJavaLangObject(myReferenceExpression.getManager(), targetClass.getResolveScope()); + } String varName = myReferenceExpression.getReferenceName(); PsiExpression initializer = null; diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java index 8f48d192d81f..d37425b05967 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java @@ -385,7 +385,7 @@ public class RefactoringUtil { public static PsiType getTypeByExpressionWithExpectedType(PsiExpression expr) { PsiElementFactory factory = JavaPsiFacade.getInstance(expr.getProject()).getElementFactory(); PsiType type = getTypeByExpression(expr, factory); - final boolean isFunctionalType = type instanceof PsiLambdaExpressionType || type instanceof PsiMethodReferenceType || type instanceof PsiLambdaParameterType; + final boolean isFunctionalType = LambdaUtil.notInferredType(type); final boolean isDenotable = PsiTypesUtil.isDenotableType(expr.getType()); if (type != null && !isFunctionalType && isDenotable) { return type; @@ -404,9 +404,7 @@ public class RefactoringUtil { public static PsiType getTypeByExpression(PsiExpression expr) { PsiElementFactory factory = JavaPsiFacade.getInstance(expr.getProject()).getElementFactory(); PsiType type = getTypeByExpression(expr, factory); - if (type instanceof PsiLambdaParameterType || - type instanceof PsiLambdaExpressionType || - type instanceof PsiMethodReferenceType) { + if (LambdaUtil.notInferredType(type)) { type = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, expr.getResolveScope()); } return type; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java b/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java index f1cde7acd2ce..f5f2ff22f1e9 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java @@ -42,7 +42,7 @@ class TypeCorrector extends PsiTypeMapper { @Override public PsiType visitType(PsiType type) { - if (type instanceof PsiLambdaParameterType || type instanceof PsiLambdaExpressionType || type instanceof PsiMethodReferenceType) { + if (LambdaUtil.notInferredType(type)) { return type; } return super.visitType(type); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterFromLambdaParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterFromLambdaParameter.java new file mode 100644 index 000000000000..3ef4c22eea70 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/afterFromLambdaParameter.java @@ -0,0 +1,8 @@ +// "Create local variable 'a'" "true" +class C { + void foo() { + (s) -> { + Object a = s; + }; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeFromLambdaParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeFromLambdaParameter.java new file mode 100644 index 000000000000..0c023701321b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createLocalFromUsage/beforeFromLambdaParameter.java @@ -0,0 +1,8 @@ +// "Create local variable 'a'" "true" +class C { + void foo() { + (s) -> { + a = s; + }; + } +} From f6e5999a685dab086db8b38c0de0afdd2bce5448 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 16:18:31 +0200 Subject: [PATCH 39/65] read action EA-75848 - assert: SharedImplUtil.findFileElement --- .../com/intellij/xml/impl/schema/SchemaDefinitionsSearch.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xml/impl/src/com/intellij/xml/impl/schema/SchemaDefinitionsSearch.java b/xml/impl/src/com/intellij/xml/impl/schema/SchemaDefinitionsSearch.java index b3cc34ff57a1..b3a77fb15077 100644 --- a/xml/impl/src/com/intellij/xml/impl/schema/SchemaDefinitionsSearch.java +++ b/xml/impl/src/com/intellij/xml/impl/schema/SchemaDefinitionsSearch.java @@ -53,7 +53,7 @@ public class SchemaDefinitionsSearch implements QueryExecutor consumer) { if (queryParameters instanceof XmlTagImpl) { final XmlTagImpl xml = (XmlTagImpl) queryParameters; - if (isTypeElement(xml)) { + if (ApplicationManager.getApplication().runReadAction((Computable)() -> isTypeElement(xml))) { final Collection infos = ApplicationManager.getApplication().runReadAction(new Computable>() { @Override From 1126e85c51d63c6ae01df0c007e722db0c4de513 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 16:22:26 +0200 Subject: [PATCH 40/65] EA-76035 - PIEAE: PsiUtilCore.ensureValid --- .../impl/quickfix/MethodReturnTypeFix.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java index 2848899bab90..308ffa30cef1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java @@ -40,7 +40,6 @@ import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor; import com.intellij.refactoring.changeSignature.OverriderUsageInfo; import com.intellij.refactoring.changeSignature.ParameterInfoImpl; -import com.intellij.refactoring.typeMigration.TypeMigrationLabeler; import com.intellij.refactoring.typeMigration.TypeMigrationProcessor; import com.intellij.refactoring.typeMigration.TypeMigrationRules; import com.intellij.usageView.UsageInfo; @@ -89,14 +88,16 @@ public class MethodReturnTypeFix extends LocalQuickFixAndIntentionActionOnPsiEle @NotNull PsiElement endElement) { final PsiMethod myMethod = (PsiMethod)startElement; - PsiType myReturnType = myReturnTypePointer.getType(); - return myMethod.isValid() - && myMethod.getManager().isInProject(myMethod) - && myReturnType != null - && myReturnType.isValid() - && !TypeConversionUtil.isNullType(myReturnType) - && myMethod.getReturnType() != null - && !Comparing.equal(myReturnType, myMethod.getReturnType()); + final PsiType myReturnType = myReturnTypePointer.getType(); + if (myMethod.isValid() && + myMethod.getManager().isInProject(myMethod) && + myReturnType != null && + myReturnType.isValid() && + !TypeConversionUtil.isNullType(myReturnType)) { + final PsiType returnType = myMethod.getReturnType(); + if (returnType != null && returnType.isValid() && !Comparing.equal(myReturnType, returnType)) return true; + } + return false; } @Override From 79605693259dbdfa50c851a0899ff1a3474295be Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 22 Apr 2016 16:56:30 +0200 Subject: [PATCH 41/65] Cleanup (formatting; warnings) --- .../intellij/psi/PsiCapturedWildcardType.java | 6 ++-- .../src/com/intellij/psi/PsiClassType.java | 13 +++---- .../src/com/intellij/psi/PsiDiamondType.java | 6 ++-- .../com/intellij/psi/PsiDisjunctionType.java | 6 ++-- .../com/intellij/psi/PsiIntersectionType.java | 8 +++-- .../intellij/psi/PsiLambdaExpressionType.java | 6 ++-- .../intellij/psi/PsiLambdaParameterType.java | 6 ++-- .../src/com/intellij/psi/Bottom.java | 13 +++---- .../com/intellij/psi/PsiDiamondTypeImpl.java | 36 +++++++++---------- .../src/com/intellij/psi/PsiTypeVariable.java | 6 ++-- .../refactoring/util/CanonicalTypes.java | 6 ++-- 11 files changed, 53 insertions(+), 59 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java index b9d13bc76073..c69c9250b8a2 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -48,7 +48,7 @@ public class PsiCapturedWildcardType extends PsiType.Stub { private PsiCapturedWildcardType(@NotNull PsiWildcardType existential, @NotNull PsiElement context, @Nullable PsiTypeParameter parameter) { - super(PsiAnnotation.EMPTY_ARRAY); + super(TypeAnnotationProvider.EMPTY); myExistential = existential; myContext = context; myParameter = parameter; @@ -208,4 +208,4 @@ public class PsiCapturedWildcardType extends PsiType.Stub { public PsiTypeParameter getTypeParameter() { return myParameter; } -} +} \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/PsiClassType.java b/java/java-psi-api/src/com/intellij/psi/PsiClassType.java index 8a322bca993b..5906e1d3c7c8 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiClassType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiClassType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -30,9 +30,6 @@ import org.jetbrains.annotations.Nullable; * @author max */ public abstract class PsiClassType extends PsiType { - /** - * The empty array of PSI class types which can be reused to avoid unnecessary allocations. - */ public static final PsiClassType[] EMPTY_ARRAY = new PsiClassType[0]; public static final ArrayFactory ARRAY_FACTORY = new ArrayFactory() { @NotNull @@ -53,8 +50,8 @@ public abstract class PsiClassType extends PsiType { myLanguageLevel = languageLevel; } - public PsiClassType(LanguageLevel languageLevel, @NotNull TypeAnnotationProvider annotations) { - super(annotations); + public PsiClassType(LanguageLevel languageLevel, @NotNull TypeAnnotationProvider provider) { + super(provider); myLanguageLevel = languageLevel; } @@ -221,7 +218,7 @@ public abstract class PsiClassType extends PsiType { public abstract PsiClassType rawType(); /** - * Overrides {@link com.intellij.psi.PsiType#getResolveScope()} to narrow specify @NotNull. + * Overrides {@link PsiType#getResolveScope()} to narrow specify @NotNull. */ @Override @NotNull @@ -314,4 +311,4 @@ public abstract class PsiClassType extends PsiType { @Override public abstract String getCanonicalText(boolean annotated); } -} +} \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/PsiDiamondType.java b/java/java-psi-api/src/com/intellij/psi/PsiDiamondType.java index bc71843ee20b..8b92ec95a3ae 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiDiamondType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiDiamondType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -26,8 +26,8 @@ import java.util.List; public abstract class PsiDiamondType extends PsiType { public static final RecursionGuard ourDiamondGuard = RecursionManager.createGuard("diamondInference"); - public PsiDiamondType(PsiAnnotation[] annotations) { - super(annotations); + public PsiDiamondType() { + super(TypeAnnotationProvider.EMPTY); } public abstract DiamondInferenceResult resolveInferredTypes(); diff --git a/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java b/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java index 2b5299e35327..d2c4a2ea0651 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiDisjunctionType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -39,7 +39,7 @@ public class PsiDisjunctionType extends PsiType.Stub { private final CachedValue myLubCache; public PsiDisjunctionType(@NotNull List types, @NotNull PsiManager psiManager) { - super(PsiAnnotation.EMPTY_ARRAY); + super(TypeAnnotationProvider.EMPTY); myManager = psiManager; myTypes = Collections.unmodifiableList(types); @@ -168,4 +168,4 @@ public class PsiDisjunctionType extends PsiType.Stub { return true; } -} +} \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java index f46e68012ed9..0adc5e1c79e9 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -35,7 +35,7 @@ public class PsiIntersectionType extends PsiType.Stub { private final PsiType[] myConjuncts; private PsiIntersectionType(@NotNull PsiType[] conjuncts) { - super(PsiAnnotation.EMPTY_ARRAY); + super(TypeAnnotationProvider.EMPTY); myConjuncts = conjuncts; } @@ -176,6 +176,7 @@ public class PsiIntersectionType extends PsiType.Stub { return myConjuncts[0]; } + @Override public boolean equals(final Object obj) { if (this == obj) return true; if (!(obj instanceof PsiIntersectionType)) return false; @@ -190,6 +191,7 @@ public class PsiIntersectionType extends PsiType.Stub { return true; } + @Override public int hashCode() { return myConjuncts[0].hashCode(); } @@ -221,4 +223,4 @@ public class PsiIntersectionType extends PsiType.Stub { } return null; } -} +} \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/PsiLambdaExpressionType.java b/java/java-psi-api/src/com/intellij/psi/PsiLambdaExpressionType.java index db9db62596c1..7f6b0e7e53d2 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiLambdaExpressionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiLambdaExpressionType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -26,7 +26,7 @@ public class PsiLambdaExpressionType extends PsiType { private final PsiLambdaExpression myExpression; public PsiLambdaExpressionType(PsiLambdaExpression expression) { - super(PsiAnnotation.EMPTY_ARRAY); + super(TypeAnnotationProvider.EMPTY); myExpression = expression; } @@ -77,4 +77,4 @@ public class PsiLambdaExpressionType extends PsiType { public PsiLambdaExpression getExpression() { return myExpression; } -} +} \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/PsiLambdaParameterType.java b/java/java-psi-api/src/com/intellij/psi/PsiLambdaParameterType.java index 6a1991c60b39..9d0e550c6feb 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiLambdaParameterType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiLambdaParameterType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -26,7 +26,7 @@ public class PsiLambdaParameterType extends PsiType { private final PsiParameter myParameter; public PsiLambdaParameterType(PsiParameter parameter) { - super(PsiAnnotation.EMPTY_ARRAY); + super(TypeAnnotationProvider.EMPTY); myParameter = parameter; } @@ -77,4 +77,4 @@ public class PsiLambdaParameterType extends PsiType { public PsiParameter getParameter() { return myParameter; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/Bottom.java b/java/java-psi-impl/src/com/intellij/psi/Bottom.java index 022c8636800a..c128579b50cc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/Bottom.java +++ b/java/java-psi-impl/src/com/intellij/psi/Bottom.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -25,7 +25,7 @@ public class Bottom extends PsiType { public static final Bottom BOTTOM = new Bottom(); private Bottom() { - super(PsiAnnotation.EMPTY_ARRAY); + super(TypeAnnotationProvider.EMPTY); } @NotNull @@ -56,12 +56,9 @@ public class Bottom extends PsiType { return text.equals("_"); } + @Override public boolean equals(Object o) { - if (o instanceof Bottom) { - return true; - } - - return false; + return o instanceof Bottom; } @Override @@ -84,4 +81,4 @@ public class Bottom extends PsiType { public GlobalSearchScope getResolveScope() { return null; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java index 45dcee6e9460..537a4dcf5759 100644 --- a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -47,13 +47,12 @@ import java.util.*; * @since Jul 30, 2010 */ public class PsiDiamondTypeImpl extends PsiDiamondType { - private static final Logger LOG = Logger.getInstance("#" + PsiDiamondTypeImpl.class.getName()); + private static final Logger LOG = Logger.getInstance(PsiDiamondTypeImpl.class); private final PsiManager myManager; private final PsiTypeElement myTypeElement; public PsiDiamondTypeImpl(PsiManager manager, PsiTypeElement psiTypeElement) { - super(PsiAnnotation.EMPTY_ARRAY); myManager = manager; myTypeElement = psiTypeElement; } @@ -134,9 +133,9 @@ public class PsiDiamondTypeImpl extends PsiDiamondType { final DiamondInferenceResult inferenceResult = resolveInferredTypesNoCheck(newExpression, context); if (anonymousClass != null && PsiUtil.isLanguageLevel9OrHigher(newExpression)) { - final InferredAnonymTypeVisitor anonymTypeVisitor = new InferredAnonymTypeVisitor(context); + final InferredAnonymousTypeVisitor anonymousTypeVisitor = new InferredAnonymousTypeVisitor(context); for (PsiType type : inferenceResult.getInferredTypes()) { - final Boolean accepted = type.accept(anonymTypeVisitor); + final Boolean accepted = type.accept(anonymousTypeVisitor); if (accepted != null && !accepted.booleanValue()) { return PsiDiamondTypeImpl.DiamondInferenceResult.ANONYMOUS_INNER_RESULT; } @@ -150,17 +149,16 @@ public class PsiDiamondTypeImpl extends PsiDiamondType { final PsiSubstitutor inferredSubstitutor = ourDiamondGuard.doPreventingRecursion(context, false, new Computable() { @Override public PsiSubstitutor compute() { - final JavaResolveResult staticFactoryCandidateInfo = context == newExpression ? - CachedValuesManager.getCachedValue(newExpression, - new CachedValueProvider() { - @Nullable - @Override - public Result compute() { - return new Result(getStaticFactoryCandidateInfo(newExpression, newExpression), - PsiModificationTracker.MODIFICATION_COUNT); - } - }) - : getStaticFactoryCandidateInfo(newExpression, context); + final JavaResolveResult staticFactoryCandidateInfo = + context == newExpression + ? CachedValuesManager.getCachedValue(newExpression, new CachedValueProvider() { + @Nullable + @Override + public Result compute() { + return new Result(getStaticFactoryCandidateInfo(newExpression, newExpression), PsiModificationTracker.MODIFICATION_COUNT); + } + }) + : getStaticFactoryCandidateInfo(newExpression, context); staticFactoryRef.set(staticFactoryCandidateInfo); if (staticFactoryCandidateInfo != null) { PsiSubstitutor substitutor = staticFactoryCandidateInfo.getSubstitutor(); @@ -515,10 +513,10 @@ public class PsiDiamondTypeImpl extends PsiDiamondType { * The term "subexpression" includes type arguments of parameterized types (4.5), bounds of wildcards (4.5.1), and element types of array types (10.1). * It excludes bounds of type variables. */ - private static class InferredAnonymTypeVisitor extends PsiTypeVisitor { + private static class InferredAnonymousTypeVisitor extends PsiTypeVisitor { private final PsiElement myExpression; - public InferredAnonymTypeVisitor(PsiElement expression) { + public InferredAnonymousTypeVisitor(PsiElement expression) { myExpression = expression; } @@ -564,4 +562,4 @@ public class PsiDiamondTypeImpl extends PsiDiamondType { return true; } } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/PsiTypeVariable.java b/java/java-psi-impl/src/com/intellij/psi/PsiTypeVariable.java index 872c8ded71ea..83ab83092689 100644 --- a/java/java-psi-impl/src/com/intellij/psi/PsiTypeVariable.java +++ b/java/java-psi-impl/src/com/intellij/psi/PsiTypeVariable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -22,7 +22,7 @@ import org.jetbrains.annotations.NotNull; */ public abstract class PsiTypeVariable extends PsiType { protected PsiTypeVariable() { - super(PsiAnnotation.EMPTY_ARRAY); + super(TypeAnnotationProvider.EMPTY); } public abstract int getIndex(); @@ -37,4 +37,4 @@ public abstract class PsiTypeVariable extends PsiType { return visitor.visitType(this); } } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/CanonicalTypes.java b/java/java-psi-impl/src/com/intellij/refactoring/util/CanonicalTypes.java index ccb12db66200..056020a814fe 100644 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/CanonicalTypes.java +++ b/java/java-psi-impl/src/com/intellij/refactoring/util/CanonicalTypes.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -326,7 +326,7 @@ public class CanonicalTypes { PsiType substitute = substitutor.substitute(typeParameter); substitutionMap.put(typeParameter.getName(), substitute != null ? substitute.accept(this) : null); } - String qualifiedName = ObjectUtils.notNull(aClass.getQualifiedName(), aClass.getName()); + String qualifiedName = ObjectUtils.notNull(aClass.getQualifiedName(), ObjectUtils.assertNotNull(aClass.getName())); return new ClassType(type, qualifiedName, substitutionMap); } } @@ -358,4 +358,4 @@ public class CanonicalTypes { public static Type createTypeWrapper(@NotNull PsiType type) { return type.accept(Creator.INSTANCE); } -} +} \ No newline at end of file From 07042165fa149e5a26ed1c7f9be9e9b27ccb06df Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 22 Apr 2016 17:12:06 +0200 Subject: [PATCH 42/65] [java] introduces PsiType.annotate() --- .../src/com/intellij/psi/PsiArrayType.java | 24 +++++++++++-------- .../src/com/intellij/psi/PsiEllipsisType.java | 21 +++++++++------- .../com/intellij/psi/PsiPrimitiveType.java | 22 ++++++++++------- .../src/com/intellij/psi/PsiType.java | 5 ++++ .../src/com/intellij/psi/PsiWildcardType.java | 17 ++++++------- .../impl/source/PsiClassReferenceType.java | 14 +++++++---- .../impl/source/PsiImmediateClassType.java | 19 ++++++++++----- 7 files changed, 77 insertions(+), 45 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java b/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java index 71292309cfc4..d8f7e29c11b7 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -26,24 +26,26 @@ import org.jetbrains.annotations.NotNull; public class PsiArrayType extends PsiType.Stub { private final PsiType myComponentType; - /** - * Creates an array type with the specified component type. - * - * @param componentType the type of the array component. - */ public PsiArrayType(@NotNull PsiType componentType) { - this(componentType, PsiAnnotation.EMPTY_ARRAY); + this(componentType, TypeAnnotationProvider.EMPTY); } public PsiArrayType(@NotNull PsiType componentType, @NotNull PsiAnnotation[] annotations) { super(annotations); myComponentType = componentType; } - public PsiArrayType(@NotNull PsiType componentType, @NotNull TypeAnnotationProvider annotations) { - super(annotations); + + public PsiArrayType(@NotNull PsiType componentType, @NotNull TypeAnnotationProvider provider) { + super(provider); myComponentType = componentType; } + @NotNull + @Override + public PsiArrayType annotate(@NotNull TypeAnnotationProvider provider) { + return new PsiArrayType(myComponentType, provider); + } + @NotNull @Override public String getPresentableText() { @@ -117,13 +119,15 @@ public class PsiArrayType extends PsiType.Stub { return myComponentType; } + @Override public boolean equals(Object obj) { return obj instanceof PsiArrayType && (this instanceof PsiEllipsisType == obj instanceof PsiEllipsisType) && myComponentType.equals(((PsiArrayType)obj).getComponentType()); } + @Override public int hashCode() { return myComponentType.hashCode() * 3; } -} +} \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java index b00ece6a7798..639bbeb46211 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -23,11 +23,6 @@ import org.jetbrains.annotations.NotNull; * @author ven */ public class PsiEllipsisType extends PsiArrayType { - /** - * Creates an ellipsis type instance with the specified component type. - * - * @param componentType the type of the varargs array component. - */ public PsiEllipsisType(@NotNull PsiType componentType) { super(componentType); } @@ -35,8 +30,15 @@ public class PsiEllipsisType extends PsiArrayType { public PsiEllipsisType(@NotNull PsiType componentType, @NotNull PsiAnnotation[] annotations) { super(componentType, annotations); } - public PsiEllipsisType(@NotNull PsiType componentType, @NotNull TypeAnnotationProvider annotations) { - super(componentType, annotations); + + public PsiEllipsisType(@NotNull PsiType componentType, @NotNull TypeAnnotationProvider provider) { + super(componentType, provider); + } + + @NotNull + @Override + public PsiEllipsisType annotate(@NotNull TypeAnnotationProvider provider) { + return new PsiEllipsisType(getComponentType(), provider); } @NotNull @@ -82,7 +84,8 @@ public class PsiEllipsisType extends PsiArrayType { return visitor.visitEllipsisType(this); } + @Override public int hashCode() { return super.hashCode() * 5; } -} +} \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java index 82854ddffb85..231744cdddef 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -19,7 +19,6 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiUtil; import gnu.trove.THashMap; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,23 +35,30 @@ public class PsiPrimitiveType extends PsiType.Stub { private final String myName; - PsiPrimitiveType(@NonNls @NotNull String name, @NonNls String boxedName) { - this(name, PsiAnnotation.EMPTY_ARRAY); + PsiPrimitiveType(@NotNull String name, String boxedName) { + this(name, TypeAnnotationProvider.EMPTY); if (boxedName != null) { ourQNameToUnboxed.put(boxedName, this); ourUnboxedToQName.put(this, boxedName); } } - public PsiPrimitiveType(@NonNls @NotNull String name, @NotNull PsiAnnotation[] annotations) { + public PsiPrimitiveType(@NotNull String name, @NotNull PsiAnnotation[] annotations) { super(annotations); myName = name; } - public PsiPrimitiveType(@NonNls @NotNull String name, @NotNull TypeAnnotationProvider annotations) { - super(annotations); + + public PsiPrimitiveType(@NotNull String name, @NotNull TypeAnnotationProvider provider) { + super(provider); myName = name; } + @NotNull + @Override + public PsiPrimitiveType annotate(@NotNull TypeAnnotationProvider provider) { + return new PsiPrimitiveType(myName, provider); + } + @NotNull @Override public String getPresentableText() { @@ -187,4 +193,4 @@ public class PsiPrimitiveType extends PsiType.Stub { public boolean equals(Object obj) { return obj instanceof PsiPrimitiveType && myName.equals(((PsiPrimitiveType)obj).myName); } -} +} \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/PsiType.java b/java/java-psi-api/src/com/intellij/psi/PsiType.java index 3c59fd2633e9..2b8f63b4ddbc 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiType.java @@ -72,6 +72,11 @@ public abstract class PsiType implements PsiAnnotationOwner { myAnnotationProvider = annotations; } + @NotNull + public PsiType annotate(@NotNull TypeAnnotationProvider provider) { + throw new UnsupportedOperationException("Not implemented for " + getClass()); + } + /** * Creates array type with this type as a component. */ diff --git a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java index f5c199de6642..76d6914ed612 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -31,7 +31,7 @@ public class PsiWildcardType extends PsiType.Stub { public static final String EXTENDS_PREFIX = "? extends "; public static final String SUPER_PREFIX = "? super "; - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiWildcardType"); + private static final Logger LOG = Logger.getInstance(PsiWildcardType.class); private static final Key UNBOUNDED_WILDCARD = new Key("UNBOUNDED_WILDCARD"); private final PsiManager myManager; @@ -39,14 +39,14 @@ public class PsiWildcardType extends PsiType.Stub { private final PsiType myBound; private PsiWildcardType(@NotNull PsiManager manager, boolean isExtending, @Nullable PsiType bound) { - super(PsiAnnotation.EMPTY_ARRAY); + super(TypeAnnotationProvider.EMPTY); myManager = manager; myIsExtending = isExtending; myBound = bound; } - private PsiWildcardType(@NotNull PsiWildcardType type, @NotNull TypeAnnotationProvider annotations) { - super(annotations); + private PsiWildcardType(@NotNull PsiWildcardType type, @NotNull TypeAnnotationProvider provider) { + super(provider); myManager = type.myManager; myIsExtending = type.myIsExtending; myBound = type.myBound; @@ -87,8 +87,9 @@ public class PsiWildcardType extends PsiType.Stub { } @NotNull - public PsiWildcardType annotate(@NotNull final TypeAnnotationProvider annotations) { - return new PsiWildcardType(this, annotations); + @Override + public PsiWildcardType annotate(@NotNull TypeAnnotationProvider provider) { + return new PsiWildcardType(this, provider); } @NotNull @@ -261,4 +262,4 @@ public class PsiWildcardType extends PsiType.Stub { public PsiType getSuperBound() { return myBound == null || myIsExtending ? NULL : myBound; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java index c4cf9db93b6c..a03c7956aca1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -42,8 +42,8 @@ public class PsiClassReferenceType extends PsiClassType.Stub { myReference = reference; } - public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level, @NotNull TypeAnnotationProvider annotations) { - super(level, annotations); + public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level, @NotNull TypeAnnotationProvider provider) { + super(level, provider); myReference = reference; } @@ -58,6 +58,12 @@ public class PsiClassReferenceType extends PsiClassType.Stub { return result == null ? PsiAnnotation.EMPTY_ARRAY : result.toArray(new PsiAnnotation[result.size()]); } + @NotNull + @Override + public PsiClassReferenceType annotate(@NotNull TypeAnnotationProvider provider) { + return new PsiClassReferenceType(myReference, myLanguageLevel, provider); + } + @Override public boolean isValid() { return myReference.isValid(); @@ -222,4 +228,4 @@ public class PsiClassReferenceType extends PsiClassType.Stub { public PsiJavaCodeReferenceElement getReference() { return myReference; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java index 15823d067a90..9c26c187b6b3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -79,11 +79,11 @@ public class PsiImmediateClassType extends PsiClassType.Stub { }; public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor) { - this(aClass, substitutor, null, PsiAnnotation.EMPTY_ARRAY); + this(aClass, substitutor, null, TypeAnnotationProvider.EMPTY); } public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel level) { - this(aClass, substitutor, level, PsiAnnotation.EMPTY_ARRAY); + this(aClass, substitutor, level, TypeAnnotationProvider.EMPTY); } public PsiImmediateClassType(@NotNull PsiClass aClass, @@ -96,17 +96,24 @@ public class PsiImmediateClassType extends PsiClassType.Stub { mySubstitutor = substitutor; assert substitutor.isValid(); } + public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel level, - @NotNull TypeAnnotationProvider annotations) { - super(level, annotations); + @NotNull TypeAnnotationProvider provider) { + super(level, provider); myClass = aClass; myManager = aClass.getManager(); mySubstitutor = substitutor; assert substitutor.isValid(); } + @NotNull + @Override + public PsiImmediateClassType annotate(@NotNull TypeAnnotationProvider provider) { + return new PsiImmediateClassType(myClass, mySubstitutor, myLanguageLevel, provider); + } + @Override public PsiClass resolve() { return myClass; @@ -313,4 +320,4 @@ public class PsiImmediateClassType extends PsiClassType.Stub { public PsiClassType setLanguageLevel(@NotNull LanguageLevel level) { return level.equals(myLanguageLevel) ? this : new PsiImmediateClassType(myClass, mySubstitutor, level, getAnnotationProvider()); } -} +} \ No newline at end of file From fb7cb9aef6cc1b1901b1d0306779218e427107b3 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Fri, 22 Apr 2016 18:19:50 +0300 Subject: [PATCH 43/65] JBIterator: implement skip() for real --- .../util/containers/TreeTraverserTest.java | 15 +++++++++++++++ .../com/intellij/util/containers/JBIterator.java | 16 ++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/platform/platform-tests/testSrc/com/intellij/util/containers/TreeTraverserTest.java b/platform/platform-tests/testSrc/com/intellij/util/containers/TreeTraverserTest.java index d3cd404e9312..f04035c86f8c 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/containers/TreeTraverserTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/containers/TreeTraverserTest.java @@ -23,6 +23,7 @@ import junit.framework.TestCase; import org.jetbrains.annotations.NotNull; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import static com.intellij.openapi.util.Conditions.not; @@ -227,6 +228,20 @@ public class TreeTraverserTest extends TestCase { assertEquals(Arrays.asList(1, 2), list); } + public void testIteratorContractsSkipAndStop() { + final AtomicInteger count = new AtomicInteger(0); + JBIterator it = new JBIterator() { + + @Override + protected Integer nextImpl() { + return count.get() < 0 ? stop() : + count.incrementAndGet() < 10 ? skip() : + (Integer)count.addAndGet(-count.get() - 1); + } + }; + assertEquals(JBIterable.of(-1).toList(), JBIterable.once(it).toList()); + } + // JBIterable ---------------------------------------------- public void testAppend() { diff --git a/platform/util/src/com/intellij/util/containers/JBIterator.java b/platform/util/src/com/intellij/util/containers/JBIterator.java index c14a398ce6fb..8caa1e2140d7 100644 --- a/platform/util/src/com/intellij/util/containers/JBIterator.java +++ b/platform/util/src/com/intellij/util/containers/JBIterator.java @@ -45,7 +45,7 @@ import java.util.NoSuchElementException; * * @author gregsh * - * @noinspection unchecked + * @noinspection unchecked, AssignmentToForLoopParameter */ public abstract class JBIterator implements Iterator { private static final Object NONE = new String("#none"); @@ -137,18 +137,14 @@ public abstract class JBIterator implements Iterator { private void peekNext() { if (myNext != NONE) return; - Object o = nextImpl(); - if (myNext == STOP) return; - Op op = myFirstOp.nextOp; - while (op != null) { - o = op.apply(o); + Object o = NONE; + for (Op op = myFirstOp; op != null; op = op == null ? myFirstOp : op.nextOp) { + o = op == myFirstOp ? nextImpl() : op.apply(o); if (myNext == SKIP) { - myNext = NONE; - o = nextImpl(); - op = myFirstOp; + o = myNext = NONE; + op = null; } if (myNext == STOP) return; - op = op.nextOp; } myNext = o; } From 042f65d0783f8ee3d1e3a88da972adcd4c0b325f Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Fri, 22 Apr 2016 18:59:31 +0300 Subject: [PATCH 44/65] mocha: show actual file in Diff dialog (WEB-15907) --- .../sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java index a84cefa94b4c..2646cceaa08d 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java @@ -271,7 +271,8 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP if (comparisonFailureActualText != null && comparisonFailureExpectedText != null) { testProxy.setTestComparisonFailed(failureMessage, stackTrace, comparisonFailureActualText, comparisonFailureExpectedText, - testFailedEvent.getExpectedFilePath()); + testFailedEvent.getExpectedFilePath(), + testFailedEvent.getActualFilePath()); } else if (comparisonFailureActualText == null && comparisonFailureExpectedText == null) { testProxy.setTestFailed(failureMessage, stackTrace, testFailedEvent.isTestError()); } else { From 1a176631276b82f3e9485674d80bb935aec9acbf Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Wed, 20 Apr 2016 23:05:55 +0300 Subject: [PATCH 45/65] Refactoring: BaseRefence and PyStringLiteralReference moved to community --- .../com/jetbrains/python/BaseReference.java | 71 +++++++++++++++++++ .../python/PyStringLiteralReference.java | 50 +++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 python/src/com/jetbrains/python/BaseReference.java create mode 100644 python/src/com/jetbrains/python/PyStringLiteralReference.java diff --git a/python/src/com/jetbrains/python/BaseReference.java b/python/src/com/jetbrains/python/BaseReference.java new file mode 100644 index 000000000000..e6a385bd94db --- /dev/null +++ b/python/src/com/jetbrains/python/BaseReference.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2016 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.python; + +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Alexei Orischenko + * Date: Dec 4, 2009 + */ +public abstract class BaseReference implements PsiReference, PyUserInitiatedResolvableReference { + protected final PsiElement myElement; + + protected BaseReference(@NotNull PsiElement element) { + myElement = element; + } + + public PsiElement getElement() { + return myElement; + } + + public TextRange getRangeInElement() { + return new TextRange(0, myElement.getTextLength()); + } + + @NotNull + public String getCanonicalText() { + return myElement.getText(); + } + + public PsiElement handleElementRename(@NotNull String newElementName) throws IncorrectOperationException { + throw new IncorrectOperationException(); + } + + public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { + return null; + } + + public boolean isReferenceTo(PsiElement element) { + return resolve() == element; + } + + public boolean isSoft() { + return false; + } + + @Nullable + @Override + public PsiElement userInitiatedResolve() { + // Override this method if your reference may benefit from this knowledge + return resolve(); + } +} diff --git a/python/src/com/jetbrains/python/PyStringLiteralReference.java b/python/src/com/jetbrains/python/PyStringLiteralReference.java new file mode 100644 index 000000000000..46fd61466ac9 --- /dev/null +++ b/python/src/com/jetbrains/python/PyStringLiteralReference.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2016 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.python; + +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.jetbrains.python.psi.PyElementGenerator; +import com.jetbrains.python.psi.StringLiteralExpression; +import org.jetbrains.annotations.NotNull; + +/** + * Some reference for string literal (handles rename and range correctly) + * + * @author Ilya.Kazakevich + */ +public abstract class PyStringLiteralReference extends BaseReference { + @NotNull + protected final StringLiteralExpression myStringLiteral; + + protected PyStringLiteralReference(@NotNull final StringLiteralExpression element) { + super(element); + myStringLiteral = element; + } + + @SuppressWarnings("RefusedBequest") // 1 instead of 1 in range and "-1" at the end because we do not need quotes + @Override + public final TextRange getRangeInElement() { + return PythonStringUtil.getTextRange(myElement); + } + + @Override + public PsiElement handleElementRename(@NotNull final String newElementName) { + final PsiElement newString = PyElementGenerator.getInstance(myElement.getProject()).createStringLiteralFromString(newElementName); + myStringLiteral.replace(newString); + return newString; + } +} From 9c0948ebcf90b20e466f064ca4f0441a76f723db Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 22 Apr 2016 18:55:50 +0300 Subject: [PATCH 46/65] fix drag behaviour when mouse press point is on gutter side of folding area earlier for such a click mouse movement has been disabled (see commit 670e628), but we must also remember a line where click was made in this case, to move caret there if mouse press is continued with a drag, just like it's done when initial mouse press is inside gutter icons area --- .../src/com/intellij/openapi/editor/impl/EditorImpl.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 1c41c4cf2770..361a49b9fe74 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -4413,7 +4413,9 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return; } - if (getMouseEventArea(e) == EditorMouseEventArea.LINE_MARKERS_AREA) { + EditorMouseEventArea eventArea = getMouseEventArea(e); + if (eventArea == EditorMouseEventArea.LINE_MARKERS_AREA || + eventArea == EditorMouseEventArea.FOLDING_OUTLINE_AREA && !isInsideGutterWhitespaceArea(e)) { // The general idea is that we don't want to change caret position on gutter marker area click (e.g. on setting a breakpoint) // but do want to allow bulk selection on gutter marker mouse drag. However, when a drag is performed, the first event is // a 'mouse pressed' event, that's why we remember target line on 'mouse pressed' processing and use that information on @@ -5857,7 +5859,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myExpectedCaretOffset = -1; } - if (event.getArea() == EditorMouseEventArea.LINE_MARKERS_AREA) { + if (event.getArea() == EditorMouseEventArea.LINE_MARKERS_AREA || + event.getArea() == EditorMouseEventArea.FOLDING_OUTLINE_AREA && !isInsideGutterWhitespaceArea(e)) { myDragOnGutterSelectionStartLine = EditorUtil.yPositionToLogicalLine(EditorImpl.this, e); } From d77c31eaba2863882a07ba420d1c05c5b08e302c Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 22 Apr 2016 18:53:21 +0200 Subject: [PATCH 47/65] [java] introduces PsiType.annotate(); minor optimization --- java/java-psi-api/src/com/intellij/psi/PsiArrayType.java | 2 +- .../src/com/intellij/psi/PsiEllipsisType.java | 2 +- .../src/com/intellij/psi/PsiPrimitiveType.java | 2 +- .../src/com/intellij/psi/PsiWildcardType.java | 2 +- .../intellij/psi/impl/source/PsiClassReferenceType.java | 2 +- .../intellij/psi/impl/source/PsiImmediateClassType.java | 9 ++++----- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java b/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java index d8f7e29c11b7..5019d5b57fed 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiArrayType.java @@ -43,7 +43,7 @@ public class PsiArrayType extends PsiType.Stub { @NotNull @Override public PsiArrayType annotate(@NotNull TypeAnnotationProvider provider) { - return new PsiArrayType(myComponentType, provider); + return provider == getAnnotationProvider() ? this : new PsiArrayType(myComponentType, provider); } @NotNull diff --git a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java index 639bbeb46211..d7105defd1a2 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java @@ -38,7 +38,7 @@ public class PsiEllipsisType extends PsiArrayType { @NotNull @Override public PsiEllipsisType annotate(@NotNull TypeAnnotationProvider provider) { - return new PsiEllipsisType(getComponentType(), provider); + return provider == getAnnotationProvider() ? this : new PsiEllipsisType(getComponentType(), provider); } @NotNull diff --git a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java index 231744cdddef..5ce28619f7fb 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java @@ -56,7 +56,7 @@ public class PsiPrimitiveType extends PsiType.Stub { @NotNull @Override public PsiPrimitiveType annotate(@NotNull TypeAnnotationProvider provider) { - return new PsiPrimitiveType(myName, provider); + return provider == getAnnotationProvider() ? this : new PsiPrimitiveType(myName, provider); } @NotNull diff --git a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java index 76d6914ed612..5ed01f39b4a8 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java @@ -89,7 +89,7 @@ public class PsiWildcardType extends PsiType.Stub { @NotNull @Override public PsiWildcardType annotate(@NotNull TypeAnnotationProvider provider) { - return new PsiWildcardType(this, provider); + return provider == getAnnotationProvider() ? this : new PsiWildcardType(this, provider); } @NotNull diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java index a03c7956aca1..585922734345 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java @@ -61,7 +61,7 @@ public class PsiClassReferenceType extends PsiClassType.Stub { @NotNull @Override public PsiClassReferenceType annotate(@NotNull TypeAnnotationProvider provider) { - return new PsiClassReferenceType(myReference, myLanguageLevel, provider); + return provider == getAnnotationProvider() ? this : new PsiClassReferenceType(myReference, myLanguageLevel, provider); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java index 9c26c187b6b3..f2bd79ba335e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java @@ -111,7 +111,7 @@ public class PsiImmediateClassType extends PsiClassType.Stub { @NotNull @Override public PsiImmediateClassType annotate(@NotNull TypeAnnotationProvider provider) { - return new PsiImmediateClassType(myClass, mySubstitutor, myLanguageLevel, provider); + return provider == getAnnotationProvider() ? this : new PsiImmediateClassType(myClass, mySubstitutor, myLanguageLevel, provider); } @Override @@ -123,6 +123,7 @@ public class PsiImmediateClassType extends PsiClassType.Stub { public String getClassName() { return myClass.getName(); } + @Override @NotNull public PsiType[] getParameters() { @@ -134,12 +135,10 @@ public class PsiImmediateClassType extends PsiClassType.Stub { List lst = new ArrayList(); for (PsiTypeParameter parameter : parameters) { PsiType substituted = mySubstitutor.substitute(parameter); - if (substituted != null) { - lst.add(substituted); - } - else { + if (substituted == null) { return PsiType.EMPTY_ARRAY; } + lst.add(substituted); } return lst.toArray(createArray(lst.size())); } From 5984dae7acb6b5057609a0da23bf282f28163538 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 18:01:35 +0200 Subject: [PATCH 48/65] trim input name before validate; trimmed on create already (IDEA-155062) --- .../com/intellij/ide/actions/CreateFileFromTemplateDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateDialog.java index 2d93ffec1a14..e584694f946d 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateDialog.java @@ -59,7 +59,7 @@ public class CreateFileFromTemplateDialog extends DialogWrapper { @Override protected ValidationInfo doValidate() { if (myInputValidator != null) { - final String text = myNameField.getText(); + final String text = myNameField.getText().trim(); final boolean canClose = myInputValidator.canClose(text); if (!canClose) { String errorText = LangBundle.message("incorrect.name"); From b7eddbbbc393f72dbba5753bca1a227a602b0643 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 19:04:56 +0200 Subject: [PATCH 49/65] extract method: fold parameters after array acces was detected (IDEA-155094) --- .../refactoring/extractMethod/ParametersFolder.java | 11 ++++------- .../extractMethod/ArrayAccessWithTopExpression.java | 8 ++++++++ .../ArrayAccessWithTopExpression_after.java | 12 ++++++++++++ .../com/intellij/refactoring/ExtractMethodTest.java | 4 ++++ 4 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithTopExpression.java create mode 100644 java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithTopExpression_after.java diff --git a/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java b/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java index 50a5e91903d0..b7e0e48f8c4b 100644 --- a/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java +++ b/java/java-analysis-impl/src/com/intellij/refactoring/extractMethod/ParametersFolder.java @@ -118,15 +118,12 @@ public class ParametersFolder { PsiExpression mostRanked = null; for (int i = mentionedInExpressions.size() - 1; i >= 0; i--) { PsiExpression expression = mentionedInExpressions.get(i); - if (expression instanceof PsiArrayAccessExpression) { - mostRanked = expression; - if (!isConditional(expression, scope)) { - myFoldingSelectedByDefault = true; - break; - } + boolean arrayAccess = expression instanceof PsiArrayAccessExpression && !isConditional(expression, scope); + if (arrayAccess) { + myFoldingSelectedByDefault = true; } final int r = findUsedVariables(data, inputVariables, expression).size(); - if (currentRank < r) { + if (currentRank < r || arrayAccess && currentRank == r) { currentRank = r; mostRanked = expression; } diff --git a/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithTopExpression.java b/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithTopExpression.java new file mode 100644 index 000000000000..453e376880d5 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithTopExpression.java @@ -0,0 +1,8 @@ +class Test { + { + int i = 0; + double[] doubles = null; + + double progressResult = doubles[0] / i; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithTopExpression_after.java b/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithTopExpression_after.java new file mode 100644 index 000000000000..11b7df990b29 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/ArrayAccessWithTopExpression_after.java @@ -0,0 +1,12 @@ +class Test { + { + int i = 0; + double[] doubles = null; + + newMethod(doubles[0] / i); + } + + private void newMethod(double v) { + double progressResult = v; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index 7df6b43c8fb7..35946793c3a8 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -500,6 +500,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTest(); } + public void testArrayAccessWithTopExpression() throws Exception { + doTest(); + } + public void testArrayAccessWithDuplicates() throws Exception { doDuplicatesTest(); } From dd93b4ba459ef395f6190d355860d29030c50cc8 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 22 Apr 2016 19:20:45 +0200 Subject: [PATCH 50/65] write module classpath if forked per module even if all tests were located in one module as classpath could be from the project as per-config (IDEA-155036) --- .../com/intellij/execution/JavaTestFrameworkRunnableState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java b/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java index f5ce0f3e0442..f07cb5301613 100644 --- a/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java +++ b/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java @@ -369,7 +369,7 @@ public abstract class JavaTestFrameworkRunnableState> perModule) throws FileNotFoundException, UnsupportedEncodingException, CantRunException { - if (perModule != null && perModule.size() > 1) { + if (perModule != null) { final String classpath = getScope() == TestSearchScope.WHOLE_PROJECT ? null : javaParameters.getClassPath().getPathsString(); From 84f06cf5c6d93324e9c4e4257a0b43f4d8a42da5 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 22 Apr 2016 20:44:14 +0300 Subject: [PATCH 51/65] IDEA-139647 Change signature: focus is lost while typing parameter name/value --- .../changeSignature/ParameterTableModelBase.java | 8 +------- .../src/com/intellij/util/ui/ListTableModel.java | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ParameterTableModelBase.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ParameterTableModelBase.java index 21b1a41b8d6f..b1fd7f19fe38 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ParameterTableModelBase.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ParameterTableModelBase.java @@ -64,13 +64,7 @@ public abstract class ParameterTableModelBase

, Aspect> diff --git a/platform/util/src/com/intellij/util/ui/ListTableModel.java b/platform/util/src/com/intellij/util/ui/ListTableModel.java index bdd04ec399ac..28386e00e89e 100644 --- a/platform/util/src/com/intellij/util/ui/ListTableModel.java +++ b/platform/util/src/com/intellij/util/ui/ListTableModel.java @@ -113,10 +113,23 @@ public class ListTableModel extends TableViewModel implements Editab @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + setValueAt(aValue, rowIndex, columnIndex, true); + } + + /** + * Sets the value in the cell at {@code columnIndex} and {@code rowIndex} to {@code aValue}. + * This method allows to choose will the model listeners notified or not. + * + * @param aValue the new value + * @param rowIndex the row whose value is to be changed + * @param columnIndex the column whose value is to be changed + * @param notifyListeners indicates whether the model listeners are notified + */ + public void setValueAt(Object aValue, int rowIndex, int columnIndex, boolean notifyListeners) { if (rowIndex < myItems.size()) { myColumnInfos[columnIndex].setValue(getItem(rowIndex), aValue); } - fireTableCellUpdated(rowIndex, columnIndex); + if (notifyListeners) fireTableCellUpdated(rowIndex, columnIndex); } /** From 8627ab083275c5dbec42699ddc0bbf18001b2bde Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 22 Apr 2016 20:26:21 +0200 Subject: [PATCH 52/65] avoid explicit document commit when setting/getting editor state --- .../codeInsight/folding/impl/CodeFoldingManagerImpl.java | 1 - .../codeInsight/folding/impl/DocumentFoldingInfo.java | 4 +--- .../fileEditor/impl/text/PsiAwareTextEditorProvider.java | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java index f7e436086ce3..80ac45003bbe 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java @@ -186,7 +186,6 @@ public class CodeFoldingManagerImpl extends CodeFoldingManager implements Projec Document document = editor.getDocument(); PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(document); if (file == null || !file.getViewProvider().isPhysical() || !file.isValid()) return; - PsiDocumentManager.getInstance(myProject).commitDocument(document); Editor[] otherEditors = EditorFactory.getInstance().getEditors(document, myProject); if (otherEditors.length == 0 && !editor.isDisposed()) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java index 294b8ee6544f..b29f4c6a5366 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/DocumentFoldingInfo.java @@ -80,9 +80,7 @@ class DocumentFoldingInfo implements JDOMExternalizable, CodeFoldingState { LOG.assertTrue(!editor.isDisposed()); clear(); - PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); - documentManager.commitDocument(editor.getDocument()); - PsiFile file = documentManager.getPsiFile(editor.getDocument()); + PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(editor.getDocument()); SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(myProject); EditorFoldingInfo info = EditorFoldingInfo.get(editor); diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorProvider.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorProvider.java index 89866c888758..c4b72aa189f3 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorProvider.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/text/PsiAwareTextEditorProvider.java @@ -137,7 +137,6 @@ public class PsiAwareTextEditorProvider extends TextEditorProvider implements As if (FileEditorStateLevel.FULL == level) { // Folding if (project != null && !project.isDisposed() && !editor.isDisposed() && project.isInitialized()) { - PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); state.setFoldingState(CodeFoldingManager.getInstance(project).saveFoldingState(editor)); } else { @@ -154,7 +153,7 @@ public class PsiAwareTextEditorProvider extends TextEditorProvider implements As // Folding final CodeFoldingState foldState = state.getFoldingState(); if (project != null && foldState != null) { - PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); + LOG.assertTrue(PsiDocumentManager.getInstance(project).isCommitted(editor.getDocument())); editor.getFoldingModel().runBatchFoldingOperation( () -> CodeFoldingManager.getInstance(project).restoreFoldingState(editor, foldState) ); From 6ea3b7a197693deb95e24960e7de5a35a5771551 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 22 Apr 2016 20:48:45 +0200 Subject: [PATCH 53/65] [java] usages migrated to PsiType.annotate() --- .../ParameterObjectBuilder.java | 6 ++--- .../src/com/intellij/psi/GenericsUtil.java | 11 +++++--- .../com/intellij/psi/JVMElementFactory.java | 21 ++++++++++----- .../src/com/intellij/psi/PsiClassType.java | 6 +++++ .../com/intellij/psi/PsiElementFactory.java | 6 ----- .../src/com/intellij/psi/PsiEllipsisType.java | 3 ++- .../com/intellij/psi/PsiJavaParserFacade.java | 7 +++-- .../com/intellij/psi/PsiPrimitiveType.java | 26 +++++++++---------- .../src/com/intellij/psi/PsiType.java | 14 +++------- .../src/com/intellij/psi/PsiWildcardType.java | 11 +++----- .../intellij/psi/TypeAnnotationProvider.java | 24 +++++++++++++++-- .../psi/impl/PsiJavaParserFacadeImpl.java | 15 +++++++---- .../impl/source/tree/JavaSharedImplUtil.java | 4 +-- .../tree/java/PsiNewExpressionImpl.java | 12 +++++---- .../refactoring/util/CanonicalTypes.java | 24 ++++++++--------- .../ig/fixes/ConvertToVarargsMethodFix.java | 6 ++--- .../varargs/MakeMethodVarargsIntention.java | 2 +- .../psi/impl/GroovyPsiElementFactoryImpl.java | 3 ++- 18 files changed, 113 insertions(+), 88 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/ParameterObjectBuilder.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/ParameterObjectBuilder.java index ae0fc205a68c..ac91a848aae8 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/ParameterObjectBuilder.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/ParameterObjectBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -137,8 +137,8 @@ class ParameterObjectBuilder { out.append(CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS ? " final " : ""); final String parameterName = parameter.getName(); final PsiType type = field.getType(); - final PsiType fieldType = parameter.isVarArgs() && type instanceof PsiArrayType ? - PsiEllipsisType.createEllipsis(((PsiArrayType)type).getComponentType(), PsiAnnotation.EMPTY_ARRAY) : type; + final PsiType fieldType = parameter.isVarArgs() && type instanceof PsiArrayType ? + new PsiEllipsisType(((PsiArrayType)type).getComponentType()) : type; out.append(' ' + fieldType.getCanonicalText() + ' ' + parameterName); if (iterator.hasNext()) { out.append(", "); diff --git a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java index aaf7141512ab..aa050b311359 100644 --- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -376,11 +376,14 @@ public class GenericsUtil { LOG.assertTrue(toPut == null || toPut.isValid(), toPut); substitutor = substitutor.put(typeParameter, toPut); } - final PsiAnnotation[] applicableAnnotations = classType.getApplicableAnnotations(); - if (substitutor == PsiSubstitutor.EMPTY && !toExtend && applicableAnnotations.length == 0 && !(aClass instanceof PsiTypeParameter)) return classType; + PsiAnnotation[] applicableAnnotations = classType.getApplicableAnnotations(); + if (substitutor == PsiSubstitutor.EMPTY && !toExtend && applicableAnnotations.length == 0 && !(aClass instanceof PsiTypeParameter)) { + return classType; + } PsiManager manager = aClass.getManager(); PsiType result = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory() - .createType(aClass, substitutor, PsiUtil.getLanguageLevel(aClass), applicableAnnotations); + .createType(aClass, substitutor, PsiUtil.getLanguageLevel(aClass)) + .annotate(TypeAnnotationProvider.Static.create(applicableAnnotations)); if (toExtend) result = PsiWildcardType.createExtends(manager, result); return result; } diff --git a/java/java-psi-api/src/com/intellij/psi/JVMElementFactory.java b/java/java-psi-api/src/com/intellij/psi/JVMElementFactory.java index 7c3999e37a7b..6b1f4f8532b5 100644 --- a/java/java-psi-api/src/com/intellij/psi/JVMElementFactory.java +++ b/java/java-psi-api/src/com/intellij/psi/JVMElementFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -34,7 +34,7 @@ public interface JVMElementFactory { * * @param name the name of the class to create. * @return the created class instance. - * @throws com.intellij.util.IncorrectOperationException + * @throws IncorrectOperationException * if name is not a valid Java identifier. */ @NotNull @@ -175,7 +175,7 @@ public interface JVMElementFactory { * * @param name the name of the annotation type to create. * @return the created annotation type instance. - * @throws com.intellij.util.IncorrectOperationException if name is not a valid Java identifier. + * @throws IncorrectOperationException if name is not a valid Java identifier. */ @NotNull PsiClass createAnnotationType(@NotNull @NonNls String name) throws IncorrectOperationException; @@ -201,13 +201,20 @@ public interface JVMElementFactory { @NotNull PsiClassType createType(@NotNull PsiClass resolve, @NotNull PsiSubstitutor substitutor); - /* - additional languageLevel parameter to memorize language level for allowing/prohibiting boxing/unboxing - */ + /** + * Creates a class type for the specified class, using the specified substitutor + * to replace generic type parameters on the class. + * + * @param resolve the class for which the class type is created. + * @param substitutor the substitutor to use. + * @param languageLevel to memorize language level for allowing/prohibiting boxing/unboxing. + * @return the class type instance. + */ @NotNull PsiClassType createType(@NotNull PsiClass resolve, @NotNull PsiSubstitutor substitutor, @NotNull LanguageLevel languageLevel); - @NotNull + /** @deprecated use {@link PsiType#annotate(TypeAnnotationProvider)} (to be removed in IDEA 18) */ + @SuppressWarnings("unused") PsiClassType createType(@NotNull PsiClass resolve, @NotNull PsiSubstitutor substitutor, @NotNull LanguageLevel languageLevel, diff --git a/java/java-psi-api/src/com/intellij/psi/PsiClassType.java b/java/java-psi-api/src/com/intellij/psi/PsiClassType.java index 5906e1d3c7c8..4c11523f2c46 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiClassType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiClassType.java @@ -55,6 +55,12 @@ public abstract class PsiClassType extends PsiType { myLanguageLevel = languageLevel; } + @NotNull + @Override + public PsiClassType annotate(@NotNull TypeAnnotationProvider provider) { + return (PsiClassType)super.annotate(provider); + } + /** * Resolves the class reference and returns the resulting class. * diff --git a/java/java-psi-api/src/com/intellij/psi/PsiElementFactory.java b/java/java-psi-api/src/com/intellij/psi/PsiElementFactory.java index 41ac72898245..404a39672972 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiElementFactory.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiElementFactory.java @@ -178,12 +178,6 @@ public interface PsiElementFactory extends PsiJavaParserFacade, JVMElementFactor @Override @NotNull PsiClassType createType(@NotNull PsiClass resolve, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel languageLevel); - @Override - @NotNull PsiClassType createType(@NotNull PsiClass resolve, - @NotNull PsiSubstitutor substitutor, - @Nullable LanguageLevel languageLevel, - @NotNull PsiAnnotation[] annotations); - /** * Creates a class type for the specified reference pointing to a class. * diff --git a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java index d7105defd1a2..0738462ee21c 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiEllipsisType.java @@ -41,7 +41,8 @@ public class PsiEllipsisType extends PsiArrayType { return provider == getAnnotationProvider() ? this : new PsiEllipsisType(getComponentType(), provider); } - @NotNull + /** @deprecated use {@link #annotate(TypeAnnotationProvider)} (to be removed in IDEA 18) */ + @SuppressWarnings("unused") public static PsiType createEllipsis(@NotNull PsiType componentType, @NotNull PsiAnnotation[] annotations) { return new PsiEllipsisType(componentType, annotations); } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiJavaParserFacade.java b/java/java-psi-api/src/com/intellij/psi/PsiJavaParserFacade.java index 70d7d3f46bd3..64fe93db80d4 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiJavaParserFacade.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiJavaParserFacade.java @@ -235,11 +235,14 @@ public interface PsiJavaParserFacade { /** * Creates a Java type from the specified text. * - * @param text the text of the type to create (a primitive type keyword). - * @param annotations array (possible empty) of annotations to annotate the created type. + * @param text the text of the type to create (a primitive type keyword). * @return the created type instance. * @throws IncorrectOperationException if some of the parameters are not valid. */ @NotNull + PsiType createPrimitiveTypeFromText(@NotNull String text) throws IncorrectOperationException; + + /** @deprecated use {@link PsiType#annotate(TypeAnnotationProvider)} (to be removed in IDEA 18) */ + @SuppressWarnings("unused") PsiType createPrimitiveType(@NotNull String text, @NotNull PsiAnnotation[] annotations) throws IncorrectOperationException; } \ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java index 5ce28619f7fb..1862c29a916c 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiPrimitiveType.java @@ -125,19 +125,18 @@ public class PsiPrimitiveType extends PsiType.Stub { @Nullable public static PsiPrimitiveType getUnboxedType(PsiType type) { if (!(type instanceof PsiClassType)) return null; + + assert type.isValid() : type; LanguageLevel languageLevel = ((PsiClassType)type).getLanguageLevel(); if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) return null; - assert type.isValid() : type; PsiClass psiClass = ((PsiClassType)type).resolve(); if (psiClass == null) return null; PsiPrimitiveType unboxed = ourQNameToUnboxed.get(psiClass.getQualifiedName()); - PsiAnnotation[] annotations = type.getAnnotations(); - if (unboxed != null && annotations.length > 0) { - unboxed = new PsiPrimitiveType(unboxed.myName, annotations); - } - return unboxed; + if (unboxed == null) return null; + + return unboxed.annotate(type.getAnnotationProvider()); } public String getBoxedTypeName() { @@ -152,31 +151,30 @@ public class PsiPrimitiveType extends PsiType.Stub { * it was not possible to resolve the reference to the class. */ @Nullable - public PsiClassType getBoxedType(PsiElement context) { + public PsiClassType getBoxedType(@NotNull PsiElement context) { PsiFile file = context.getContainingFile(); LanguageLevel languageLevel = PsiUtil.getLanguageLevel(file); if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_5)) return null; String boxedQName = getBoxedTypeName(); - //[ven]previous call returns null for NULL, VOID if (boxedQName == null) return null; + JavaPsiFacade facade = JavaPsiFacade.getInstance(file.getProject()); PsiClass aClass = facade.findClass(boxedQName, file.getResolveScope()); if (aClass == null) return null; PsiElementFactory factory = facade.getElementFactory(); - return factory.createType(aClass, PsiSubstitutor.EMPTY, languageLevel, getAnnotations()); + return factory.createType(aClass, PsiSubstitutor.EMPTY, languageLevel).annotate(getAnnotationProvider()); } @Nullable - public PsiClassType getBoxedType(final PsiManager manager, final GlobalSearchScope resolveScope) { - final String boxedQName = getBoxedTypeName(); - - //[ven]previous call returns null for NULL, VOID + public PsiClassType getBoxedType(@NotNull PsiManager manager, @NotNull GlobalSearchScope resolveScope) { + String boxedQName = getBoxedTypeName(); if (boxedQName == null) return null; - final PsiClass aClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(boxedQName, resolveScope); + PsiClass aClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(boxedQName, resolveScope); if (aClass == null) return null; + return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(aClass); } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiType.java b/java/java-psi-api/src/com/intellij/psi/PsiType.java index 2b8f63b4ddbc..6220ffd8cba1 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiType.java @@ -56,13 +56,7 @@ public abstract class PsiType implements PsiAnnotationOwner { * Constructs a PsiType with given annotations */ protected PsiType(@NotNull final PsiAnnotation[] annotations) { - this(annotations.length == 0 ? TypeAnnotationProvider.EMPTY : new TypeAnnotationProvider() { - @NotNull - @Override - public PsiAnnotation[] getAnnotations() { - return annotations; - } - }); + this(TypeAnnotationProvider.Static.create(annotations)); } /** @@ -85,10 +79,8 @@ public abstract class PsiType implements PsiAnnotationOwner { return new PsiArrayType(this); } - /** - * Creates array type with this type as a component. - */ - @NotNull + /** @deprecated use {@link #annotate(TypeAnnotationProvider)} (to be removed in IDEA 18) */ + @SuppressWarnings("unused") public PsiArrayType createArrayType(@NotNull PsiAnnotation... annotations) { return new PsiArrayType(this, annotations); } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java index 5ed01f39b4a8..263f02029ce4 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiWildcardType.java @@ -75,15 +75,10 @@ public class PsiWildcardType extends PsiType.Stub { return new PsiWildcardType(manager, false, bound); } - @NotNull + /** @deprecated use {@link #annotate(TypeAnnotationProvider)} (to be removed in IDEA 18) */ + @SuppressWarnings("unused") public PsiWildcardType annotate(@NotNull final PsiAnnotation[] annotations) { - return annotations.length == 0 ? this : new PsiWildcardType(this, new TypeAnnotationProvider() { - @NotNull - @Override - public PsiAnnotation[] getAnnotations() { - return annotations; - } - }); + return annotations.length == 0 ? this : new PsiWildcardType(this, TypeAnnotationProvider.Static.create(annotations)); } @NotNull diff --git a/java/java-psi-api/src/com/intellij/psi/TypeAnnotationProvider.java b/java/java-psi-api/src/com/intellij/psi/TypeAnnotationProvider.java index 8184778ee46c..05600cffde2f 100644 --- a/java/java-psi-api/src/com/intellij/psi/TypeAnnotationProvider.java +++ b/java/java-psi-api/src/com/intellij/psi/TypeAnnotationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -36,4 +36,24 @@ public interface TypeAnnotationProvider { @NotNull PsiAnnotation[] getAnnotations(); -} + + + class Static implements TypeAnnotationProvider { + private final PsiAnnotation[] myAnnotations; + + private Static(PsiAnnotation[] annotations) { + myAnnotations = annotations; + } + + @NotNull + @Override + public PsiAnnotation[] getAnnotations() { + return myAnnotations; + } + + @NotNull + public static TypeAnnotationProvider create(@NotNull PsiAnnotation[] annotations) { + return annotations.length == 0 ? EMPTY : new Static(annotations); + } + } +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java index 956490c77384..121ba9dbc33b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -383,13 +383,18 @@ public class PsiJavaParserFacadeImpl implements PsiJavaParserFacade { } @NotNull - @Override - public PsiType createPrimitiveType(@NotNull final String text, @NotNull final PsiAnnotation[] annotations) throws IncorrectOperationException { - final PsiPrimitiveType primitiveType = getPrimitiveType(text); + public PsiType createPrimitiveTypeFromText(@NotNull String text) throws IncorrectOperationException { + PsiPrimitiveType primitiveType = getPrimitiveType(text); if (primitiveType == null) { throw new IncorrectOperationException("Incorrect primitive type '" + text + "'"); } - return annotations.length == 0 ? primitiveType : new PsiPrimitiveType(text, annotations); + return primitiveType; + } + + @NotNull + @Override + public PsiType createPrimitiveType(@NotNull String text, @NotNull PsiAnnotation[] annotations) throws IncorrectOperationException { + return createPrimitiveTypeFromText(text).annotate(TypeAnnotationProvider.Static.create(annotations)); } public static PsiPrimitiveType getPrimitiveType(final String text) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java index 18ff2d110ad9..07fcb8023c55 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -48,7 +48,7 @@ public class JavaSharedImplUtil { List allAnnotations = collectAnnotations(anchor, stopAt); if (allAnnotations == null) return null; for (PsiAnnotation[] annotations : allAnnotations) { - type = type.createArrayType(annotations); + type = type.createArrayType().annotate(TypeAnnotationProvider.Static.create(annotations)); } return type; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiNewExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiNewExpressionImpl.java index 7862a7381011..f093215ee502 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiNewExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiNewExpressionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -73,20 +73,22 @@ public class PsiNewExpressionImpl extends ExpressionPsiElement implements PsiNew else if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(elementType)) { assert type == null : this; PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); - type = factory.createPrimitiveType(child.getText(), ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true)); + PsiAnnotation[] copy = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true); + type = factory.createPrimitiveTypeFromText(child.getText()).annotate(TypeAnnotationProvider.Static.create(copy)); if (stop) return type; } else if (elementType == JavaTokenType.LBRACKET) { assert type != null : this; - type = type.createArrayType(ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true)); + PsiAnnotation[] copy = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true); + type = type.createArrayType().annotate(TypeAnnotationProvider.Static.create(copy)); if (stop) return type; } else if (elementType == JavaElementType.ANONYMOUS_CLASS) { PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); PsiClass aClass = (PsiClass)child.getPsi(); PsiSubstitutor substitutor = aClass instanceof PsiTypeParameter ? PsiSubstitutor.EMPTY : factory.createRawSubstitutor(aClass); - type = factory.createType(aClass, substitutor, PsiUtil.getLanguageLevel(aClass), - ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true)); + PsiAnnotation[] copy = ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true); + type = factory.createType(aClass, substitutor, PsiUtil.getLanguageLevel(aClass)).annotate(TypeAnnotationProvider.Static.create(copy)); if (stop) return type; } } diff --git a/java/java-psi-impl/src/com/intellij/refactoring/util/CanonicalTypes.java b/java/java-psi-impl/src/com/intellij/refactoring/util/CanonicalTypes.java index 056020a814fe..99c1dad3c89c 100644 --- a/java/java-psi-impl/src/com/intellij/refactoring/util/CanonicalTypes.java +++ b/java/java-psi-impl/src/com/intellij/refactoring/util/CanonicalTypes.java @@ -50,10 +50,10 @@ public class CanonicalTypes { } private abstract static class AnnotatedType extends Type { - protected final PsiAnnotation[] myAnnotations; + protected final TypeAnnotationProvider myProvider; - protected AnnotatedType(@NotNull PsiAnnotation[] annotations) { - myAnnotations = annotations; + public AnnotatedType(@NotNull TypeAnnotationProvider provider) { + myProvider = TypeAnnotationProvider.Static.create(provider.getAnnotations()); } } @@ -61,14 +61,14 @@ public class CanonicalTypes { private final PsiPrimitiveType myType; private Primitive(@NotNull PsiPrimitiveType type) { - super(type.getAnnotations()); + super(type.getAnnotationProvider()); myType = type; } @NotNull @Override public PsiType getType(PsiElement context, PsiManager manager) { - return myAnnotations.length == 0 ? myType : new PsiPrimitiveType(myType.getCanonicalText(false), myAnnotations); + return myType.annotate(myProvider); } @Override @@ -81,14 +81,14 @@ public class CanonicalTypes { protected final Type myComponentType; private Array(@NotNull PsiType original, @NotNull Type componentType) { - super(original.getAnnotations()); + super(original.getAnnotationProvider()); myComponentType = componentType; } @NotNull @Override public PsiType getType(PsiElement context, PsiManager manager) throws IncorrectOperationException { - return myComponentType.getType(context, manager).createArrayType(myAnnotations); + return myComponentType.getType(context, manager).createArrayType().annotate(myProvider); } @Override @@ -115,7 +115,7 @@ public class CanonicalTypes { @NotNull @Override public PsiType getType(PsiElement context, PsiManager manager) throws IncorrectOperationException { - return new PsiEllipsisType(myComponentType.getType(context, manager), myAnnotations); + return new PsiEllipsisType(myComponentType.getType(context, manager)).annotate(myProvider); } @Override @@ -129,7 +129,7 @@ public class CanonicalTypes { private final Type myBound; private WildcardType(@NotNull PsiType original, boolean isExtending, @Nullable Type bound) { - super(original.getAnnotations()); + super(original.getAnnotationProvider()); myIsExtending = isExtending; myBound = bound; } @@ -147,7 +147,7 @@ public class CanonicalTypes { else { type = PsiWildcardType.createSuper(manager, myBound.getType(context, manager)); } - return type.annotate(myAnnotations); + return type.annotate(myProvider); } @Override @@ -205,7 +205,7 @@ public class CanonicalTypes { private final Map mySubstitutor; private ClassType(@NotNull PsiType original, @NotNull String classQName, @NotNull Map substitutor) { - super(original.getAnnotations()); + super(original.getAnnotationProvider()); myPresentableText = original.getPresentableText(); myClassQName = classQName; mySubstitutor = substitutor; @@ -227,7 +227,7 @@ public class CanonicalTypes { Type substitute = mySubstitutor.get(typeParameter.getName()); substitutionMap.put(typeParameter, substitute != null ? substitute.getType(context, manager) : null); } - return factory.createType(aClass, factory.createSubstitutor(substitutionMap), null, myAnnotations); + return factory.createType(aClass, factory.createSubstitutor(substitutionMap), null).annotate(myProvider); } @Override diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ConvertToVarargsMethodFix.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ConvertToVarargsMethodFix.java index 2c0212fafc2f..384b63aa7545 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ConvertToVarargsMethodFix.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/ConvertToVarargsMethodFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -20,8 +20,6 @@ import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.InspectionGadgetsFix; import org.jetbrains.annotations.NotNull; @@ -90,7 +88,7 @@ public class ConvertToVarargsMethodFix extends InspectionGadgetsFix { final PsiArrayType arrayType = (PsiArrayType)type; final PsiType componentType = arrayType.getComponentType(); final PsiElementFactory factory = JavaPsiFacade.getElementFactory(method.getProject()); - final PsiType ellipsisType = PsiEllipsisType.createEllipsis(componentType, type.getAnnotations()); + final PsiType ellipsisType = new PsiEllipsisType(componentType, TypeAnnotationProvider.Static.create(type.getAnnotations())); final PsiTypeElement newTypeElement = factory.createTypeElement(ellipsisType); final PsiTypeElement typeElement = lastParameter.getTypeElement(); if (typeElement != null) { diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/varargs/MakeMethodVarargsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/varargs/MakeMethodVarargsIntention.java index 2b0617c673a6..24881155584b 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/varargs/MakeMethodVarargsIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/varargs/MakeMethodVarargsIntention.java @@ -48,7 +48,7 @@ public class MakeMethodVarargsIntention extends Intention { final PsiElementFactory factory = JavaPsiFacade.getInstance(element.getProject()).getElementFactory(); final PsiTypeElement typeElement = lastParameter.getTypeElement(); LOG.assertTrue(typeElement != null); - final PsiType ellipsisType = PsiEllipsisType.createEllipsis(((PsiArrayType)type).getComponentType(), type.getAnnotations()); + final PsiType ellipsisType = new PsiEllipsisType(((PsiArrayType)type).getComponentType(), TypeAnnotationProvider.Static.create(type.getAnnotations())); typeElement.replace(factory.createTypeElement(ellipsisType)); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java index 2a2db5ecaeb9..33003a77b739 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -1131,6 +1131,7 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory { return JavaPsiFacade.getElementFactory(myProject).createType(resolve, substitutor, languageLevel); } + @SuppressWarnings("deprecation") @NotNull @Override public PsiClassType createType(@NotNull PsiClass resolve, From b9ec9bb6a1248cf8d276390fb6dca72081593f13 Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 23 Apr 2016 10:13:18 +0200 Subject: [PATCH 54/65] don't lose submitted transactions --- .../openapi/application/TransactionGuardImpl.java | 12 +++--------- .../intellij/application/TransactionTest.groovy | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java index 184ed367e9bb..237df5160ca3 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java @@ -60,6 +60,7 @@ public class TransactionGuardImpl extends TransactionGuard { public void finish() { Queue queue = getQueue(prevTransaction); queue.addAll(myCurrentTransaction.myQueue); + myCurrentTransaction.myQueue = queue; if (!queue.isEmpty()) { pollQueueLater(); } @@ -72,14 +73,7 @@ public class TransactionGuardImpl extends TransactionGuard { @NotNull private Queue getQueue(@Nullable TransactionIdImpl transaction) { - if (transaction == null) { - return myQueue; - } - if (myCurrentTransaction != null && transaction.myStartCounter > myCurrentTransaction.myStartCounter) { - // transaction is finished already, it makes no sense to add to its queue - return myCurrentTransaction.myQueue; - } - return transaction.myQueue; + return transaction == null ? myQueue : transaction.myQueue; } private void pollQueueLater() { @@ -304,7 +298,7 @@ public class TransactionGuardImpl extends TransactionGuard { private static class TransactionIdImpl implements TransactionId { private static final AtomicLong ourTransactionCounter = new AtomicLong(); final long myStartCounter = ourTransactionCounter.getAndIncrement(); - final Queue myQueue = new LinkedBlockingQueue(); + Queue myQueue = new LinkedBlockingQueue(); @Override public String toString() { diff --git a/platform/platform-tests/testSrc/com/intellij/application/TransactionTest.groovy b/platform/platform-tests/testSrc/com/intellij/application/TransactionTest.groovy index b810c6eacc27..1b68f58338bd 100644 --- a/platform/platform-tests/testSrc/com/intellij/application/TransactionTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/application/TransactionTest.groovy @@ -216,4 +216,18 @@ class TransactionTest extends LightPlatformTestCase { assert log == ['1', '2', '3', '4', '5'] } + public void "test don't add transaction to outdated queue"() { + TransactionGuard.submitTransaction testRootDisposable, { + log << '1' + guard.submitTransactionLater testRootDisposable, { log << '3' } + log << '2' + } + TransactionGuard.submitTransaction testRootDisposable, { + UIUtil.dispatchAllInvocationEvents() + assert log == ['1', '2'] + } + UIUtil.dispatchAllInvocationEvents() + assert log == ['1', '2', '3'] + } + } From e9801d81e3581f17e6ddda0c6731ae3f2e605cc8 Mon Sep 17 00:00:00 2001 From: peter Date: Sat, 23 Apr 2016 18:59:51 +0200 Subject: [PATCH 55/65] overriding method search: remove costly and completely useless check --- .../psi/impl/search/JavaAllOverridingMethodsSearcher.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaAllOverridingMethodsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaAllOverridingMethodsSearcher.java index 4a8655419bd3..b24655b12bde 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaAllOverridingMethodsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaAllOverridingMethodsSearcher.java @@ -59,8 +59,6 @@ public class JavaAllOverridingMethodsSearcher implements QueryExecutor Date: Sat, 23 Apr 2016 19:03:02 +0200 Subject: [PATCH 56/65] PsiAugmentProvider: ask for dumbness once --- .../src/com/intellij/psi/augment/PsiAugmentProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java b/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java index d2fc5de10594..532dda378f07 100644 --- a/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java +++ b/java/java-psi-api/src/com/intellij/psi/augment/PsiAugmentProvider.java @@ -142,8 +142,9 @@ public abstract class PsiAugmentProvider { } private static void forEach(Project project, Processor processor) { + boolean dumb = DumbService.isDumb(project); for (PsiAugmentProvider provider : Extensions.getExtensions(EP_NAME)) { - if (!DumbService.isDumb(project) || DumbService.isDumbAware(provider)) { + if (!dumb || DumbService.isDumbAware(provider)) { try { boolean goOn = processor.process(provider); if (!goOn) break; From 6048ecb6d18ad561fd60e5d219181984a96c552b Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Sun, 24 Apr 2016 17:50:44 +0100 Subject: [PATCH 57/65] simplify and remove yellow code --- .../platform-impl/src/com/intellij/ide/IdeEventQueue.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java index b41d5f7292e5..8e51040024b8 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -787,7 +787,7 @@ public class IdeEventQueue extends EventQueue { if (e instanceof WindowEvent) { final WindowEvent we = (WindowEvent)e; - ApplicationActivationStateManager.get().updateState(we); + ApplicationActivationStateManager.updateState(we); storeLastFocusedComponent(we); } From de6fcdbd8a562c006f6ee16812a338e823aeb88d Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 25 Apr 2016 00:18:56 +0200 Subject: [PATCH 58/65] Fix env var name --- python/setup-test-environment/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/setup-test-environment/build.gradle b/python/setup-test-environment/build.gradle index c4e4a9639afc..c32115b7c154 100644 --- a/python/setup-test-environment/build.gradle +++ b/python/setup-test-environment/build.gradle @@ -7,7 +7,7 @@ plugins { envs { bootstrapDirectory = new File(System.getenv().getOrDefault("PYCHARM_PYTHONS", new File(buildDir, 'pythons').path)) - envsDirectory = new File(System.getenv().getOrDefault("PYCHARM_PYTHON_ENVS", new File(buildDir, 'envs').path)) + envsDirectory = new File(System.getenv().getOrDefault("PYCHARM_PYTHON_VIRTUAL_ENVS", new File(buildDir, 'envs').path)) minicondaVersion = 'latest' packages = ["pip", "setuptools"] _64Bits = true From d9288e4b42d29a2e34a78def8b9b2756dd856db3 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sat, 23 Apr 2016 20:43:41 +0200 Subject: [PATCH 59/65] SSR: find parameterized method calls (IDEA-154740) --- .../impl/matcher/JavaMatchingVisitor.java | 66 +++++++++++++++---- .../StructuralSearchTest.java | 19 ++++++ 2 files changed, 74 insertions(+), 11 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index e58dfe17f109..477987466086 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -1041,50 +1041,94 @@ public class JavaMatchingVisitor extends JavaElementVisitor { final PsiReferenceExpression mcallRef1 = mcall.getMethodExpression(); final PsiReferenceExpression mcallRef2 = mcall2.getMethodExpression(); - final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(mcallRef1.getReferenceNameElement()); + final PsiElement patternMethodName = mcallRef1.getReferenceNameElement(); + final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(patternMethodName); - if (!myMatchingVisitor.matchText(mcallRef1.getReferenceNameElement(), mcallRef2.getReferenceNameElement()) && !isTypedVar) { + if (!isTypedVar && !myMatchingVisitor.matchText(patternMethodName, mcallRef2.getReferenceNameElement())) { myMatchingVisitor.setResult(false); return; } - final PsiExpression qualifier = mcallRef1.getQualifierExpression(); - final PsiExpression elementQualifier = mcallRef2.getQualifierExpression(); - if (qualifier != null) { + final PsiExpression patternQualifier = mcallRef1.getQualifierExpression(); + final PsiExpression matchedQualifier = mcallRef2.getQualifierExpression(); + if (patternQualifier != null) { - if (elementQualifier != null) { - myMatchingVisitor.setResult(myMatchingVisitor.match(qualifier, elementQualifier)); + if (matchedQualifier != null) { + myMatchingVisitor.setResult(myMatchingVisitor.match(patternQualifier, matchedQualifier)); if (!myMatchingVisitor.getResult()) return; } else { final PsiMethod method = mcall2.resolveMethod(); if (method != null) { - if (qualifier instanceof PsiThisExpression) { + if (patternQualifier instanceof PsiThisExpression) { myMatchingVisitor.setResult(!method.hasModifierProperty(PsiModifier.STATIC)); return; } } - final MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(qualifier); + final MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(patternQualifier); matchImplicitQualifier(handler, method, myMatchingVisitor.getMatchContext()); if (!myMatchingVisitor.getResult()) { return; } } } - else if (elementQualifier != null) { + else if (matchedQualifier != null) { myMatchingVisitor.setResult(false); return; } myMatchingVisitor.setResult(myMatchingVisitor.matchSons(mcall.getArgumentList(), mcall2.getArgumentList())); + if (myMatchingVisitor.getResult()) { + myMatchingVisitor.setResult(matchTypeParameters(mcallRef1, mcallRef2)); + } + if (myMatchingVisitor.getResult() && isTypedVar) { boolean res = myMatchingVisitor.getResult(); - res &= myMatchingVisitor.handleTypedElement(mcallRef1.getReferenceNameElement(), mcallRef2.getReferenceNameElement()); + res &= myMatchingVisitor.handleTypedElement(patternMethodName, mcallRef2.getReferenceNameElement()); myMatchingVisitor.setResult(res); } } + private boolean matchTypeParameters(PsiJavaCodeReferenceElement mcallRef1, PsiJavaCodeReferenceElement mcallRef2) { + final PsiReferenceParameterList patternParameterList = mcallRef1.getParameterList(); + if (patternParameterList == null) { + return true; + } + final PsiTypeElement[] patternTypeElements = patternParameterList.getTypeParameterElements(); + if (patternTypeElements.length == 0) { + return true; + } + PsiReferenceParameterList matchedParameterList = mcallRef2.getParameterList(); + if (matchedParameterList == null) { + return false; + } + if (matchedParameterList.getFirstChild() == null) { // check inferred type parameters + final JavaResolveResult resolveResult = mcallRef2.advancedResolve(false); + final PsiMethod targetMethod = (PsiMethod)resolveResult.getElement(); + if (targetMethod == null) { + return false; + } + final PsiTypeParameterList typeParameterList = targetMethod.getTypeParameterList(); + if (typeParameterList == null) { + return false; + } + final PsiTypeParameter[] typeParameters = typeParameterList.getTypeParameters(); + final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + matchedParameterList = (PsiReferenceParameterList)matchedParameterList.copy(); + for (final PsiTypeParameter typeParameter : typeParameters) { + final PsiType type = substitutor.substitute(typeParameter); + if (type == null) { + return false; + } + final PsiTypeElement matchedTypeElement = JavaPsiFacade.getElementFactory(mcallRef1.getProject()).createTypeElement(type); + matchedParameterList.add(matchedTypeElement); + } + } + final PsiTypeElement[] matchedTypeElements = matchedParameterList.getTypeParameterElements(); + return myMatchingVisitor.matchSequentially(patternTypeElements, matchedTypeElements); + } + @Override public void visitExpressionStatement(final PsiExpressionStatement expr) { final PsiElement other = myMatchingVisitor.getElement(); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 73a8eff7fa73..1d33cca4914b 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -3443,4 +3443,23 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("any variable can be final", 3, findMatchesCount(source, "@Modifier(\"final\") '_T '_a;")); assertEquals("parameters and local variables are not instance fields", 1, findMatchesCount(source, "@Modifier(\"Instance\") '_T '_a;")); } + + public void testFindParameterizedMethodCalls() { + String source = "interface Foo {" + + " T bar();" + + " void bar2(S, T);" + + "}" + + "class X {" + + " void x(Foo foo) {" + + " foo.bar();" + + " foo.bar();" + + " String s = foo.bar();" + + " foo.bar2(1, 2);" + + " }" + + "}"; + assertEquals("find parameterized method calls 1", 1, findMatchesCount(source, "foo.bar()")); + assertEquals("find parameterized method calls 2", 2, findMatchesCount(source, "foo.bar()")); + assertEquals("find parameterized method calls 3", 3, findMatchesCount(source, "'_a.<'_b>'_c('_d*)")); + assertEquals("find parameterized method calls 4", 4, findMatchesCount(source, "'_a.<'_b+>'_c('_d*)")); + } } From 1ce6f8d2fa052d8c49cdc41b83aa9b45e2771aaf Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Mon, 25 Apr 2016 10:54:43 +0200 Subject: [PATCH 60/65] introduce param object: pass substitution around which won't be available after method signature is changed (IDEA-154208) --- .../changeSignature/JavaChangeInfoImpl.java | 2 +- .../JavaChangeSignatureUsageProcessor.java | 25 +++++++------- .../changeSignature/JavaParameterInfo.java | 3 +- ...troduceParameterObjectClassDescriptor.java | 12 ++----- .../JavaIntroduceParameterObjectDelegate.java | 34 ++++++++++++++----- .../after/Param.java | 13 +++++++ .../after/Test.java | 11 ++++++ .../before/Test.java | 12 +++++++ .../IntroduceParameterObjectTest.java | 14 ++++++++ .../changeSignature/ChangeInfo.java | 9 ----- .../changeSignature/ParameterInfo.java | 2 +- .../IntroduceParameterObjectDelegate.java | 4 ++- .../changeSignature/GrChangeInfoImpl.java | 2 +- .../GrChangeSignatureUsageProcessor.java | 7 ++-- ...roovyIntroduceParameterObjectDelegate.java | 7 ++-- 15 files changed, 107 insertions(+), 50 deletions(-) create mode 100644 java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/after/Param.java create mode 100644 java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/after/Test.java create mode 100644 java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/before/Test.java diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java index 46021270acde..cb1b753898f4 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java @@ -309,7 +309,7 @@ public class JavaChangeInfoImpl extends UserDataHolderBase implements JavaChange @Nullable public PsiExpression getValue(int i, PsiCallExpression expr) throws IncorrectOperationException { if (defaultValues[i] != null) return defaultValues[i]; - final PsiElement valueAtCallSite = newParms[i].getActualValue(expr); + final PsiElement valueAtCallSite = newParms[i].getActualValue(expr, PsiSubstitutor.EMPTY); return valueAtCallSite instanceof PsiExpression ? (PsiExpression)valueAtCallSite : null; } diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java index 1cdde7c66a3f..5d9eb7b102b1 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java @@ -410,7 +410,8 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr //This methods works equally well for primary usages as well as for propagated callers' usages private static void fixActualArgumentsList(PsiExpressionList list, JavaChangeInfo changeInfo, - boolean toInsertDefaultValue, PsiSubstitutor substitutor) throws IncorrectOperationException { + boolean toInsertDefaultValue, + PsiSubstitutor substitutor) throws IncorrectOperationException { final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory(); if (changeInfo.isParameterSetOrOrderChanged()) { if (changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl)changeInfo).isPropagationEnabled) { @@ -418,7 +419,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr for (ParameterInfoImpl info : createdParmsInfo) { PsiExpression newArg; if (toInsertDefaultValue) { - newArg = createDefaultValue(changeInfo, factory, info, list); + newArg = createDefaultValue(changeInfo, factory, info, list, substitutor); } else { newArg = factory.createExpressionFromText(info.getName(), list); @@ -486,12 +487,12 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr continue; } } - newArgs[i] = createActualArgument(changeInfo, list, newParms[i], toInsertDefaultValue, args); + newArgs[i] = createActualArgument(changeInfo, list, newParms[i], toInsertDefaultValue, args, substitutor); } if (changeInfo.isArrayToVarargs()) { if (newVarargInitializers == null) { newArgs[newNonVarargCount] = - createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args); + createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args, substitutor); } else { System.arraycopy(newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length); @@ -503,7 +504,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr for (int i = newNonVarargCount; i < newArgsLength; i++){ final int oldIndex = newParms[newNonVarargCount].getOldIndex(); if (oldIndex >= 0 && oldIndex != nonVarargCount) { - newArgs[i] = createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args); + newArgs[i] = createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args, substitutor); } else { System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount); break; @@ -526,7 +527,8 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr final PsiExpressionList list, final JavaParameterInfo info, final boolean toInsertDefaultValue, - final PsiExpression[] args) throws IncorrectOperationException { + final PsiExpression[] args, + PsiSubstitutor substitutor) throws IncorrectOperationException { final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory(); final int index = info.getOldIndex(); if (index >= 0 && index < args.length) { @@ -534,7 +536,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr } else { if (toInsertDefaultValue) { - return createDefaultValue(changeInfo, factory, info, list); + return createDefaultValue(changeInfo, factory, info, list, substitutor); } else { return factory.createExpressionFromText(info.getName(), list); @@ -546,7 +548,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr private static PsiExpression createDefaultValue(JavaChangeInfo changeInfo, final PsiElementFactory factory, final JavaParameterInfo info, - final PsiExpressionList list) + final PsiExpressionList list, PsiSubstitutor substitutor) throws IncorrectOperationException { if (info.isUseAnySingleVariable()) { final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper(); @@ -593,7 +595,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr } final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class); final String defaultValue = info.getDefaultValue(); - return callExpression != null ? (PsiExpression)info.getActualValue(callExpression) + return callExpression != null ? (PsiExpression)info.getActualValue(callExpression, substitutor) : !StringUtil.isEmpty(defaultValue) ? factory.createExpressionFromText(defaultValue, list) : null; } @@ -706,14 +708,13 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr private static void addDelegateArguments(JavaChangeInfo changeInfo, PsiElementFactory factory, final PsiCallExpression callExpression) throws IncorrectOperationException { final JavaParameterInfo[] newParms = changeInfo.getNewParameters(); final String[] oldParameterNames = changeInfo.getOldParameterNames(); - for (int i = 0; i < newParms.length; i++) { - JavaParameterInfo newParm = newParms[i]; + for (JavaParameterInfo newParm : newParms) { final PsiExpression actualArg; if (newParm.getOldIndex() >= 0) { actualArg = factory.createExpressionFromText(oldParameterNames[newParm.getOldIndex()], callExpression); } else { - actualArg = (PsiExpression)changeInfo.getActualValue(i, callExpression); + actualArg = (PsiExpression)newParm.getActualValue(callExpression, PsiSubstitutor.EMPTY); } final PsiExpressionList argumentList = callExpression.getArgumentList(); if (actualArg != null && argumentList != null) { diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaParameterInfo.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaParameterInfo.java index bc5740508172..b2dd2e8f0dbe 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaParameterInfo.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaParameterInfo.java @@ -34,8 +34,7 @@ public interface JavaParameterInfo extends ParameterInfo { PsiExpression getValue(PsiCallExpression callExpression); @Nullable - @Override - default PsiElement getActualValue(PsiElement callExpression) { + default PsiElement getActualValue(PsiElement callExpression, Object substitutor) { return callExpression instanceof PsiCallExpression ? getValue((PsiCallExpression)callExpression) : null; } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectClassDescriptor.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectClassDescriptor.java index f19c14328fad..ef2387ea2f8f 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectClassDescriptor.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectClassDescriptor.java @@ -32,20 +32,19 @@ import com.intellij.refactoring.MoveDestination; import com.intellij.refactoring.changeSignature.ParameterInfoImpl; import com.intellij.refactoring.introduceParameterObject.IntroduceParameterObjectClassDescriptor; import com.intellij.refactoring.introduceParameterObject.IntroduceParameterObjectDelegate; -import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; public class JavaIntroduceParameterObjectClassDescriptor extends IntroduceParameterObjectClassDescriptor { private static final Logger LOG = Logger.getInstance("#" + JavaIntroduceParameterObjectClassDescriptor.class.getName()); - private final Set myTypeParameters = new HashSet<>(); + private final Set myTypeParameters = new LinkedHashSet<>(); private final Map myExistingClassProperties = new HashMap<>(); private final MoveDestination myMoveDestination; @@ -106,12 +105,7 @@ public class JavaIntroduceParameterObjectClassDescriptor extends IntroduceParame public String createFakeClassTypeText() { String text = StringUtil.getQualifiedName(getPackageName(), getClassName()); if (!myTypeParameters.isEmpty()) { - text += "<" + StringUtil.join(myTypeParameters, new Function() { - @Override - public String fun(PsiTypeParameter parameter) { - return parameter.getName(); - } - }, ", ") + ">"; + text += "<" + StringUtil.join(myTypeParameters, PsiNamedElement::getName, ", ") + ">"; } return text; } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectDelegate.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectDelegate.java index 713afe952eb5..09ce3b828eaf 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectDelegate.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/JavaIntroduceParameterObjectDelegate.java @@ -22,6 +22,7 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.impl.PsiDiamondTypeUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; @@ -42,6 +43,7 @@ import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -86,9 +88,9 @@ public class JavaIntroduceParameterObjectDelegate return new ParameterInfoImpl(-1, paramName, facade.getElementFactory().createTypeFromText(classTypeText, method), null) { @Nullable @Override - public PsiElement getActualValue(PsiElement exp) { + public PsiElement getActualValue(PsiElement exp, Object substitutor) { final IntroduceParameterObjectDelegate> delegate = findDelegate(exp); - return delegate != null ? delegate.createNewParameterInitializerAtCallSite(exp, descriptor, oldMethodParameters) : null; + return delegate != null ? delegate.createNewParameterInitializerAtCallSite(exp, descriptor, oldMethodParameters, substitutor) : null; } }; } @@ -96,7 +98,8 @@ public class JavaIntroduceParameterObjectDelegate @Override public PsiElement createNewParameterInitializerAtCallSite(PsiElement callExpression, IntroduceParameterObjectClassDescriptor descriptor, - List oldMethodParameters) { + List oldMethodParameters, + Object substitutor) { if (callExpression instanceof PsiCallExpression) { final PsiCallExpression expr = (PsiCallExpression)callExpression; final JavaPsiFacade facade = JavaPsiFacade.getInstance(expr.getProject()); @@ -109,16 +112,31 @@ public class JavaIntroduceParameterObjectDelegate final PsiExpression[] args = argumentList.getExpressions(); StringBuilder newExpression = new StringBuilder(); - final JavaResolveResult resolvant = expr.resolveMethodGenerics(); - final PsiSubstitutor substitutor = resolvant.getSubstitutor(); - newExpression.append("new ") - .append(JavaPsiFacade.getElementFactory(expr.getProject()).createType(existingClass, substitutor).getCanonicalText()); + newExpression.append("new ").append(existingClass.getQualifiedName()); + if (descriptor instanceof JavaIntroduceParameterObjectClassDescriptor) { + List types = new ArrayList<>(); + for (PsiTypeParameter parameter : ((JavaIntroduceParameterObjectClassDescriptor)descriptor).getTypeParameters()) { + PsiType type = ((PsiSubstitutor)substitutor).substitute(parameter); + if (type == null) { + types.clear(); + break; + } + types.add(type.getCanonicalText()); + } + if (!types.isEmpty()) { + newExpression.append("<").append(StringUtil.join(types, ", ")).append(">"); + } + } newExpression.append('('); newExpression.append(getMergedArgs(descriptor, oldMethodParameters, args)); newExpression.append(')'); - return JavaCodeStyleManager.getInstance(callExpression.getProject()) + PsiNewExpression newClassExpression = (PsiNewExpression)JavaCodeStyleManager.getInstance(callExpression.getProject()) .shortenClassReferences(facade.getElementFactory().createExpressionFromText(newExpression.toString(), expr)); + if (PsiDiamondTypeUtil.canChangeContextForDiamond(newClassExpression, newClassExpression.getType())) { + PsiDiamondTypeUtil.replaceExplicitWithDiamond(newClassExpression.getClassOrAnonymousClassReference().getParameterList()); + } + return newClassExpression; } return null; } diff --git a/java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/after/Param.java b/java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/after/Param.java new file mode 100644 index 000000000000..1bb40430e713 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/after/Param.java @@ -0,0 +1,13 @@ +import java.util.List; + +public class Param { + private final List y; + + public Param(List y) { + this.y = y; + } + + public List getY() { + return y; + } +} diff --git a/java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/after/Test.java b/java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/after/Test.java new file mode 100644 index 000000000000..68610f7ba8ee --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/after/Test.java @@ -0,0 +1,11 @@ +import java.util.List; + +public class Test { + public static String foo(Param param) { + return null; + } + + void bar(List list) { + System.out.println(foo(new Param<>(list))); + } +} diff --git a/java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/before/Test.java b/java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/before/Test.java new file mode 100644 index 000000000000..f13937986913 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceParameterObject/typeParametersWithSubstitution/before/Test.java @@ -0,0 +1,12 @@ +import java.util.Collection; +import java.util.List; + +public class Test { + public static String foo(List y) { + return null; + } + + void bar(List list) { + System.out.println(foo(list)); + } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterObjectTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterObjectTest.java index 1f82ad987ab0..c35b9fd93c79 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterObjectTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceParameterObjectTest.java @@ -22,7 +22,9 @@ package com.intellij.refactoring; import com.intellij.JavaTestUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.changeSignature.JavaMethodDescriptor; @@ -132,6 +134,18 @@ public class IntroduceParameterObjectTest extends MultiFileTestCase{ doTest(); } + public void testTypeParametersWithSubstitution() throws Exception { + final LanguageLevelProjectExtension projectExtension = LanguageLevelProjectExtension.getInstance(getProject()); + final LanguageLevel oldLevel = projectExtension.getLanguageLevel(); + try { + projectExtension.setLanguageLevel(LanguageLevel.HIGHEST); + doTest(); + } + finally { + projectExtension.setLanguageLevel(oldLevel); + } + } + public void testSameTypeAndVarargs() throws Exception { doTest(false, false, method -> { final PsiParameter[] parameters = method.getParameterList().getParameters(); diff --git a/platform/lang-api/src/com/intellij/refactoring/changeSignature/ChangeInfo.java b/platform/lang-api/src/com/intellij/refactoring/changeSignature/ChangeInfo.java index deee40749a0e..6e37873a3118 100644 --- a/platform/lang-api/src/com/intellij/refactoring/changeSignature/ChangeInfo.java +++ b/platform/lang-api/src/com/intellij/refactoring/changeSignature/ChangeInfo.java @@ -52,13 +52,4 @@ public interface ChangeInfo { String getNewName(); Language getLanguage(); - - /** - * For added parameters, return expression to be inserted as argument at the parameter position in callExpression. - * Based on parameter default value {@link ParameterInfo#getActualValue(PsiElement)} - */ - default PsiElement getActualValue(int i, PsiElement callExpression) { - final ParameterInfo[] parameters = getNewParameters(); - return i < parameters.length ? parameters[i].getActualValue(callExpression) : null; - } } diff --git a/platform/lang-api/src/com/intellij/refactoring/changeSignature/ParameterInfo.java b/platform/lang-api/src/com/intellij/refactoring/changeSignature/ParameterInfo.java index 2a9f07a8e736..61198c412b68 100644 --- a/platform/lang-api/src/com/intellij/refactoring/changeSignature/ParameterInfo.java +++ b/platform/lang-api/src/com/intellij/refactoring/changeSignature/ParameterInfo.java @@ -55,7 +55,7 @@ public interface ParameterInfo { * Could be overridden to provide values which depend on the call site */ @Nullable - default PsiElement getActualValue(PsiElement callExpression) { + default PsiElement getActualValue(PsiElement callExpression, Object substitutor) { return null; } diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduceParameterObject/IntroduceParameterObjectDelegate.java b/platform/lang-impl/src/com/intellij/refactoring/introduceParameterObject/IntroduceParameterObjectDelegate.java index e7c53c24066b..def9b138945c 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/introduceParameterObject/IntroduceParameterObjectDelegate.java +++ b/platform/lang-impl/src/com/intellij/refactoring/introduceParameterObject/IntroduceParameterObjectDelegate.java @@ -100,10 +100,12 @@ public abstract class IntroduceParameterObjectDelegate oldMethodParameters); + List oldMethodParameters, + Object substitutor); /** * Pass new parameter infos to the change info constructor which corresponds to the language of this delegate diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeInfoImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeInfoImpl.java index 63ac08423815..e8e1fe8f2d75 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeInfoImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeInfoImpl.java @@ -336,7 +336,7 @@ public class GrChangeInfoImpl implements JavaChangeInfo { @Override public PsiExpression getValue(int i, PsiCallExpression callExpression) { if (defaultValues[i] != null) return defaultValues[i]; - final PsiElement valueAtCallSite = parameters.get(i).getActualValue(callExpression); + final PsiElement valueAtCallSite = parameters.get(i).getActualValue(callExpression, PsiSubstitutor.EMPTY); return valueAtCallSite instanceof PsiExpression ? (PsiExpression)valueAtCallSite : null; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUsageProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUsageProcessor.java index 63e9e67d663f..312a53febdeb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUsageProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureUsageProcessor.java @@ -529,7 +529,7 @@ public class GrChangeSignatureUsageProcessor implements ChangeSignatureUsageProc argsToDelete.removeAll(map[index].args); } else { - values[i] = createDefaultValue(factory, changeInfo, parameter, argumentList); + values[i] = createDefaultValue(factory, changeInfo, parameter, argumentList, substitutor); } } @@ -640,7 +640,8 @@ public class GrChangeSignatureUsageProcessor implements ChangeSignatureUsageProc private static GrExpression createDefaultValue(GroovyPsiElementFactory factory, JavaChangeInfo changeInfo, JavaParameterInfo info, - final GrArgumentList list) { + final GrArgumentList list, + PsiSubstitutor substitutor) { if (info.isUseAnySingleVariable()) { final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper(); final PsiType type = info.getTypeWrapper().getType(changeInfo.getMethod(), list.getManager()); @@ -689,7 +690,7 @@ public class GrChangeSignatureUsageProcessor implements ChangeSignatureUsageProc } } - final PsiElement element = info.getActualValue(list.getParent()); + final PsiElement element = info.getActualValue(list.getParent(), substitutor); if (element instanceof GrExpression) { return (GrExpression)element; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduceParameterObject/GroovyIntroduceParameterObjectDelegate.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduceParameterObject/GroovyIntroduceParameterObjectDelegate.java index 63d8b3bdc52f..3985d2d2aa3f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduceParameterObject/GroovyIntroduceParameterObjectDelegate.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduceParameterObject/GroovyIntroduceParameterObjectDelegate.java @@ -76,10 +76,10 @@ public class GroovyIntroduceParameterObjectDelegate return new GrParameterInfo(descriptor.getClassName(), null, null, classType, -1, false) { @Nullable @Override - public PsiElement getActualValue(PsiElement callExpression) { + public PsiElement getActualValue(PsiElement callExpression, Object substitutor) { final IntroduceParameterObjectDelegate> delegate = findDelegate(callExpression); - return delegate != null ? delegate.createNewParameterInitializerAtCallSite(callExpression, descriptor, oldMethodParameters) : null; + return delegate != null ? delegate.createNewParameterInitializerAtCallSite(callExpression, descriptor, oldMethodParameters, substitutor) : null; } }; } @@ -87,7 +87,8 @@ public class GroovyIntroduceParameterObjectDelegate @Override public PsiElement createNewParameterInitializerAtCallSite(PsiElement callExpression, IntroduceParameterObjectClassDescriptor descriptor, - List oldMethodParameters) { + List oldMethodParameters, + Object substitutor) { if (callExpression instanceof GrCallExpression) { final GrArgumentList list = ((GrCallExpression)callExpression).getArgumentList(); if (list == null) { From c095654a368b142c98f05a813741c16779a52906 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 25 Apr 2016 11:03:58 +0200 Subject: [PATCH 61/65] remove unnecessary invokeLater from usage view rerun actions --- .../safeDelete/SafeDeleteProcessor.java | 29 ++++++++----------- .../plugins/xpathView/XPathEvalAction.java | 9 +----- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteProcessor.java index 41ca52e1b334..caad0352049c 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/safeDelete/SafeDeleteProcessor.java @@ -313,23 +313,18 @@ public class SafeDeleteProcessor extends BaseRefactoringProcessor { @Override public void run() { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - PsiDocumentManager.getInstance(myProject).commitAllDocuments(); - myUsageView.close(); - ArrayList elements = new ArrayList(); - for (SmartPsiElementPointer pointer : myPointers) { - final PsiElement element = pointer.getElement(); - if (element != null) { - elements.add(element); - } - } - if(!elements.isEmpty()) { - SafeDeleteHandler.invoke(myProject, PsiUtilCore.toPsiElementArray(elements), true); - } - } - }); + PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + myUsageView.close(); + ArrayList elements = new ArrayList(); + for (SmartPsiElementPointer pointer : myPointers) { + final PsiElement element = pointer.getElement(); + if (element != null) { + elements.add(element); + } + } + if(!elements.isEmpty()) { + SafeDeleteHandler.invoke(myProject, PsiUtilCore.toPsiElementArray(elements), true); + } } } diff --git a/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/XPathEvalAction.java b/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/XPathEvalAction.java index c1d5cb386ce0..53acb8928f79 100644 --- a/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/XPathEvalAction.java +++ b/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/XPathEvalAction.java @@ -550,14 +550,7 @@ public class XPathEvalAction extends XPathAction { public abstract static class EditExpressionAction implements Runnable { @Override public void run() { - Runnable runnable = new Runnable() { - @Override - public void run() { - execute(); - } - - }; - SwingUtilities.invokeLater(runnable); + execute(); } protected abstract void execute(); From 3beec9ace3c4d6078daf1f8449062e5d74c5f8a6 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 25 Apr 2016 11:05:01 +0200 Subject: [PATCH 62/65] remove unnecessary invokeLater from ConfigureTemplateDirectoriesAction --- .../ConfigureTemplateDirectoriesAction.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/ConfigureTemplateDirectoriesAction.java b/python/openapi/src/com/jetbrains/python/templateLanguages/ConfigureTemplateDirectoriesAction.java index 064ce6afc139..e813bf0d740c 100644 --- a/python/openapi/src/com/jetbrains/python/templateLanguages/ConfigureTemplateDirectoriesAction.java +++ b/python/openapi/src/com/jetbrains/python/templateLanguages/ConfigureTemplateDirectoriesAction.java @@ -18,8 +18,6 @@ package com.jetbrains.python.templateLanguages; import com.intellij.codeInsight.intention.LowPriorityAction; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; @@ -42,11 +40,11 @@ public class ConfigureTemplateDirectoriesAction implements LocalQuickFix, LowPri @Override public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - ShowSettingsUtil.getInstance().showSettingsDialog(project, "Project Structure"); - } - }, ModalityState.NON_MODAL); + ShowSettingsUtil.getInstance().showSettingsDialog(project, "Project Structure"); + } + + @Override + public boolean startInWriteAction() { + return false; } } From 306d16f2b43e5b22129f50a9684d2655d887de0e Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 21 Apr 2016 17:35:59 +0300 Subject: [PATCH 63/65] BuildNumber: deprecate 'fallback' method and use 'currentVersion' instead; 'fallback' name is obscure and it's better to use fallback version (999.SNAPSHOT) only if we cannot read more actual build number from build.txt, otherwise some plugins may be disabled as incompatible --- .../com/intellij/ide/plugins/PluginManagerCore.java | 2 +- .../src/com/intellij/openapi/util/BuildNumber.java | 12 ++++++++++-- .../com/intellij/openapi/util/BuildNumberTest.java | 12 ++++++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java index 101dc097da03..9b5a6ba6fcb8 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java +++ b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java @@ -94,7 +94,7 @@ public class PluginManagerCore { if (ourBuildNumber == null) { ourBuildNumber = BUILD_NUMBER == null ? null : BuildNumber.fromString(BUILD_NUMBER); if (ourBuildNumber == null) { - ourBuildNumber = BuildNumber.fromString("SNAPSHOT"); + ourBuildNumber = BuildNumber.currentVersion(); } } return ourBuildNumber; diff --git a/platform/util/src/com/intellij/openapi/util/BuildNumber.java b/platform/util/src/com/intellij/openapi/util/BuildNumber.java index c736162a16e0..73a0bec3492a 100644 --- a/platform/util/src/com/intellij/openapi/util/BuildNumber.java +++ b/platform/util/src/com/intellij/openapi/util/BuildNumber.java @@ -96,7 +96,7 @@ public class BuildNumber implements Comparable { if (BUILD_NUMBER.equals(version) || SNAPSHOT.equals(version)) { final String productCode = name != null ? name : ""; - return new BuildNumber(productCode, Holder.CURRENT_VERSION.myComponents); + return new BuildNumber(productCode, currentVersion().myComponents); } String code = version; @@ -171,9 +171,17 @@ public class BuildNumber implements Comparable { } catch (IOException ignored) { } - return fallback(); + return fromString(FALLBACK_VERSION); } + /** + * This method is for internal platform use only. In regular code use {@link com.intellij.openapi.application.ApplicationInfo#getBuild()} instead. + */ + public static BuildNumber currentVersion() { + return Holder.CURRENT_VERSION; + } + + @Deprecated public static BuildNumber fallback() { return fromString(FALLBACK_VERSION); } diff --git a/platform/util/testSrc/com/intellij/openapi/util/BuildNumberTest.java b/platform/util/testSrc/com/intellij/openapi/util/BuildNumberTest.java index 2a49881972ec..cb91d33654c4 100644 --- a/platform/util/testSrc/com/intellij/openapi/util/BuildNumberTest.java +++ b/platform/util/testSrc/com/intellij/openapi/util/BuildNumberTest.java @@ -129,12 +129,12 @@ public class BuildNumberTest { } @Test - public void fallbackVersion() throws Exception { - assertParsed(BuildNumber.fallback(), 999, BuildNumber.SNAPSHOT_VALUE, "999.SNAPSHOT"); - assertTrue(BuildNumber.fallback().isSnapshot()); + public void currentVersion() throws Exception { + BuildNumber current = BuildNumber.currentVersion(); + assertTrue(current.isSnapshot()); - assertTrue(BuildNumber.fallback().compareTo(BuildNumber.fromString("7512")) > 0); - assertTrue(BuildNumber.fallback().compareTo(BuildNumber.fromString("145")) > 0); - assertTrue(BuildNumber.fallback().compareTo(BuildNumber.fromString("145.12")) > 0); + assertTrue(current.compareTo(BuildNumber.fromString("7512")) > 0); + assertTrue(current.compareTo(BuildNumber.fromString("145")) > 0); + assertTrue(current.compareTo(BuildNumber.fromString("145.12")) > 0); } } \ No newline at end of file From 591b2184a00a6d528fbd5b9a181b66ea6403b374 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 25 Apr 2016 12:43:22 +0300 Subject: [PATCH 64/65] IDEA-155151 NPE on startup on clean installation (when lo license is present) --- .../src/com/intellij/ui/components/JBScrollPane.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index c0fd4beeb80c..d84bb3341d77 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -17,6 +17,7 @@ package com.intellij.ui.components; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.KeyboardShortcut; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; @@ -177,8 +178,9 @@ public class JBScrollPane extends JScrollPane { } private static void updateInputMap(InputMap map, String prefix, String... actions) { - if (map != null) { + if (map != null && null != ApplicationManager.getApplication()) { ActionManager manager = ActionManager.getInstance(); + if (manager != null) for (String action : actions) { KeyboardShortcut shortcut = manager.getKeyboardShortcut(prefix + action); if (shortcut != null) map.put(shortcut.getFirstKeyStroke(), action); From f18b4524af546163f7e7090d842b5744bb477c5a Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Mon, 25 Apr 2016 12:50:48 +0300 Subject: [PATCH 65/65] IDEA-154925 DesignerToolWindowManager shouldn't initialize swing components in headless mode --- plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml b/plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml index ede0d2b92f01..499619eea8eb 100644 --- a/plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml +++ b/plugins/ui-designer-core/src/META-INF/DesignerCorePlugin.xml @@ -7,9 +7,11 @@ com.intellij.designer.DesignerToolWindowManager + com.intellij.designer.palette.PaletteToolWindowManager +