1 package com.jetbrains.edu.learning.ui
3 import com.intellij.icons.AllIcons
4 import com.intellij.ide.browsers.WebBrowserManager
5 import com.intellij.openapi.Disposable
6 import com.intellij.openapi.actionSystem.*
7 import com.intellij.openapi.application.ApplicationManager
8 import com.intellij.openapi.editor.Document
9 import com.intellij.openapi.editor.Editor
10 import com.intellij.openapi.editor.EditorFactory
11 import com.intellij.openapi.editor.ex.EditorEx
12 import com.intellij.openapi.editor.ex.FocusChangeListener
13 import com.intellij.openapi.project.Project
14 import com.intellij.openapi.util.Disposer
15 import com.jetbrains.edu.learning.StudyTaskManager
16 import com.jetbrains.edu.learning.StudyUtils
17 import com.jetbrains.edu.learning.core.EduNames
18 import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder
20 class StudyHint(private val myPlaceholder: AnswerPlaceholder?, project: Project) {
21 val studyToolWindow: StudyToolWindow
22 private var myShownHintNumber = 0
23 private var isEditingMode = false
24 private val newHintDefaultText = "Edit this hint"
27 val taskManager = StudyTaskManager.getInstance(project)
28 if (StudyUtils.hasJavaFx() && taskManager.shouldUseJavaFx()) {
29 studyToolWindow = StudyJavaFxToolWindow()
32 studyToolWindow = StudySwingToolWindow()
34 studyToolWindow.init(project, false)
36 if (myPlaceholder == null) {
37 studyToolWindow.setText(OUR_WARNING_MESSAGE)
40 val course = taskManager.course
42 val courseMode = course.courseMode
43 val group = DefaultActionGroup()
44 val hints = myPlaceholder?.hints
46 if (courseMode == EduNames.STUDY) {
48 group.addAll(GoBackward(), GoForward())
52 group.addAll(GoBackward(), GoForward(), Separator.getInstance(), EditHint(), AddHint(), RemoveHint())
54 studyToolWindow.setActionToolbar(group)
55 if (!hints.isEmpty()) {
56 studyToolWindow.setText(hints[myShownHintNumber])
59 studyToolWindow.setText("No hints are provided")
65 private inner class GoForward : AnAction("Next Hint", "Next Hint", AllIcons.Actions.Forward) {
68 override fun actionPerformed(e: AnActionEvent) {
69 studyToolWindow.setText(myPlaceholder!!.hints[++myShownHintNumber])
72 override fun update(e: AnActionEvent) {
73 e.presentation.isEnabled = !isEditingMode && myPlaceholder != null && myShownHintNumber + 1 < myPlaceholder.hints.size
77 private inner class GoBackward : AnAction("Previous Hint", "Previous Hint", AllIcons.Actions.Back) {
79 override fun actionPerformed(e: AnActionEvent) {
80 studyToolWindow.setText(myPlaceholder!!.hints[--myShownHintNumber])
83 override fun update(e: AnActionEvent) {
84 e.presentation.isEnabled = !isEditingMode && myShownHintNumber - 1 >= 0
88 private inner class EditHint : ToggleAction("Edit Hint", "Edit Hint", AllIcons.Modules.Edit) {
90 private var currentDocument: Document? = null
92 override fun isSelected(e: AnActionEvent): Boolean {
93 e.project ?: return false
97 override fun setSelected(e: AnActionEvent, state: Boolean) {
98 val project = e.project ?: return
99 e.presentation.text = if (state) "Save Hint" else "Edit Hint"
100 doOnSelection(state, project)
103 fun doOnSelection(state: Boolean, project: Project) {
106 val factory = EditorFactory.getInstance()
107 currentDocument = factory.createDocument(myPlaceholder!!.hints[myShownHintNumber])
108 WebBrowserManager.getInstance().isShowBrowserHover = false
109 if (currentDocument != null) {
110 val createdEditor = factory.createEditor(currentDocument as Document, project) as EditorEx
111 Disposer.register(project, Disposable { factory.releaseEditor(createdEditor) })
112 val editorComponent = createdEditor.component
113 studyToolWindow.setTopComponent(editorComponent)
114 studyToolWindow.repaint()
116 createdEditor.addFocusListener(object: FocusChangeListener {
117 override fun focusGained(editor: Editor?) {
118 if (createdEditor.document.text == newHintDefaultText) {
119 ApplicationManager.getApplication().runWriteAction { createdEditor.document.setText("") }
123 override fun focusLost(editor: Editor?) {
130 isEditingMode = false
131 myPlaceholder!!.hints[myShownHintNumber] = currentDocument!!.text
132 studyToolWindow.setText(myPlaceholder.hints[myShownHintNumber])
133 studyToolWindow.setDefaultTopComponent()
137 override fun update(e: AnActionEvent) {
138 e.presentation.isEnabled = myPlaceholder?.hints?.isEmpty() == false
142 private inner class AddHint : AnAction("Add Hint", "Add Hint", AllIcons.General.Add) {
144 override fun actionPerformed(e: AnActionEvent) {
145 myPlaceholder!!.hints.add(newHintDefaultText)
147 studyToolWindow.setText(newHintDefaultText)
150 override fun update(e: AnActionEvent?) {
151 e?.presentation?.isEnabled = !isEditingMode && myPlaceholder != null && !myPlaceholder.hints.isEmpty()
155 private inner class RemoveHint : AnAction("Remove Hint", "Remove Hint", AllIcons.General.Remove) {
157 override fun actionPerformed(e: AnActionEvent) {
158 myPlaceholder!!.hints.removeAt(myShownHintNumber)
159 myShownHintNumber = if (myPlaceholder.hints.size == 1) 0 else if (myShownHintNumber + 1 < myPlaceholder.hints.size) myShownHintNumber + 1 else myShownHintNumber - 1
160 studyToolWindow.setText(myPlaceholder.hints[myShownHintNumber])
163 override fun update(e: AnActionEvent) {
164 e.presentation.isEnabled = myPlaceholder != null && myPlaceholder.hints.size > 1 && !isEditingMode
169 private val OUR_WARNING_MESSAGE = "Put the caret in the answer placeholder to get hint"