diff options
Diffstat (limited to 'python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java')
-rw-r--r-- | python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java b/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java new file mode 100644 index 000000000000..69c5acc5f127 --- /dev/null +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/editor/StudyEditor.java @@ -0,0 +1,347 @@ +package com.jetbrains.python.edu.editor; + +import com.intellij.codeHighlighting.BackgroundEditorHighlighter; +import com.intellij.ide.structureView.StructureViewBuilder; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.colors.EditorColorsScheme; +import com.intellij.openapi.editor.impl.DocumentImpl; +import com.intellij.openapi.fileEditor.*; +import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; +import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl; +import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.Navigatable; +import com.intellij.ui.HideableTitledPanel; +import com.intellij.ui.JBColor; +import com.intellij.util.ui.UIUtil; +import com.jetbrains.python.edu.StudyDocumentListener; +import com.jetbrains.python.edu.StudyTaskManager; +import com.jetbrains.python.edu.actions.*; +import com.jetbrains.python.edu.course.Task; +import com.jetbrains.python.edu.course.TaskFile; +import icons.StudyIcons; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledDocument; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeListener; +import java.util.HashMap; +import java.util.Map; + +/** + * Implementation of StudyEditor which has panel with special buttons and task text + * also @see {@link com.jetbrains.python.edu.editor.StudyFileEditorProvider} + */ +public class StudyEditor implements TextEditor { + private static final String TASK_TEXT_HEADER = "Task Text"; + private final FileEditor myDefaultEditor; + private final JComponent myComponent; + private JButton myCheckButton; + private JButton myNextTaskButton; + private JButton myPrevTaskButton; + private JButton myRefreshButton; + private static final Map<Document, StudyDocumentListener> myDocumentListeners = new HashMap<Document, StudyDocumentListener>(); + private Project myProject; + + public JButton getCheckButton() { + return myCheckButton; + } + + public JButton getPrevTaskButton() { + return myPrevTaskButton; + } + + private static JButton addButton(@NotNull final JComponent parentComponent, String toolTipText, Icon icon) { + JButton newButton = new JButton(); + newButton.setToolTipText(toolTipText); + newButton.setIcon(icon); + newButton.setSize(new Dimension(icon.getIconWidth(), icon.getIconHeight())); + parentComponent.add(newButton); + return newButton; + } + + public static void addDocumentListener(@NotNull final Document document, @NotNull final StudyDocumentListener listener) { + myDocumentListeners.put(document, listener); + } + + @Nullable + public static StudyDocumentListener getListener(@NotNull final Document document) { + return myDocumentListeners.get(document); + } + + public StudyEditor(@NotNull final Project project, @NotNull final VirtualFile file) { + myProject = project; + myDefaultEditor = TextEditorProvider.getInstance().createEditor(myProject, file); + myComponent = myDefaultEditor.getComponent(); + JPanel studyPanel = new JPanel(); + studyPanel.setLayout(new BoxLayout(studyPanel, BoxLayout.Y_AXIS)); + TaskFile taskFile = StudyTaskManager.getInstance(myProject).getTaskFile(file); + if (taskFile != null) { + Task currentTask = taskFile.getTask(); + String taskText = currentTask.getResourceText(project, currentTask.getText(), false); + initializeTaskText(studyPanel, taskText); + JPanel studyButtonPanel = new JPanel(new GridLayout(1, 2)); + JPanel taskActionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + studyButtonPanel.add(taskActionsPanel); + studyButtonPanel.add(new JPanel()); + initializeButtons(taskActionsPanel, taskFile); + studyPanel.add(studyButtonPanel); + myComponent.add(studyPanel, BorderLayout.NORTH); + } + } + + private static void initializeTaskText(JPanel studyPanel, @Nullable String taskText) { + JTextPane taskTextPane = new JTextPane(); + taskTextPane.setContentType("text/html"); + taskTextPane.setEditable(false); + taskTextPane.setText(taskText); + EditorColorsScheme editorColorsScheme = EditorColorsManager.getInstance().getGlobalScheme(); + int fontSize = editorColorsScheme.getEditorFontSize(); + String fontName = editorColorsScheme.getEditorFontName(); + setJTextPaneFont(taskTextPane, new Font(fontName, Font.PLAIN, fontSize), JBColor.BLACK); + taskTextPane.setBackground(UIUtil.getPanelBackground()); + taskTextPane.setBorder(new EmptyBorder(15, 20, 0, 100)); + HideableTitledPanel taskTextPanel = new HideableTitledPanel(TASK_TEXT_HEADER, taskTextPane, true); + taskTextPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); + studyPanel.add(taskTextPanel); + } + + private static void setJTextPaneFont(JTextPane jtp, Font font, Color c) { + MutableAttributeSet attrs = jtp.getInputAttributes(); + StyleConstants.setFontFamily(attrs, font.getFamily()); + StyleConstants.setFontSize(attrs, font.getSize()); + StyleConstants.setItalic(attrs, (font.getStyle() & Font.ITALIC) != 0); + StyleConstants.setBold(attrs, (font.getStyle() & Font.BOLD) != 0); + StyleConstants.setForeground(attrs, c); + StyledDocument doc = jtp.getStyledDocument(); + doc.setCharacterAttributes(0, doc.getLength() + 1, attrs, false); + } + + private void initializeButtons(@NotNull final JPanel taskActionsPanel, @NotNull final TaskFile taskFile) { + myCheckButton = addButton(taskActionsPanel, "Check task", StudyIcons.Resolve); + myPrevTaskButton = addButton(taskActionsPanel, "Prev Task", StudyIcons.Prev); + myNextTaskButton = addButton(taskActionsPanel, "Next Task", StudyIcons.Next); + myRefreshButton = addButton(taskActionsPanel, "Start task again", StudyIcons.Refresh24); + if (!taskFile.getTask().getUserTests().isEmpty()) { + JButton runButton = addButton(taskActionsPanel, "Run", StudyIcons.Run); + runButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + StudyRunAction studyRunAction = (StudyRunAction)ActionManager.getInstance().getAction("StudyRunAction"); + studyRunAction.run(myProject); + } + }); + JButton watchInputButton = addButton(taskActionsPanel, "Watch test input", StudyIcons.WatchInput); + watchInputButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + StudyEditInputAction studyEditInputAction = (StudyEditInputAction)ActionManager.getInstance().getAction("WatchInputAction"); + studyEditInputAction.showInput(myProject); + } + }); + } + myCheckButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + StudyCheckAction studyCheckAction = (StudyCheckAction)ActionManager.getInstance().getAction("CheckAction"); + studyCheckAction.check(myProject); + } + }); + + myNextTaskButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + StudyNextStudyTaskAction studyNextTaskAction = (StudyNextStudyTaskAction)ActionManager.getInstance().getAction("NextTaskAction"); + studyNextTaskAction.navigateTask(myProject); + } + }); + myPrevTaskButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + StudyPreviousStudyTaskAction + prevTaskAction = (StudyPreviousStudyTaskAction)ActionManager.getInstance().getAction("PreviousTaskAction"); + prevTaskAction.navigateTask(myProject); + } + }); + myRefreshButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + StudyRefreshTaskAction studyRefreshTaskAction = (StudyRefreshTaskAction)ActionManager.getInstance().getAction("RefreshTaskAction"); + studyRefreshTaskAction.refresh(myProject); + } + }); + } + + public JButton getNextTaskButton() { + return myNextTaskButton; + } + + public JButton getRefreshButton() { + return myRefreshButton; + } + + FileEditor getDefaultEditor() { + return myDefaultEditor; + } + + @NotNull + @Override + public JComponent getComponent() { + return myComponent; + } + + @Nullable + @Override + public JComponent getPreferredFocusedComponent() { + return myDefaultEditor.getPreferredFocusedComponent(); + } + + @NotNull + @Override + public String getName() { + return "Study Editor"; + } + + @NotNull + @Override + public FileEditorState getState(@NotNull FileEditorStateLevel level) { + return myDefaultEditor.getState(level); + } + + @Override + public void setState(@NotNull FileEditorState state) { + myDefaultEditor.setState(state); + } + + @Override + public boolean isModified() { + return myDefaultEditor.isModified(); + } + + @Override + public boolean isValid() { + return myDefaultEditor.isValid(); + } + + @Override + public void selectNotify() { + myDefaultEditor.selectNotify(); + } + + @Override + public void deselectNotify() { + myDefaultEditor.deselectNotify(); + } + + @Override + public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) { + myDefaultEditor.addPropertyChangeListener(listener); + } + + @Override + public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) { + myDefaultEditor.removePropertyChangeListener(listener); + } + + @Nullable + @Override + public BackgroundEditorHighlighter getBackgroundHighlighter() { + return myDefaultEditor.getBackgroundHighlighter(); + } + + @Nullable + @Override + public FileEditorLocation getCurrentLocation() { + return myDefaultEditor.getCurrentLocation(); + } + + @Nullable + @Override + public StructureViewBuilder getStructureViewBuilder() { + return myDefaultEditor.getStructureViewBuilder(); + } + + @Override + public void dispose() { + Disposer.dispose(myDefaultEditor); + } + + @Nullable + @Override + public <T> T getUserData(@NotNull Key<T> key) { + return myDefaultEditor.getUserData(key); + } + + @Override + public <T> void putUserData(@NotNull Key<T> key, @Nullable T value) { + myDefaultEditor.putUserData(key, value); + } + + + @Nullable + public static StudyEditor getSelectedStudyEditor(@NotNull final Project project) { + try { + FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow(). + getSelectedEditor().getSelectedEditorWithProvider().getFirst(); + if (fileEditor instanceof StudyEditor) { + return (StudyEditor)fileEditor; + } + } catch (Exception e) { + return null; + } + return null; + } + + @Nullable + public static Editor getSelectedEditor(@NotNull final Project project) { + StudyEditor studyEditor = getSelectedStudyEditor(project); + if (studyEditor != null) { + FileEditor defaultEditor = studyEditor.getDefaultEditor(); + if (defaultEditor instanceof PsiAwareTextEditorImpl) { + return ((PsiAwareTextEditorImpl)defaultEditor).getEditor(); + } + } + return null; + } + + public static void removeListener(Document document) { + myDocumentListeners.remove(document); + } + + @NotNull + @Override + public Editor getEditor() { + if (myDefaultEditor instanceof TextEditor) + return ((TextEditor)myDefaultEditor).getEditor(); + return EditorFactory.getInstance().createViewer(new DocumentImpl(""), myProject); + } + + @Override + public boolean canNavigateTo(@NotNull Navigatable navigatable) { + if (myDefaultEditor instanceof TextEditor) { + ((TextEditor)myDefaultEditor).canNavigateTo(navigatable); + } + return false; + } + + @Override + public void navigateTo(@NotNull Navigatable navigatable) { + if (myDefaultEditor instanceof TextEditor) { + ((TextEditor)myDefaultEditor).navigateTo(navigatable); + } + } +} |