Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2014-10-29 13:06:17 +03:00
204 changed files with 2270 additions and 1071 deletions
@@ -80,7 +80,7 @@
<add-to-group group-id="ProjectViewPopupMenu" anchor="before" relative-to-action="CutCopyPasteGroup"/>
<add-to-group group-id="FileMenu" relative-to-action="FileMainSettingsGroup" anchor="before"/>
</action>
<action id="CCRunTests" class="org.jetbrains.plugins.coursecreator.actions.CCRunTestsAction" text="Run tests" description="Run tests"/>
<action id="CCRunTests" class="org.jetbrains.plugins.coursecreator.actions.CCRunTestsAction" text="Run Tests" description="Run tests"/>
</actions>
</idea-plugin>
@@ -24,7 +24,7 @@ public class CCAddTaskWindow extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(CCAddTaskWindow.class);
public CCAddTaskWindow() {
super("Add problem to solve", "Add problem to solve", null);
super("Add Problem to Solve", "Add problem to solve", null);
}
@@ -21,7 +21,7 @@ import javax.swing.*;
public class CCChangeCourseInfo extends DumbAwareAction {
public CCChangeCourseInfo() {
super("Change Course information", "Change Course Information", null);
super("Change Course Information", "Change Course Information", null);
}
@Override
@@ -18,7 +18,7 @@ public class CCDeleteTaskWindow extends CCTaskWindowAction {
private static final Logger LOG = Logger.getInstance(CCDeleteTaskWindow.class);
public CCDeleteTaskWindow() {
super("Delete problem","Delete problem", null);
super("Delete Problem","Delete problem", null);
}
@Override
@@ -50,7 +50,7 @@ public class CCShowPreview extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(CCShowPreview.class.getName());
public CCShowPreview() {
super("Show preview","Show preview", null);
super("Show Preview","Show preview", null);
}
@Override
@@ -11,7 +11,7 @@ import org.jetbrains.plugins.coursecreator.ui.CreateTaskWindowDialog;
public class CCShowTaskWindowDetails extends CCTaskWindowAction {
public CCShowTaskWindowDetails() {
super("Show problem details", "Show problem details", null);
super("Show Problem Details", "Show problem details", null);
}
@Override
@@ -22,8 +22,6 @@
<depends>com.intellij.modules.lang</depends>
<depends>com.intellij.modules.python</depends>
<application-components>
</application-components>
<project-components>
<component>
@@ -40,27 +38,33 @@
</application-components>
<actions>
<action id="CheckAction" class="com.jetbrains.python.edu.actions.StudyCheckAction" text="check"
description="Runs tests for current tasks">
<action id="CheckAction" class="com.jetbrains.python.edu.actions.StudyCheckAction" text="Check Task"
description="Check current task">
</action>
<action id="PrevWindowAction" class="com.jetbrains.python.edu.actions.StudyPrevWindowAction" text="PrevWindowAction" description="prev">
<action id="PrevWindowAction" class="com.jetbrains.python.edu.actions.StudyPrevWindowAction" text="Previous Task Window"
description="Navigate to previous task window">
</action>
<action id="NextWindow" class="com.jetbrains.python.edu.actions.StudyNextWindowAction" text="NextWindowAction" description="next">
<action id="NextWindow" class="com.jetbrains.python.edu.actions.StudyNextWindowAction" text="Next Task Window"
description="Navigate to next task window">
</action>
<action id="NextTaskAction" class="com.jetbrains.python.edu.actions.StudyNextStudyTaskAction" text="NextTaskAction" description="Next Task"/>
<action id="PreviousTaskAction" class="com.jetbrains.python.edu.actions.StudyPreviousStudyTaskAction" text="PreviousTaskAction"
description="Previous Task"/>
<action id="RefreshTaskAction" class="com.jetbrains.python.edu.actions.StudyRefreshTaskFileAction" text="RefreshTaskAction"
<action id="PreviousTaskAction" class="com.jetbrains.python.edu.actions.StudyPreviousStudyTaskAction" text="Previous Task"
description="Navigate to previous task"/>
<action id="NextTaskAction" class="com.jetbrains.python.edu.actions.StudyNextStudyTaskAction" text="Next Task"
description="Navigate to next task"/>
<action id="RefreshTaskAction" class="com.jetbrains.python.edu.actions.StudyRefreshTaskFileAction" text="Reset Task File"
description="Refresh current task"/>
<action id="WatchInputAction" class="com.jetbrains.python.edu.actions.StudyEditInputAction" text="WatchInputAction"
description="watch input"/>
<action id="ShowHintAction" class="com.jetbrains.python.edu.actions.StudyShowHintAction" text="Show hint"
description="Show hint"/>
<action id="StudyRunAction" class="com.jetbrains.python.edu.actions.StudyRunAction" text="StudyRunAction" description="run your code"/>
<action id="WatchInputAction" class="com.jetbrains.python.edu.actions.StudyEditInputAction" text="Watch Test Input"
description="Watch test input "/>
<action id="ShowHintAction" class="com.jetbrains.python.edu.actions.StudyShowHintAction" text="Show Hint for Task Window"
description="Show hint for task window"/>
<action id="StudyRunAction" class="com.jetbrains.python.edu.actions.StudyRunAction" text="Run File With Tests"
description="Run your code with tests"/>
<action id="WelcomeScreen.PythonIntro" class="com.jetbrains.python.edu.actions.StudyIntroductionCourseAction" icon="StudyIcons.EducationalProjectType">
<add-to-group group-id="WelcomeScreen.QuickStart" anchor="first"/>
</action>
<action id="StudyWatchTutorial" class="com.jetbrains.python.edu.actions.StudyWatchTutorialAction">
<add-to-group group-id="HelpMenu" anchor="first"/>
</action>
</actions>
@@ -1,14 +1,20 @@
package com.jetbrains.python.edu;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.fileEditor.impl.EditorEmptyTextPainter;
import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.util.Couple;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.util.PairFunction;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.python.edu.actions.*;
import javax.swing.*;
import java.awt.*;
/**
@@ -27,13 +33,19 @@ public class StudyInstructionPainter extends EditorEmptyTextPainter {
UIUtil.TextPainter painter = new UIUtil.TextPainter().withLineSpacing(1.5f);
painter.appendLine("PyCharm Educational Edition").underlined(new JBColor(Gray._150, Gray._180));
painter.appendLine("Navigate to the next task window with Ctrl + Enter").smaller().withBullet();
painter.appendLine("Navigate between task windows with Ctrl + Shift + < and Ctrl + Shift + >").smaller().withBullet();
painter.appendLine("Navigate between tasks with Ctrl + < and Ctrl + >").smaller().withBullet();
painter.appendLine("Reset current task file with Ctrl + Shift + X").smaller().withBullet();
painter.appendLine("Check task with Alt + Ctrl + Enter").smaller().withBullet();
painter.appendLine("Get hint for the task window using Ctrl + 7").smaller().withBullet();
painter.appendLine("To see your progress, open the 'Course Description' panel").smaller().withBullet();
addAction(painter, "Navigate to the next task window", StudyNextWindowAction.ACTION_ID, StudyNextWindowAction.SHORTCUT2, true);
String shortcut1 = getShortcutText(StudyPrevWindowAction.ACTION_ID, StudyPrevWindowAction.SHORTCUT, false, false);
String shortcut2 = getShortcutText(StudyNextWindowAction.ACTION_ID, StudyNextWindowAction.SHORTCUT, false, false);
String text = "Navigate between task windows with " + shortcut1 +
" and " + shortcut2;
painter.appendLine(text).smaller().withBullet();
shortcut1 = getShortcutText(StudyPreviousStudyTaskAction.ACTION_ID, StudyPreviousStudyTaskAction.SHORTCUT, false, false);
shortcut2 = getShortcutText(StudyNextStudyTaskAction.ACTION_ID, StudyNextStudyTaskAction.SHORTCUT, false, false);
painter.appendLine("Navigate between tasks with " + shortcut1 + " and " + shortcut2).smaller().withBullet();
addAction(painter, "Reset current task file", StudyRefreshTaskFileAction.ACTION_ID, StudyRefreshTaskFileAction.SHORTCUT, false);
addAction(painter, "Check task", StudyCheckAction.ACTION_ID, StudyCheckAction.SHORTCUT, false);
addAction(painter, "Get hint for the task window", StudyShowHintAction.ACTION_ID, StudyShowHintAction.SHORTCUT, false);
painter.appendLine("To see your progress open the 'Course Description' panel").smaller().withBullet();
painter.draw(g, new PairFunction<Integer, Integer, Couple<Integer>>() {
@Override
public Couple<Integer> fun(Integer width, Integer height) {
@@ -42,4 +54,25 @@ public class StudyInstructionPainter extends EditorEmptyTextPainter {
}
});
}
private static void addAction(UIUtil.TextPainter painter, String text, String actionId, String defaultShortcutString, boolean useDefault) {
String shortcut = getShortcutText(actionId, defaultShortcutString, useDefault, true);
String actionText = text + " with " + shortcut;
painter.appendLine(actionText).smaller().withBullet();
}
private static String getShortcutText(String actionId, String defaultShortcutString, boolean useDefault, boolean wrapTag) {
AnAction action = ActionManager.getInstance().getAction(actionId);
String shortcut = "";
if (!useDefault) {
shortcut = KeymapUtil.getFirstKeyboardShortcutText(action);
}
if (shortcut.isEmpty() && defaultShortcutString != null) {
KeyboardShortcut keyboardShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(defaultShortcutString), null);
shortcut = KeymapUtil.getShortcutText(keyboardShortcut);
}
if (!wrapTag) {
return shortcut;
}
return "<shortcut>" + shortcut + "</shortcut>";
}
}
@@ -1,6 +1,12 @@
package com.jetbrains.python.edu;
import com.intellij.ide.BrowserUtil;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.AnActionListener;
import com.intellij.openapi.application.ApplicationManager;
@@ -14,11 +20,15 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupAdapter;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileAdapter;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.wm.*;
import com.intellij.util.ui.update.UiNotifyConnector;
import com.intellij.util.xmlb.XmlSerializer;
import com.jetbrains.python.edu.actions.*;
import com.jetbrains.python.edu.course.Course;
@@ -32,7 +42,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -145,9 +157,65 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon
}
final ToolWindow studyToolWindow = toolWindowManager.getToolWindow(toolWindowId);
class UrlOpeningListener implements NotificationListener {
private final boolean myExpireNotification;
public UrlOpeningListener(boolean expireNotification) {
myExpireNotification = expireNotification;
}
protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
URL url = event.getURL();
if (url == null) {
BrowserUtil.browse(event.getDescription());
}
else {
BrowserUtil.browse(url);
}
if (myExpireNotification) {
notification.expire();
}
}
@Override
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
hyperlinkActivated(notification, event);
}
}
}
if (studyToolWindow != null) {
StudyUtils.updateStudyToolWindow(myProject);
studyToolWindow.show(null);
UiNotifyConnector.doWhenFirstShown(studyToolWindow.getComponent(), new Runnable() {
@Override
public void run() {
if (PropertiesComponent.getInstance().getBoolean("StudyShowPopup", true)) {
String content = "<html>If you'd like to learn" +
" more about PyCharm " +
"Educational Edition, " +
"click <a href=\"http://www.jetbrains.com/pycharm-educational/quickstart/\">here</a> to watch a tutorial</html>";
final Notification notification =
new Notification("Watch Tutorials!", "", content, NotificationType.INFORMATION, new UrlOpeningListener(true));
Notifications.Bus.notify(notification);
Balloon balloon = notification.getBalloon();
if (balloon != null) {
balloon.addListener(new JBPopupAdapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
notification.expire();
}
});
}
notification.whenExpired(new Runnable() {
@Override
public void run() {
PropertiesComponent.getInstance().setValue("StudyShowPopup", String.valueOf(false));
}
});
}
}
});
}
addShortcut(StudyNextWindowAction.SHORTCUT, StudyNextWindowAction.ACTION_ID);
addShortcut(StudyPrevWindowAction.SHORTCUT, StudyPrevWindowAction.ACTION_ID);
@@ -167,6 +235,10 @@ public class StudyTaskManager implements ProjectComponent, PersistentStateCompon
private static void addShortcut(@NotNull final String shortcutString, @NotNull final String actionIdString) {
Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
Shortcut[] shortcuts = keymap.getShortcuts(actionIdString);
if (shortcuts.length > 0) {
return;
}
Shortcut studyActionShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(shortcutString), null);
String[] actionsIds = keymap.getActionIds(studyActionShortcut);
for (String actionId : actionsIds) {
@@ -0,0 +1,17 @@
package com.jetbrains.python.edu.actions;
import com.intellij.ide.BrowserUtil;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAwareAction;
import org.jetbrains.annotations.NotNull;
public class StudyWatchTutorialAction extends DumbAwareAction {
public StudyWatchTutorialAction() {
super("Learn more about PyCharm Educational Edition", null, null);
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
BrowserUtil.browse("http://www.jetbrains.com/pycharm-educational/quickstart/");
}
}
@@ -4,6 +4,8 @@ import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
import com.intellij.icons.AllIcons;
import com.intellij.ide.structureView.StructureViewBuilder;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
@@ -16,6 +18,7 @@ import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl;
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
@@ -48,8 +51,9 @@ import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Implementation of StudyEditor which has panel with special buttons and task text
@@ -79,7 +83,14 @@ public class StudyEditor implements TextEditor {
return myTaskFile;
}
private static JButton addButton(@NotNull final JComponent parentComponent, String toolTipText, Icon icon) {
private static JButton addButton(@NotNull final JComponent parentComponent, String actionID, Icon icon,
@Nullable String defaultShortcutString) {
AnAction action = ActionManager.getInstance().getAction(actionID);
String toolTipText = KeymapUtil.createTooltipText(action.getTemplatePresentation().getText(), action);
if (!toolTipText.contains("(") && defaultShortcutString != null) {
KeyboardShortcut shortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(defaultShortcutString), null);
toolTipText += " (" + KeymapUtil.getShortcutText(shortcut) + ")";
}
JButton newButton = new JButton();
newButton.setToolTipText(toolTipText);
newButton.setIcon(icon);
@@ -192,13 +203,13 @@ public class StudyEditor implements TextEditor {
}
private void initializeButtons(@NotNull final JPanel taskActionsPanel, @NotNull final TaskFile taskFile) {
myCheckButton = addButton(taskActionsPanel, "Check task (Ctrl + Alt + Enter)", StudyIcons.Resolve);
myPrevTaskButton = addButton(taskActionsPanel, "Previous task (Ctrl + &lt;)", StudyIcons.Prev);
myNextTaskButton = addButton(taskActionsPanel, "Next task (Ctrl + >)", AllIcons.Actions.Forward);
myRefreshButton = addButton(taskActionsPanel, "Reset task file (Ctrl + Shift + X)", AllIcons.Actions.Refresh);
JButton myShowHintButton = addButton(taskActionsPanel, "Show hint for task window (Ctrl + 7)", StudyIcons.ShowHint);
myCheckButton = addButton(taskActionsPanel, StudyCheckAction.ACTION_ID, StudyIcons.Resolve, StudyCheckAction.SHORTCUT);
myPrevTaskButton = addButton(taskActionsPanel, StudyPreviousStudyTaskAction.ACTION_ID, StudyIcons.Prev, StudyPreviousStudyTaskAction.SHORTCUT);
myNextTaskButton = addButton(taskActionsPanel, StudyNextStudyTaskAction.ACTION_ID, AllIcons.Actions.Forward, StudyNextStudyTaskAction.SHORTCUT);
myRefreshButton = addButton(taskActionsPanel, StudyRefreshTaskFileAction.ACTION_ID, AllIcons.Actions.Refresh, StudyRefreshTaskFileAction.SHORTCUT);
JButton myShowHintButton = addButton(taskActionsPanel, StudyShowHintAction.ACTION_ID, StudyIcons.ShowHint, StudyShowHintAction.SHORTCUT);
if (!taskFile.getTask().getUserTests().isEmpty()) {
JButton runButton = addButton(taskActionsPanel, "Run", AllIcons.General.Run);
JButton runButton = addButton(taskActionsPanel, StudyRunAction.ACTION_ID, AllIcons.General.Run, null);
runButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -206,7 +217,7 @@ public class StudyEditor implements TextEditor {
studyRunAction.run(myProject);
}
});
JButton watchInputButton = addButton(taskActionsPanel, "Watch test input", StudyIcons.WatchInput);
JButton watchInputButton = addButton(taskActionsPanel, "WatchInputAction", StudyIcons.WatchInput, null);
watchInputButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {