├── .gitignore
├── .idea
├── .name
├── codeStyleSettings.xml
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── intellij-plugin.iml
├── libraries
│ ├── com_google_code_gson_gson_Release.xml
│ └── com_mashape_unirest_unirest_java_Release.xml
├── misc.xml
├── modules.xml
├── uiDesigner.xml
└── vcs.xml
├── README.md
├── intellij-plugin.iml
├── resources
├── META-INF
│ └── plugin.xml
├── code-mirror
│ ├── codemirror-darcula.css
│ ├── codemirror-old-darcula.css
│ ├── codemirror-old.css
│ ├── codemirror.css
│ ├── codemirror.js
│ ├── colorize.js
│ ├── javascript.js
│ ├── runmode.js
│ └── template.html
├── icons
│ ├── download_blue.png
│ ├── stepik_logo_green.png
│ └── stepik_logotype_13x13-2.png
├── python.js
└── style
│ ├── javaFXBrowserDarcula.css
│ ├── javaFXBrowserDarculaScrollBar.css
│ └── javaFXBrowserScrollBar.css
└── src
└── org
└── stepik
└── plugin
├── actions
├── mainMenu
│ ├── Help.java
│ ├── MainMenuAction.java
│ ├── NegTranslator.java
│ ├── PrintMapInfo.java
│ ├── RefreshMap.java
│ ├── RefreshToken.java
│ ├── SignIn.java
│ ├── SomeAction.java
│ ├── UpdateCourse.java
│ └── WhoAmI.java
└── popupMenu
│ ├── DownloadLastSubmission.java
│ ├── GetIdStep.java
│ ├── GetStepStatus.java
│ ├── PopupMenuAction.java
│ └── SendFile.java
├── components
├── MyModuleComponent.java
└── MyProjectComponent.java
├── icons
└── PluginIcons.java
├── modules
├── Attempt.java
├── Course.java
├── CourseInfo.java
├── Lesson.java
├── Section.java
├── Step.java
├── StepInfo.java
├── Submission.java
├── TokenInfo.java
└── Unit.java
├── projectWizard
├── StepikModuleBuilder.java
├── StepikModuleType.java
├── StepikModuleWizardStep.form
├── StepikModuleWizardStep.java
└── StepikProjectStructureDetector.java
├── stepikConnector
└── StepikConnector.java
├── storages
├── ActionVisibleProperties.java
├── CourseDefinitionStorage.java
├── StepikApplicationStorage.java
└── StudentStorage.java
├── toolWindow
├── JavaStudyPluginConfigurator.java
├── StudyBasePluginConfigurator.java
├── StudyBrowserWindow.java
├── StudyCondition.java
├── StudyEditor.java
├── StudyEditorFactoryListener.java
├── StudyJavaFxToolWindow.java
├── StudyPluginConfigurator.java
├── StudySwingToolWindow.java
├── StudyToolWindow.java
├── StudyToolWindowFactory.java
└── StudyUtils.java
└── utils
├── MyLogger.java
├── NotificationTemplates.java
├── NotificationUtils.java
├── Utils.java
└── YaTranslator.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 | out/
14 | .idea/workspace.xml
15 | .idea/tasks.xml
16 | intellij-plugin.zip
17 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | intellij-plugin
--------------------------------------------------------------------------------
/.idea/codeStyleSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/intellij-plugin.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/libraries/com_google_code_gson_gson_Release.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/libraries/com_mashape_unirest_unirest_java_Release.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 | -
41 |
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # This repository is outdated
2 | Current repository: [intellij-plugins](https://github.com/StepicOrg/intellij-plugins)
3 |
4 | # intellij-plugin 0.6.8
5 |
6 | To work with plugin you must to create a project of Stepik type.
7 | You need to enter login and password your Stepik account.
8 | And then input course URL or course number.
9 | After twenty seconds course will be built.
10 |
11 | To send task click the left mouse button on file. In the shortcut menu choose "Send step".
12 | In the same way you can to download last submissions and get the status of step.
13 |
14 |
15 | ## Features
16 | * **Sign in** — you can input login and password, and then you get OAuth2 token.
17 | * **Who am i** — return `user_name`.
18 | * **Download Latest Submission** — download your latest submission this step from site.
19 | * **Check Step Status** — return a step status and status of last submission posted from IDE.
20 | * **Submit Solution** — send this step to platform.
21 |
22 | ## Install
23 | 0. Download and install IntelliJ IDEA 2016 (https://www.jetbrains.com/idea/)
24 | 1. Download latest version of the plugin from https://drive.google.com/open?id=0B3r_Au4BpPbweXJhYWpYWTdkZnc (intellij-plugin.zip) or build it yourself from the source code.
25 | 2. Open IntelliJ IDEA
26 | 3. Menu IntelliJ IDEA > Preferences > Plugins > Install plugin from disk... > intellij-plugin.zip
27 | 4. Restart IDEA
28 |
29 | ## Usage
30 | 1. File > New > Project > Stepik
31 | 2. Enter your login/password and a course link (in a form of https://stepik.org/course/some-course-name-ID/ or just ID)
32 |
33 | ## Build
34 | 1. In order to build this project, you have to setting up an development environment (IntelliJ Platform SDK) as described here: http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/setting_up_environment.html
35 | 2. Clone project, e.g. using `git clone https://github.com/StepicOrg/intellij-plugin.git`.
36 | 3. Deploy the plugin as described here: http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/deploying_plugin.html
37 |
--------------------------------------------------------------------------------
/intellij-plugin.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/resources/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 | stepik.submmit.plugin.id
3 | Stepik Java submitter -beta-
4 | 0.6.8
5 | Stepik
6 |
7 |
9 | To use this plugin you have to have Stepik account and follow the course.
10 |
11 | It used Yandex.Translator to translate lesson names on Russian to package names on English.
12 | ]]>
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
26 |
29 |
30 |
31 |
32 |
33 |
35 |
36 |
38 |
39 |
41 |
42 |
44 |
45 |
48 |
49 |
51 |
52 |
54 |
55 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
92 |
93 |
101 |
102 |
104 |
105 |
106 |
107 |
111 |
112 |
113 |
114 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
131 |
132 |
133 |
135 |
136 |
137 |
144 |
146 |
147 |
148 |
149 |
153 |
154 |
155 |
156 |
158 |
159 |
160 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | org.stepik.plugin.components.MyModuleComponent
169 |
170 |
171 |
172 |
173 | org.stepik.plugin.components.MyProjectComponent
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/resources/code-mirror/codemirror-darcula.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2014 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | body {
18 | margin-left: 20px;
19 | font-family: Helvetica, sans-serif;
20 | }
21 |
22 | code {
23 | font-family: "Source Code Pro", monospace;
24 | }
25 |
26 | /* BASICS */
27 | .task-help pre code {
28 | background-color: #f7f7f7;
29 | white-space: pre-wrap;
30 | margin-bottom: 10px;
31 | padding: 5px 25px 5px 15px;
32 | display: inline-block;
33 | margin-right: 21px;
34 | }
35 |
36 | .CodeMirror {
37 | /* Set height, width, borders, and global font properties here */
38 | font-family: monospace;
39 | height: 300px;
40 | color: black;
41 | }
42 |
43 | /* PADDING */
44 |
45 | .CodeMirror-lines {
46 | padding: 4px 0; /* Vertical padding around content */
47 | }
48 | .CodeMirror pre {
49 | padding: 0 4px; /* Horizontal padding of content */
50 | }
51 |
52 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
53 | background-color: white; /* The little square between H and V scrollbars */
54 | }
55 |
56 | /* GUTTER */
57 |
58 | .CodeMirror-gutters {
59 | border-right: 1px solid #ddd;
60 | background-color: #f7f7f7;
61 | white-space: nowrap;
62 | }
63 | .CodeMirror-linenumbers {}
64 | .CodeMirror-linenumber {
65 | padding: 0 3px 0 5px;
66 | min-width: 20px;
67 | text-align: right;
68 | color: #999;
69 | white-space: nowrap;
70 | }
71 |
72 | .CodeMirror-guttermarker { color: black; }
73 | .CodeMirror-guttermarker-subtle { color: #999; }
74 |
75 | /* CURSOR */
76 |
77 | .CodeMirror-cursor {
78 | border-left: 1px solid black;
79 | border-right: none;
80 | width: 0;
81 | }
82 | /* Shown when moving in bi-directional text */
83 | .CodeMirror div.CodeMirror-secondarycursor {
84 | border-left: 1px solid silver;
85 | }
86 | .cm-fat-cursor .CodeMirror-cursor {
87 | width: auto;
88 | border: 0;
89 | background: #7e7;
90 | }
91 | .cm-fat-cursor div.CodeMirror-cursors {
92 | z-index: 1;
93 | }
94 |
95 | .cm-animate-fat-cursor {
96 | width: auto;
97 | border: 0;
98 | -webkit-animation: blink 1.06s steps(1) infinite;
99 | -moz-animation: blink 1.06s steps(1) infinite;
100 | animation: blink 1.06s steps(1) infinite;
101 | background-color: #7e7;
102 | }
103 | @-moz-keyframes blink {
104 | 0% {}
105 | 50% { background-color: transparent; }
106 | 100% {}
107 | }
108 | @-webkit-keyframes blink {
109 | 0% {}
110 | 50% { background-color: transparent; }
111 | 100% {}
112 | }
113 | @keyframes blink {
114 | 0% {}
115 | 50% { background-color: transparent; }
116 | 100% {}
117 | }
118 |
119 | /* Can style cursor different in overwrite (non-insert) mode */
120 | .CodeMirror-overwrite .CodeMirror-cursor {}
121 |
122 | .cm-tab { display: inline-block; text-decoration: inherit; }
123 |
124 | .CodeMirror-ruler {
125 | border-left: 1px solid #ccc;
126 | position: absolute;
127 | }
128 |
129 | /* DEFAULT THEME */
130 |
131 | .cm-s-default .cm-header {color: #589df6;}
132 | .cm-s-default .cm-quote {color: #6a864c;}
133 | .cm-negative {color: #d44;}
134 | .cm-positive {color: #6a864c;}
135 | .cm-header, .cm-strong {font-weight: bold;}
136 | .cm-em {font-style: italic;}
137 | .cm-link {text-decoration: underline;}
138 | .cm-strikethrough {text-decoration: line-through;}
139 |
140 | .cm-s-default .cm-keyword {color: #708;}
141 | .cm-s-default .cm-atom {color: #219;}
142 | .cm-s-default .cm-number {color: #164;}
143 | .cm-s-default .cm-def {color: #589df6;}
144 | .cm-s-default .cm-variable,
145 | .cm-s-default .cm-punctuation,
146 | .cm-s-default .cm-property,
147 | .cm-s-default .cm-operator {}
148 | .cm-s-default .cm-variable-2 {color: #05a;}
149 | .cm-s-default .cm-variable-3 {color: #085;}
150 | .cm-s-default .cm-comment {color: #a50;}
151 | .cm-s-default .cm-string {color: #a11;}
152 | .cm-s-default .cm-string-2 {color: #f50;}
153 | .cm-s-default .cm-meta {color: #555;}
154 | .cm-s-default .cm-qualifier {color: #555;}
155 | .cm-s-default .cm-builtin {color: #30a;}
156 | .cm-s-default .cm-bracket {color: #997;}
157 | .cm-s-default .cm-tag {color: #170;}
158 | .cm-s-default .cm-attribute {color: #589df6;}
159 | .cm-s-default .cm-hr {color: #999;}
160 | .cm-s-default .cm-link {color: #589df6;}
161 |
162 | .cm-s-default .cm-error {color: #f00;}
163 | .cm-invalidchar {color: #f00;}
164 |
165 | .CodeMirror-composing { border-bottom: 2px solid; }
166 |
167 | /* Default styles for common addons */
168 |
169 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
170 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
171 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
172 | .CodeMirror-activeline-background {background: #e8f2ff;}
173 |
174 | /* STOP */
175 |
176 | /* The rest of this file contains styles related to the mechanics of
177 | the editor. You probably shouldn't touch them. */
178 |
179 | .CodeMirror {
180 | position: relative;
181 | overflow: hidden;
182 | background: white;
183 | }
184 |
185 | .CodeMirror-scroll {
186 | overflow: scroll !important; /* Things will break if this is overridden */
187 | /* 30px is the magic margin used to hide the element's real scrollbars */
188 | /* See overflow: hidden in .CodeMirror */
189 | margin-bottom: -30px; margin-right: -30px;
190 | padding-bottom: 30px;
191 | height: 100%;
192 | outline: none; /* Prevent dragging from highlighting the element */
193 | position: relative;
194 | }
195 | .CodeMirror-sizer {
196 | position: relative;
197 | border-right: 30px solid transparent;
198 | }
199 |
200 | /* The fake, visible scrollbars. Used to force redraw during scrolling
201 | before actuall scrolling happens, thus preventing shaking and
202 | flickering artifacts. */
203 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
204 | position: absolute;
205 | z-index: 6;
206 | display: none;
207 | }
208 | .CodeMirror-vscrollbar {
209 | right: 0; top: 0;
210 | overflow-x: hidden;
211 | overflow-y: scroll;
212 | }
213 | .CodeMirror-hscrollbar {
214 | bottom: 0; left: 0;
215 | overflow-y: hidden;
216 | overflow-x: scroll;
217 | }
218 | .CodeMirror-scrollbar-filler {
219 | right: 0; bottom: 0;
220 | }
221 | .CodeMirror-gutter-filler {
222 | left: 0; bottom: 0;
223 | }
224 |
225 | .CodeMirror-gutters {
226 | position: absolute; left: 0; top: 0;
227 | z-index: 3;
228 | }
229 | .CodeMirror-gutter {
230 | white-space: normal;
231 | height: 100%;
232 | display: inline-block;
233 | margin-bottom: -30px;
234 | /* Hack to make IE7 behave */
235 | *zoom:1;
236 | *display:inline;
237 | }
238 | .CodeMirror-gutter-wrapper {
239 | position: absolute;
240 | z-index: 4;
241 | background: none !important;
242 | border: none !important;
243 | }
244 | .CodeMirror-gutter-background {
245 | position: absolute;
246 | top: 0; bottom: 0;
247 | z-index: 4;
248 | }
249 | .CodeMirror-gutter-elt {
250 | position: absolute;
251 | cursor: default;
252 | z-index: 4;
253 | }
254 | .CodeMirror-gutter-wrapper {
255 | -webkit-user-select: none;
256 | -moz-user-select: none;
257 | user-select: none;
258 | }
259 |
260 | .CodeMirror-lines {
261 | cursor: text;
262 | min-height: 1px; /* prevents collapsing before first draw */
263 | }
264 | .CodeMirror pre {
265 | /* Reset some styles that the rest of the page might have set */
266 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
267 | border-width: 0;
268 | background: transparent;
269 | font-family: inherit;
270 | font-size: inherit;
271 | margin: 0;
272 | white-space: pre;
273 | word-wrap: normal;
274 | line-height: inherit;
275 | color: inherit;
276 | z-index: 2;
277 | position: relative;
278 | overflow: visible;
279 | -webkit-tap-highlight-color: transparent;
280 | }
281 | .CodeMirror-wrap pre {
282 | word-wrap: break-word;
283 | white-space: pre-wrap;
284 | word-break: normal;
285 | }
286 |
287 | .CodeMirror-linebackground {
288 | position: absolute;
289 | left: 0; right: 0; top: 0; bottom: 0;
290 | z-index: 0;
291 | }
292 |
293 | .CodeMirror-linewidget {
294 | position: relative;
295 | z-index: 2;
296 | overflow: auto;
297 | }
298 |
299 | .CodeMirror-widget {}
300 |
301 | .CodeMirror-code {
302 | outline: none;
303 | }
304 |
305 | /* Force content-box sizing for the elements where we expect it */
306 | .CodeMirror-scroll,
307 | .CodeMirror-sizer,
308 | .CodeMirror-gutter,
309 | .CodeMirror-gutters,
310 | .CodeMirror-linenumber {
311 | -moz-box-sizing: content-box;
312 | box-sizing: content-box;
313 | }
314 |
315 | .CodeMirror-measure {
316 | position: absolute;
317 | width: 100%;
318 | height: 0;
319 | overflow: hidden;
320 | visibility: hidden;
321 | }
322 |
323 | .CodeMirror-cursor { position: absolute; }
324 | .CodeMirror-measure pre { position: static; }
325 |
326 | div.CodeMirror-cursors {
327 | visibility: hidden;
328 | position: relative;
329 | z-index: 3;
330 | }
331 | div.CodeMirror-dragcursors {
332 | visibility: visible;
333 | }
334 |
335 | .CodeMirror-focused div.CodeMirror-cursors {
336 | visibility: visible;
337 | }
338 |
339 | .CodeMirror-selected { background: #d9d9d9; }
340 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
341 | .CodeMirror-crosshair { cursor: crosshair; }
342 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
343 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
344 |
345 | .cm-searching {
346 | background: #ffa;
347 | background: rgba(255, 255, 0, .4);
348 | }
349 |
350 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
351 | .CodeMirror span { *vertical-align: text-bottom; }
352 |
353 | /* Used to force a border model for a node */
354 | .cm-force-border { padding-right: .1px; }
355 |
356 | @media print {
357 | /* Hide the cursor when printing */
358 | .CodeMirror div.CodeMirror-cursors {
359 | visibility: hidden;
360 | }
361 | }
362 |
363 | /* See issue #2901 */
364 | .cm-tab-wrap-hack:after { content: ''; }
365 |
366 | /* Help users use markselection to safely style text background */
367 | span.CodeMirror-selectedtext { background: none; }
--------------------------------------------------------------------------------
/resources/code-mirror/codemirror-old-darcula.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2014 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | .cm-s-default span.cm-keyword {
18 | color: #b07732;
19 | font-weight: bold;
20 | }
21 |
22 | .cm-s-default span.cm-softKeyword {
23 | color: #b07732;
24 | font-weight: bold;
25 | }
26 |
27 | .cm-s-default span.cm-atom {
28 | color: #b07732;
29 | font-weight: bold;
30 | }
31 |
32 | .cm-s-default span.cm-number {
33 | color: #b07732;
34 | }
35 |
36 | .cm-s-default span.cm-string {
37 | color: #588652;
38 | font-weight: bold;
39 | }
40 |
41 | .cm-s-default span.cm-def {
42 | color: #dddddd;
43 | }
44 |
45 | .cm-s-default span.cm-variable {
46 | color: #dddddd;
47 | }
48 |
49 | .cm-s-default span.cm-variable-2 {
50 | color: #b07732;
51 | }
52 |
53 | .cm-s-default span.cm-variable-3 {
54 | color: #dddddd;
55 | }
56 |
57 | .cm-s-default span.cm-property {
58 | color: #dddddd;
59 | }
60 |
61 | .cm-s-default span.cm-operator {
62 | color: #dddddd;
63 | }
64 |
65 | .cm-s-default span.cm-comment {
66 | color: #7f7f7f;
67 | }
68 |
69 | .cm-s-default span.cm-string-2 {
70 | color: #f50;
71 | }
72 |
73 | .cm-s-default span.cm-meta {
74 | color: #ba9d2a;
75 | }
76 |
77 | .cm-s-default span.cm-error {
78 | color: #944b5e;
79 | }
80 |
81 | .cm-s-default span.cm-qualifier {
82 | color: #555;
83 | }
84 |
85 | .cm-s-default span.cm-builtin {
86 | color: #30a;
87 | }
88 |
89 | .cm-s-default span.cm-bracket {
90 | color: #cc7;
91 | }
92 |
93 | .cm-s-default span.cm-tag {
94 | color: #ba9d2a;
95 | }
96 |
97 | .cm-s-default span.cm-attribute {
98 | color: #589df6;
99 | }
100 |
101 | .cm-s-default span.cm-header {
102 | color: #a0a;
103 | }
104 |
105 | .cm-s-default span.cm-quote {
106 | color: #6a7846;
107 | }
108 |
109 | .cm-s-default span.cm-hr {
110 | color: #999;
111 | }
112 |
113 | .cm-s-default span.cm-link {
114 | color: #589df6;
115 | }
116 |
117 | span.cm-header, span.cm-strong {
118 | font-weight: bold;
119 | }
120 |
121 | span.cm-em {
122 | font-style: italic;
123 | }
124 |
125 | span.cm-emstrong {
126 | font-style: italic;
127 | font-weight: bold;
128 | }
129 |
130 | span.cm-link {
131 | text-decoration: underline;
132 | }
133 |
134 | div.CodeMirror span.CodeMirror-matchingbracket {
135 | /*color: #0000ff;*/
136 | /*border: 1px #0000ff solid;*/
137 | /*background-color: #FFE87C;*/
138 | background-color: #e4e4ff;
139 | }
140 |
141 | div.CodeMirror span.CodeMirror-nonmatchingbracket {
142 | color: #b76b5e;
143 | }
144 |
145 | span.bullet {
146 | padding-right: 5px;
147 | }
--------------------------------------------------------------------------------
/resources/code-mirror/codemirror-old.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2014 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | .cm-s-default span.cm-keyword {
18 | color: #000080;
19 | font-weight: bold;
20 | }
21 |
22 | .cm-s-default span.cm-softKeyword {
23 | color: #336699;
24 | font-weight: bold;
25 | }
26 |
27 | .cm-s-default span.cm-atom {
28 | color: #336699;
29 | font-weight: bold;
30 | }
31 |
32 | .cm-s-default span.cm-number {
33 | color: #0000ff;
34 | }
35 |
36 | .cm-s-default span.cm-string {
37 | color: #008000;
38 | font-weight: bold;
39 | }
40 |
41 | .cm-s-default span.cm-def {
42 | color: black;
43 | }
44 |
45 | .cm-s-default span.cm-variable {
46 | color: black;
47 | }
48 |
49 | .cm-s-default span.cm-variable-2 {
50 | color: #05a;
51 | }
52 |
53 | .cm-s-default span.cm-variable-3 {
54 | color: black;
55 | }
56 |
57 | .cm-s-default span.cm-property {
58 | color: black;
59 | }
60 |
61 | .cm-s-default span.cm-operator {
62 | color: black;
63 | }
64 |
65 | .cm-s-default span.cm-comment {
66 | color: #a50;
67 | }
68 |
69 | .cm-s-default span.cm-string-2 {
70 | color: #f50;
71 | }
72 |
73 | .cm-s-default span.cm-meta {
74 | color: #008000;
75 | }
76 |
77 | .cm-s-default span.cm-error {
78 | color: #f00;
79 | }
80 |
81 | .cm-s-default span.cm-qualifier {
82 | color: #555;
83 | }
84 |
85 | .cm-s-default span.cm-builtin {
86 | color: #30a;
87 | }
88 |
89 | .cm-s-default span.cm-bracket {
90 | color: #cc7;
91 | }
92 |
93 | .cm-s-default span.cm-tag {
94 | color: #170;
95 | }
96 |
97 | .cm-s-default span.cm-attribute {
98 | color: #00c;
99 | }
100 |
101 | .cm-s-default span.cm-header {
102 | color: #a0a;
103 | }
104 |
105 | .cm-s-default span.cm-quote {
106 | color: #090;
107 | }
108 |
109 | .cm-s-default span.cm-hr {
110 | color: #999;
111 | }
112 |
113 | .cm-s-default span.cm-link {
114 | color: #00c;
115 | }
116 |
117 | span.cm-header, span.cm-strong {
118 | font-weight: bold;
119 | }
120 |
121 | span.cm-em {
122 | font-style: italic;
123 | }
124 |
125 | span.cm-emstrong {
126 | font-style: italic;
127 | font-weight: bold;
128 | }
129 |
130 | span.cm-link {
131 | text-decoration: underline;
132 | }
133 |
134 | div.CodeMirror span.CodeMirror-matchingbracket {
135 | /*color: #0000ff;*/
136 | /*border: 1px #0000ff solid;*/
137 | /*background-color: #FFE87C;*/
138 | background-color: #e4e4ff;
139 | }
140 |
141 | div.CodeMirror span.CodeMirror-nonmatchingbracket {
142 | color: #f22;
143 | }
144 |
145 | span.bullet {
146 | padding-right: 5px;
147 | }
--------------------------------------------------------------------------------
/resources/code-mirror/codemirror.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin-left: 20px;
3 | font-family: Helvetica, sans-serif;
4 | color: #4f5254;
5 | }
6 |
7 | code {
8 | font-family: "Source Code Pro", monospace;
9 | }
10 | /* BASICS */
11 | .task-help pre code {
12 | background-color: #f7f7f7;
13 | white-space: pre-wrap;
14 | margin-bottom: 10px;
15 | padding: 5px 25px 5px 15px;
16 | display: inline-block;
17 | margin-right: 21px;
18 | }
19 |
20 | .CodeMirror {
21 | /* Set height, width, borders, and global font properties here */
22 | font-family: monospace;
23 | height: 300px;
24 | color: black;
25 | }
26 |
27 | /* PADDING */
28 |
29 | .CodeMirror-lines {
30 | padding: 4px 0; /* Vertical padding around content */
31 | }
32 | .CodeMirror pre {
33 | padding: 0 4px; /* Horizontal padding of content */
34 | }
35 |
36 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
37 | background-color: white; /* The little square between H and V scrollbars */
38 | }
39 |
40 | /* GUTTER */
41 |
42 | .CodeMirror-gutters {
43 | border-right: 1px solid #ddd;
44 | background-color: #f7f7f7;
45 | white-space: nowrap;
46 | }
47 | .CodeMirror-linenumbers {}
48 | .CodeMirror-linenumber {
49 | padding: 0 3px 0 5px;
50 | min-width: 20px;
51 | text-align: right;
52 | color: #999;
53 | white-space: nowrap;
54 | }
55 |
56 | .CodeMirror-guttermarker { color: black; }
57 | .CodeMirror-guttermarker-subtle { color: #999; }
58 |
59 | /* CURSOR */
60 |
61 | .CodeMirror-cursor {
62 | border-left: 1px solid black;
63 | border-right: none;
64 | width: 0;
65 | }
66 | /* Shown when moving in bi-directional text */
67 | .CodeMirror div.CodeMirror-secondarycursor {
68 | border-left: 1px solid silver;
69 | }
70 | .cm-fat-cursor .CodeMirror-cursor {
71 | width: auto;
72 | border: 0;
73 | background: #7e7;
74 | }
75 | .cm-fat-cursor div.CodeMirror-cursors {
76 | z-index: 1;
77 | }
78 |
79 | .cm-animate-fat-cursor {
80 | width: auto;
81 | border: 0;
82 | -webkit-animation: blink 1.06s steps(1) infinite;
83 | -moz-animation: blink 1.06s steps(1) infinite;
84 | animation: blink 1.06s steps(1) infinite;
85 | background-color: #7e7;
86 | }
87 | @-moz-keyframes blink {
88 | 0% {}
89 | 50% { background-color: transparent; }
90 | 100% {}
91 | }
92 | @-webkit-keyframes blink {
93 | 0% {}
94 | 50% { background-color: transparent; }
95 | 100% {}
96 | }
97 | @keyframes blink {
98 | 0% {}
99 | 50% { background-color: transparent; }
100 | 100% {}
101 | }
102 |
103 | /* Can style cursor different in overwrite (non-insert) mode */
104 | .CodeMirror-overwrite .CodeMirror-cursor {}
105 |
106 | .cm-tab { display: inline-block; text-decoration: inherit; }
107 |
108 | .CodeMirror-ruler {
109 | border-left: 1px solid #ccc;
110 | position: absolute;
111 | }
112 |
113 | /* DEFAULT THEME */
114 |
115 | .cm-s-default .cm-header {color: blue;}
116 | .cm-s-default .cm-quote {color: #090;}
117 | .cm-negative {color: #d44;}
118 | .cm-positive {color: #292;}
119 | .cm-header, .cm-strong {font-weight: bold;}
120 | .cm-em {font-style: italic;}
121 | .cm-link {text-decoration: underline;}
122 | .cm-strikethrough {text-decoration: line-through;}
123 |
124 | .cm-s-default .cm-keyword {color: #708;}
125 | .cm-s-default .cm-atom {color: #219;}
126 | .cm-s-default .cm-number {color: #164;}
127 | .cm-s-default .cm-def {color: #00f;}
128 | .cm-s-default .cm-variable,
129 | .cm-s-default .cm-punctuation,
130 | .cm-s-default .cm-property,
131 | .cm-s-default .cm-operator {}
132 | .cm-s-default .cm-variable-2 {color: #05a;}
133 | .cm-s-default .cm-variable-3 {color: #085;}
134 | .cm-s-default .cm-comment {color: #a50;}
135 | .cm-s-default .cm-string {color: #a11;}
136 | .cm-s-default .cm-string-2 {color: #f50;}
137 | .cm-s-default .cm-meta {color: #555;}
138 | .cm-s-default .cm-qualifier {color: #555;}
139 | .cm-s-default .cm-builtin {color: #30a;}
140 | .cm-s-default .cm-bracket {color: #997;}
141 | .cm-s-default .cm-tag {color: #170;}
142 | .cm-s-default .cm-attribute {color: #00c;}
143 | .cm-s-default .cm-hr {color: #999;}
144 | .cm-s-default .cm-link {color: #00c;}
145 |
146 | .cm-s-default .cm-error {color: #f00;}
147 | .cm-invalidchar {color: #f00;}
148 |
149 | .CodeMirror-composing { border-bottom: 2px solid; }
150 |
151 | /* Default styles for common addons */
152 |
153 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
154 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
155 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
156 | .CodeMirror-activeline-background {background: #e8f2ff;}
157 |
158 | /* STOP */
159 |
160 | /* The rest of this file contains styles related to the mechanics of
161 | the editor. You probably shouldn't touch them. */
162 |
163 | .CodeMirror {
164 | position: relative;
165 | overflow: hidden;
166 | background: white;
167 | }
168 |
169 | .CodeMirror-scroll {
170 | overflow: scroll !important; /* Things will break if this is overridden */
171 | /* 30px is the magic margin used to hide the element's real scrollbars */
172 | /* See overflow: hidden in .CodeMirror */
173 | margin-bottom: -30px; margin-right: -30px;
174 | padding-bottom: 30px;
175 | height: 100%;
176 | outline: none; /* Prevent dragging from highlighting the element */
177 | position: relative;
178 | }
179 | .CodeMirror-sizer {
180 | position: relative;
181 | border-right: 30px solid transparent;
182 | }
183 |
184 | /* The fake, visible scrollbars. Used to force redraw during scrolling
185 | before actuall scrolling happens, thus preventing shaking and
186 | flickering artifacts. */
187 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
188 | position: absolute;
189 | z-index: 6;
190 | display: none;
191 | }
192 | .CodeMirror-vscrollbar {
193 | right: 0; top: 0;
194 | overflow-x: hidden;
195 | overflow-y: scroll;
196 | }
197 | .CodeMirror-hscrollbar {
198 | bottom: 0; left: 0;
199 | overflow-y: hidden;
200 | overflow-x: scroll;
201 | }
202 | .CodeMirror-scrollbar-filler {
203 | right: 0; bottom: 0;
204 | }
205 | .CodeMirror-gutter-filler {
206 | left: 0; bottom: 0;
207 | }
208 |
209 | .CodeMirror-gutters {
210 | position: absolute; left: 0; top: 0;
211 | z-index: 3;
212 | }
213 | .CodeMirror-gutter {
214 | white-space: normal;
215 | height: 100%;
216 | display: inline-block;
217 | margin-bottom: -30px;
218 | /* Hack to make IE7 behave */
219 | *zoom:1;
220 | *display:inline;
221 | }
222 | .CodeMirror-gutter-wrapper {
223 | position: absolute;
224 | z-index: 4;
225 | background: none !important;
226 | border: none !important;
227 | }
228 | .CodeMirror-gutter-background {
229 | position: absolute;
230 | top: 0; bottom: 0;
231 | z-index: 4;
232 | }
233 | .CodeMirror-gutter-elt {
234 | position: absolute;
235 | cursor: default;
236 | z-index: 4;
237 | }
238 | .CodeMirror-gutter-wrapper {
239 | -webkit-user-select: none;
240 | -moz-user-select: none;
241 | user-select: none;
242 | }
243 |
244 | .CodeMirror-lines {
245 | cursor: text;
246 | min-height: 1px; /* prevents collapsing before first draw */
247 | }
248 | .CodeMirror pre {
249 | /* Reset some styles that the rest of the page might have set */
250 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
251 | border-width: 0;
252 | background: transparent;
253 | font-family: inherit;
254 | font-size: inherit;
255 | margin: 0;
256 | white-space: pre;
257 | word-wrap: normal;
258 | line-height: inherit;
259 | color: inherit;
260 | z-index: 2;
261 | position: relative;
262 | overflow: visible;
263 | -webkit-tap-highlight-color: transparent;
264 | }
265 | .CodeMirror-wrap pre {
266 | word-wrap: break-word;
267 | white-space: pre-wrap;
268 | word-break: normal;
269 | }
270 |
271 | .CodeMirror-linebackground {
272 | position: absolute;
273 | left: 0; right: 0; top: 0; bottom: 0;
274 | z-index: 0;
275 | }
276 |
277 | .CodeMirror-linewidget {
278 | position: relative;
279 | z-index: 2;
280 | overflow: auto;
281 | }
282 |
283 | .CodeMirror-widget {}
284 |
285 | .CodeMirror-code {
286 | outline: none;
287 | }
288 |
289 | /* Force content-box sizing for the elements where we expect it */
290 | .CodeMirror-scroll,
291 | .CodeMirror-sizer,
292 | .CodeMirror-gutter,
293 | .CodeMirror-gutters,
294 | .CodeMirror-linenumber {
295 | -moz-box-sizing: content-box;
296 | box-sizing: content-box;
297 | }
298 |
299 | .CodeMirror-measure {
300 | position: absolute;
301 | width: 100%;
302 | height: 0;
303 | overflow: hidden;
304 | visibility: hidden;
305 | }
306 |
307 | .CodeMirror-cursor { position: absolute; }
308 | .CodeMirror-measure pre { position: static; }
309 |
310 | div.CodeMirror-cursors {
311 | visibility: hidden;
312 | position: relative;
313 | z-index: 3;
314 | }
315 | div.CodeMirror-dragcursors {
316 | visibility: visible;
317 | }
318 |
319 | .CodeMirror-focused div.CodeMirror-cursors {
320 | visibility: visible;
321 | }
322 |
323 | .CodeMirror-selected { background: #d9d9d9; }
324 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
325 | .CodeMirror-crosshair { cursor: crosshair; }
326 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
327 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
328 |
329 | .cm-searching {
330 | background: #ffa;
331 | background: rgba(255, 255, 0, .4);
332 | }
333 |
334 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
335 | .CodeMirror span { *vertical-align: text-bottom; }
336 |
337 | /* Used to force a border model for a node */
338 | .cm-force-border { padding-right: .1px; }
339 |
340 | @media print {
341 | /* Hide the cursor when printing */
342 | .CodeMirror div.CodeMirror-cursors {
343 | visibility: hidden;
344 | }
345 | }
346 |
347 | /* See issue #2901 */
348 | .cm-tab-wrap-hack:after { content: ''; }
349 |
350 | /* Help users use markselection to safely style text background */
351 | span.CodeMirror-selectedtext { background: none; }
--------------------------------------------------------------------------------
/resources/code-mirror/colorize.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"), require("./runmode"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror", "./runmode"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/;
15 |
16 | function textContent(node, out) {
17 | if (node.nodeType == 3) return out.push(node.nodeValue);
18 | for (var ch = node.firstChild; ch; ch = ch.nextSibling) {
19 | textContent(ch, out);
20 | if (isBlock.test(node.nodeType)) out.push("\n");
21 | }
22 | }
23 |
24 | CodeMirror.colorize = function(collection, defaultMode) {
25 | if (!collection) collection = document.body.getElementsByTagName("pre");
26 |
27 | for (var i = 0; i < collection.length; ++i) {
28 | var node = collection[i];
29 | var mode = node.getAttribute("data-lang") || defaultMode;
30 | if (!mode) continue;
31 |
32 | var text = [];
33 | textContent(node, text);
34 | node.innerHTML = "";
35 | CodeMirror.runMode(text.join(""), mode, node);
36 |
37 | node.className += " cm-s-default";
38 | }
39 | };
40 | });
41 |
--------------------------------------------------------------------------------
/resources/code-mirror/runmode.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.runMode = function(string, modespec, callback, options) {
15 | var mode = CodeMirror.getMode(CodeMirror.defaults, modespec);
16 | var ie = /MSIE \d/.test(navigator.userAgent);
17 | var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
18 |
19 | if (callback.appendChild) {
20 | var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize;
21 | var node = callback, col = 0;
22 | node.innerHTML = "";
23 | callback = function(text, style) {
24 | if (text == "\n") {
25 | // Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
26 | // Emitting a carriage return makes everything ok.
27 | node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text));
28 | col = 0;
29 | return;
30 | }
31 | var content = "";
32 | // replace tabs
33 | for (var pos = 0;;) {
34 | var idx = text.indexOf("\t", pos);
35 | if (idx == -1) {
36 | content += text.slice(pos);
37 | col += text.length - pos;
38 | break;
39 | } else {
40 | col += idx - pos;
41 | content += text.slice(pos, idx);
42 | var size = tabSize - col % tabSize;
43 | col += size;
44 | for (var i = 0; i < size; ++i) content += " ";
45 | pos = idx + 1;
46 | }
47 | }
48 |
49 | if (style) {
50 | var sp = node.appendChild(document.createElement("span"));
51 | sp.className = "cm-" + style.replace(/ +/g, " cm-");
52 | sp.appendChild(document.createTextNode(content));
53 | } else {
54 | node.appendChild(document.createTextNode(content));
55 | }
56 | };
57 | }
58 |
59 | var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode);
60 | for (var i = 0, e = lines.length; i < e; ++i) {
61 | if (i) callback("\n");
62 | var stream = new CodeMirror.StringStream(lines[i]);
63 | if (!stream.string && mode.blankLine) mode.blankLine(state);
64 | while (!stream.eol()) {
65 | var style = mode.token(stream, state);
66 | callback(stream.current(), style, i, stream.start, state);
67 | stream.start = stream.pos;
68 | }
69 | }
70 | };
71 |
72 | });
73 |
--------------------------------------------------------------------------------
/resources/code-mirror/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
28 |
29 |
36 |
39 |
40 |
41 |
42 | ${code}
43 |
48 |
49 |
--------------------------------------------------------------------------------
/resources/icons/download_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StepicOrg/intellij-plugin/844e500b7e4793b8db110a5cbd91b53a1464ea71/resources/icons/download_blue.png
--------------------------------------------------------------------------------
/resources/icons/stepik_logo_green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StepicOrg/intellij-plugin/844e500b7e4793b8db110a5cbd91b53a1464ea71/resources/icons/stepik_logo_green.png
--------------------------------------------------------------------------------
/resources/icons/stepik_logotype_13x13-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StepicOrg/intellij-plugin/844e500b7e4793b8db110a5cbd91b53a1464ea71/resources/icons/stepik_logotype_13x13-2.png
--------------------------------------------------------------------------------
/resources/style/javaFXBrowserDarcula.css:
--------------------------------------------------------------------------------
1 | ::-webkit-scrollbar-corner {
2 | background-color: #3c3f41;
3 | }
4 |
5 | body {
6 | background-color: #3c3f41;
7 | color: #bababa
8 | }
9 |
10 | p img {
11 | background-color: #bababa;
12 | }
13 |
14 | textarea {
15 | background-color: #3c3f41;
16 | color: #bababa
17 | }
18 |
19 | a {
20 | color: #589df6
21 | }
22 |
23 | tr {
24 | text-align: left
25 | }
--------------------------------------------------------------------------------
/resources/style/javaFXBrowserDarculaScrollBar.css:
--------------------------------------------------------------------------------
1 |
2 | .scroll-bar{
3 | -fx-background-color: #3c3f41;
4 | -fx-background-radius: 2em;
5 | }
6 | .scroll-bar:horizontal .track,
7 | .scroll-bar:vertical .track {
8 | -fx-background-color: #3c3f41;
9 | -fx-border-color:transparent;
10 | -fx-background-radius: 2em;
11 | }
12 | .scroll-bar:vertical .track-background,
13 | .scroll-bar:horizontal .track-background {
14 | -fx-background-color: #3c3f41;
15 | }
16 | .scroll-bar:horizontal .thumb {
17 | -fx-background-color: #bbbbbb;
18 | -fx-background-insets: 4 0 4 0;
19 | -fx-background-radius: 2em;
20 | -fx-opacity: 0.2;
21 | }
22 | .scroll-bar:vertical .thumb {
23 | -fx-background-color: #bbbbbb;
24 | -fx-background-insets: 0 4 0 4;
25 | -fx-background-radius: 2em;
26 | -fx-opacity: 0.2;
27 | }
28 |
29 |
30 | .scroll-bar:vertical:corner-present {
31 | -fx-shape: " ";
32 | -fx-width: 0;
33 | }
34 |
35 | .scroll-bar:horizontal:corner-present {
36 | -fx-shape: " ";
37 | -fx-width: 0;
38 | }
39 |
40 | .scroll-bar-corner {
41 | -fx-background-color: #3c3f41;
42 | }
43 | .scroll-bar:horizontal .increment-arrow {
44 | -fx-shape: " "
45 | }
46 | .scroll-bar:vertical .increment-arrow {
47 | -fx-shape: " "
48 | }
49 | .scroll-bar:horizontal .decrement-arrow {
50 | -fx-shape: " "
51 | }
52 | .scroll-bar:vertical .decrement-arrow {
53 | -fx-shape: " "
54 | }
55 |
56 |
57 |
--------------------------------------------------------------------------------
/resources/style/javaFXBrowserScrollBar.css:
--------------------------------------------------------------------------------
1 |
2 | .scroll-bar{
3 | -fx-background-color: #ffffff;
4 | -fx-background-radius: 2em;
5 | }
6 | .scroll-bar:horizontal .track,
7 | .scroll-bar:vertical .track {
8 | -fx-background-color: #ffffff;
9 | -fx-border-color:transparent;
10 | -fx-background-radius: 2em;
11 | }
12 | .scroll-bar:vertical .track-background,
13 | .scroll-bar:horizontal .track-background {
14 | -fx-background-color: #ffffff;
15 | }
16 | .scroll-bar:horizontal .thumb {
17 | -fx-background-color: #dddddd;
18 | -fx-background-insets: 4 0 4 0;
19 | -fx-background-radius: 2em;
20 | }
21 | .scroll-bar:vertical .thumb {
22 | -fx-background-color: #dddddd;
23 | -fx-background-insets: 0 4 0 4;
24 | -fx-background-radius: 2em;
25 | }
26 |
27 | .scroll-bar:vertical:corner-present {
28 | -fx-shape: " ";
29 | -fx-width: 0;
30 | }
31 |
32 | .scroll-bar:horizontal:corner-present {
33 | -fx-shape: " ";
34 | -fx-width: 0;
35 | }
36 |
37 | .scroll-bar-corner {
38 | -fx-background-color: #ffffff;
39 | }
40 | .scroll-bar:horizontal .increment-arrow {
41 | -fx-shape: " "
42 | }
43 | .scroll-bar:vertical .increment-arrow {
44 | -fx-shape: " "
45 | }
46 | .scroll-bar:horizontal .decrement-arrow {
47 | -fx-shape: " "
48 | }
49 | .scroll-bar:vertical .decrement-arrow {
50 | -fx-shape: " "
51 | }
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/Help.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.ui.Messages;
5 |
6 | public class Help extends MainMenuAction {
7 |
8 | private static String text = "Stepik plugin for code challenges on Java.\n" +
9 | "\n" +
10 | "To work with plugin you must to create a project of Stepik type.\n" +
11 | "You need to enter login and password your Stepik account.\n" +
12 | "And then input course URL or course number.\n" +
13 | "After twenty seconds course will be built.\n" +
14 | "\n" +
15 | "To send task click the left mouse button on file. In the shortcut menu choose \"Submit Solution\".\n" +
16 | "In the same way you can to download last submissions and get the status of step.\n" +
17 | "\n" +
18 | "\"Who am I\" -- returns your user_name.\n" +
19 | "\"Update course\" -- download new lessons.\n" +
20 | "\n\n--------------------------------------\n\n" +
21 | "Stepik плагин для решения задач на программирование на языке Java.\n" +
22 | "\n" +
23 | "Для работы с плагином необходимо создать проект типа Stepik.\n" +
24 | "Ввести логин и пароль от аккаунта.\n" +
25 | "Затем ввести ссылку на курс или его номер.\n" +
26 | "Через двадцать секунд проект будет построен.\n" +
27 | "\n" +
28 | "Для отправки задачи кликните левой кнопкой мыши на файле. В контекстном меню выберете \"Submit Solution\".\n" +
29 | "Тем же способом вы можете загрузить последний отправленный вариант или узнать статус задачи.\n" +
30 | "\n" +
31 | "\"Who am I\" -- возвращает user_name.\n" +
32 | "\"Update course\" -- загружает новые уроки.\n";
33 |
34 | @Override
35 | public void actionPerformed(AnActionEvent e) {
36 | Messages.showMessageDialog(e.getProject(), text, "Information", Messages.getInformationIcon());
37 | }
38 |
39 | @Override
40 | public void update(AnActionEvent e) {
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/MainMenuAction.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import org.stepik.plugin.storages.ActionVisibleProperties;
6 |
7 | public abstract class MainMenuAction extends AnAction {
8 | @Override
9 | public void update(AnActionEvent e) {
10 | ActionVisibleProperties properties = ActionVisibleProperties.getInstance(e.getProject());
11 | e.getPresentation().setEnabled(properties.isEnabled());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/NegTranslator.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.ui.Messages;
5 | import org.stepik.plugin.storages.CourseDefinitionStorage;
6 |
7 | /**
8 | * Created by Petr on 03.06.2016.
9 | */
10 | public class NegTranslator extends MainMenuAction {
11 |
12 | @Override
13 | public void actionPerformed(AnActionEvent e) {
14 | CourseDefinitionStorage ws = CourseDefinitionStorage.getInstance(e.getProject());
15 |
16 | ws.setTranslate(!ws.isTranslate());
17 | Messages.showMessageDialog(e.getProject(), Boolean.toString(ws.isTranslate()), "Information", Messages.getInformationIcon());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/PrintMapInfo.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.openapi.ui.Messages;
6 | import org.stepik.plugin.modules.StepInfo;
7 | import org.stepik.plugin.storages.CourseDefinitionStorage;
8 |
9 | import java.util.Map;
10 |
11 | public class PrintMapInfo extends MainMenuAction {
12 |
13 | @Override
14 | public void actionPerformed(AnActionEvent e) {
15 | Project project = e.getProject();
16 |
17 | CourseDefinitionStorage ws = CourseDefinitionStorage.getInstance(e.getProject());
18 | final String[] text = {""};
19 |
20 | Map map = ws.getMapPathInfo();
21 | if (map == null) {
22 | Messages.showMessageDialog(project, "path--step is null", "Information", Messages.getInformationIcon());
23 | } else {
24 | map.keySet().forEach((x) -> text[0] += x + "\n");
25 | Messages.showMessageDialog(project, text[0], "Information", Messages.getInformationIcon());
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/RefreshMap.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.project.Project;
5 | import org.stepik.plugin.utils.Utils;
6 |
7 | public class RefreshMap extends MainMenuAction {
8 |
9 | @Override
10 | public void actionPerformed(AnActionEvent e) {
11 | Project project = e.getProject();
12 | Utils.refreshFiles(project);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/RefreshToken.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import org.stepik.plugin.stepikConnector.StepikConnector;
5 |
6 | public class RefreshToken extends MainMenuAction {
7 |
8 | @Override
9 | public void actionPerformed(AnActionEvent e) {
10 | StepikConnector.initToken(e.getProject());
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/SignIn.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.ui.Messages;
7 | import org.stepik.plugin.stepikConnector.StepikConnector;
8 |
9 | public class SignIn extends MainMenuAction {
10 |
11 | @Override
12 | public void actionPerformed(AnActionEvent e) {
13 | Project project = e.getData(PlatformDataKeys.PROJECT);
14 |
15 | String login =
16 | Messages.showInputDialog(project, "Please, input your E-mail", "Sing in", Messages.getQuestionIcon());
17 | String password =
18 | Messages.showPasswordDialog(project, "Please, input your Password", "Sing in", Messages.getQuestionIcon());
19 |
20 | StepikConnector.setLoginAndPassword(login, password, project);
21 | StepikConnector.initToken(e.getProject());
22 | String name = StepikConnector.getUserName(project);
23 |
24 | Messages.showMessageDialog(project, "Hello, " + name + "!\n I am glad to see you.", "Information", Messages.getInformationIcon());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/SomeAction.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.actionSystem.CommonDataKeys;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.vfs.VirtualFile;
7 | import com.intellij.psi.PsiFile;
8 | import com.intellij.psi.PsiManager;
9 | import com.intellij.refactoring.RefactoringFactory;
10 | import com.intellij.refactoring.RenameRefactoring;
11 |
12 | public class SomeAction extends MainMenuAction {
13 |
14 | @Override
15 | public void actionPerformed(AnActionEvent e) {
16 | Project project = e.getProject();
17 | VirtualFile vf = e.getData(CommonDataKeys.VIRTUAL_FILE);
18 | if (vf == null) return;
19 |
20 | PsiFile psi = PsiManager.getInstance(project).findFile(vf);
21 | RenameRefactoring rr = RefactoringFactory.getInstance(project).createRename(psi, "step");
22 |
23 | psi.setName("Abra");
24 |
25 |
26 | }
27 |
28 |
29 | public void update(AnActionEvent anActionEvent) {
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/UpdateCourse.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.diagnostic.Logger;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.ui.Messages;
7 | import com.intellij.openapi.vfs.LocalFileSystem;
8 | import com.intellij.openapi.vfs.VirtualFile;
9 | import org.stepik.plugin.modules.Course;
10 | import org.stepik.plugin.modules.StepInfo;
11 | import org.stepik.plugin.projectWizard.StepikModuleBuilder;
12 | import org.stepik.plugin.stepikConnector.StepikConnector;
13 | import org.stepik.plugin.storages.ActionVisibleProperties;
14 | import org.stepik.plugin.storages.CourseDefinitionStorage;
15 | import org.stepik.plugin.storages.StepikApplicationStorage;
16 | import org.stepik.plugin.utils.Utils;
17 |
18 | import java.io.File;
19 | import java.io.IOException;
20 | import java.nio.charset.Charset;
21 | import java.nio.file.Files;
22 | import java.nio.file.Path;
23 | import java.nio.file.Paths;
24 | import java.util.HashMap;
25 | import java.util.HashSet;
26 | import java.util.Map;
27 | import java.util.Set;
28 |
29 | public class UpdateCourse extends MainMenuAction {
30 | private static final Logger LOG = Logger.getInstance(UpdateCourse.class);
31 | private static String success = "Course is successfully updated.";
32 | private static String error = "Course was not updated.";
33 | private static String old = "No new lessons.";
34 | private static String nnew = "New lessons are created.";
35 | private static String course_is_broken = "Your course_no is broke.\nPlease insert correct course_no or course_link.";
36 | private static String login_is_broken = "Your login is broke.\nPlease insert your e-mail on Stepik account.";
37 | private static String password_is_broken = "Your password is broke.\nPlease insert your password on Stepik account.";
38 |
39 | @Override
40 | public void actionPerformed(AnActionEvent e) {
41 | final Project project = e.getProject();
42 |
43 | final VirtualFile root = project.getBaseDir();
44 | CourseDefinitionStorage projectService = CourseDefinitionStorage.getInstance(project);
45 | String courseID = projectService.getCourseID();
46 | String login = StepikConnector.getLogin(project);
47 | projectService.setProjectName(project.getName());
48 |
49 |
50 | ActionVisibleProperties prop = ActionVisibleProperties.getInstance(project);
51 | if (isCourseBroke(courseID, login) || !prop.isVisible()) {
52 | if (Messages.showYesNoDialog(project, "Your project of course is broke.\nDo you want to repair it?", "Repair", Messages.getQuestionIcon()) == 0) {
53 | if (courseID == null || courseID.isEmpty()) {
54 | repairCourseID(project);
55 | }
56 |
57 | if (login == null || login.isEmpty()) {
58 | repairLoginAndPassword(project);
59 | }
60 |
61 | prop.setEnabled(true);
62 | prop.setVisible(true);
63 | } else {
64 | return;
65 | }
66 | }
67 | StepikConnector.initToken(project);
68 |
69 |
70 | Map map;
71 | Set newFiles = new HashSet<>();
72 | Course course = StepikConnector.getCourse(courseID, project);
73 |
74 | Utils.refreshFiles(project);
75 | map = new HashMap<>(projectService.getMapPathInfo());
76 | course.build(root.getPath(), project);
77 |
78 | projectService.mapPathInfo.entrySet().forEach(x -> {
79 | if (!map.containsKey(x.getKey())) {
80 | String path = x.getKey();
81 | StepInfo stepInfo = x.getValue();
82 |
83 | File file = new File(path);
84 | if (!file.exists()) {
85 | file.getParentFile().mkdirs();
86 | newFiles.add(path);
87 | try {
88 | Path path1 = Paths.get(path);
89 | Files.write(path1, StepikModuleBuilder.getText(stepInfo.getFilename(), stepInfo.getPackageName()), Charset.forName("UTF-8"));
90 | } catch (IOException ex) {
91 | LOG.error("Create file error\n" + ex.getMessage());
92 | }
93 | }
94 | }
95 | });
96 |
97 | LocalFileSystem.getInstance().refresh(true);
98 |
99 | StringBuilder sb = new StringBuilder();
100 | sb.append(success + "\n");
101 | if (newFiles.isEmpty()) {
102 | sb.append(old);
103 | } else {
104 | sb.append(nnew);
105 | }
106 | Messages.showMessageDialog(project, sb.toString(), "Information", Messages.getInformationIcon());
107 |
108 | }
109 |
110 | private boolean isCourseBroke(String courseID, String login) {
111 | return courseID == null || courseID.isEmpty() || login == null || login.isEmpty();
112 | }
113 |
114 | private void repairCourseID(Project project) {
115 | CourseDefinitionStorage projectService = CourseDefinitionStorage.getInstance(project);
116 | String courseID = Messages.showInputDialog(project, course_is_broken, "Repair", Messages.getQuestionIcon());
117 | courseID = Utils.parseUrl(courseID);
118 | boolean translate = Messages.showYesNoDialog(project, "Do you want to translate package names?", "Translator", Messages.getQuestionIcon()) == 0;
119 | projectService.setCourseID(courseID);
120 | projectService.setTranslate(translate);
121 | ActionVisibleProperties prop = ActionVisibleProperties.getInstance(project);
122 | prop.setEnabled(true);
123 | prop.setVisible(true);
124 | }
125 |
126 | private void repairLoginAndPassword(Project project) {
127 | String login = Messages.showInputDialog(project, login_is_broken, "Repair", Messages.getQuestionIcon(), StepikApplicationStorage.getInstance().getLogin(), null);
128 |
129 | if (StepikConnector.isPasswordSet(project)) {
130 | String password = Messages.showInputDialog(project, password_is_broken, "Repair", Messages.getQuestionIcon());
131 | StepikConnector.setLoginAndPassword(login, password, project);
132 | } else {
133 | StepikConnector.setLogin(login, project);
134 | }
135 | }
136 |
137 | @Override
138 | public void update(AnActionEvent e) {
139 | // super.update(e);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/mainMenu/WhoAmI.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.mainMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.diagnostic.Logger;
7 | import com.intellij.openapi.project.Project;
8 | import com.intellij.openapi.ui.Messages;
9 | import org.stepik.plugin.stepikConnector.StepikConnector;
10 |
11 | public class WhoAmI extends MainMenuAction {
12 | private static final Logger LOG = Logger.getInstance(AnAction.class);
13 |
14 | @Override
15 | public void actionPerformed(AnActionEvent e) {
16 |
17 | Project project = e.getData(PlatformDataKeys.PROJECT);
18 | String login = StepikConnector.getLogin(project);
19 | String name = null;
20 | name = StepikConnector.getUserName(project);
21 | Messages.showMessageDialog(project, "Hello, " + name + "!\n I am glad to see you.", "Information", Messages.getInformationIcon());
22 |
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/popupMenu/DownloadLastSubmission.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.popupMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.actionSystem.CommonDataKeys;
5 | import com.intellij.openapi.application.ApplicationManager;
6 | import com.intellij.openapi.command.CommandProcessor;
7 | import com.intellij.openapi.editor.Document;
8 | import com.intellij.openapi.fileEditor.FileDocumentManager;
9 | import com.intellij.openapi.project.Project;
10 | import com.intellij.openapi.vfs.VirtualFile;
11 | import org.stepik.plugin.modules.Submission;
12 | import org.stepik.plugin.stepikConnector.StepikConnector;
13 | import org.stepik.plugin.storages.CourseDefinitionStorage;
14 | import org.stepik.plugin.utils.NotificationTemplates;
15 | import org.stepik.plugin.utils.NotificationUtils;
16 |
17 | import java.util.HashSet;
18 | import java.util.List;
19 | import java.util.Set;
20 |
21 | public class DownloadLastSubmission extends PopupMenuAction {
22 |
23 | @Override
24 | public void actionPerformed(AnActionEvent e) {
25 | Project project = e.getProject();
26 | VirtualFile vf = e.getData(CommonDataKeys.VIRTUAL_FILE);
27 | if (vf == null) return;
28 |
29 | CourseDefinitionStorage projectService = CourseDefinitionStorage.getInstance(project);
30 | String stepName = vf.getName().split("\\.")[0];
31 |
32 | List submissions =
33 | StepikConnector.getSubmissions(projectService.getStepID(vf.getPath()), project);
34 |
35 | if (submissions.isEmpty()) {
36 | NotificationUtils.showNotification(NotificationTemplates.DOWNLOAD_WARNING, project);
37 | } else {
38 | String code = submissions.get(submissions.size() - 1).getCode();
39 | String pack = CourseDefinitionStorage.getInstance(project).getPackageName(vf.getPath());
40 | Document doc = FileDocumentManager.getInstance().getDocument(vf);
41 | String code2 = renameFromMainToStep(code, stepName, pack);
42 | CommandProcessor.getInstance().executeCommand(project,
43 | () -> ApplicationManager.getApplication().runWriteAction(
44 | () -> {
45 | doc.setText(code2);
46 | }), "Download last submission", "Download last submission");
47 | }
48 | }
49 |
50 | private String renameFromMainToStep(String code, String stepName, String ppackage) {
51 | String[] lines = code.split("\n");
52 |
53 | Set skipLine = new HashSet<>();
54 | for (int i = 0; i < lines.length; i++) {
55 | if (lines[i].contains("// Sent from IntelliJ IDEA")) skipLine.add(i);
56 | if (lines[i].contains("package")) skipLine.add(i);
57 | if (lines[i].contains("class Main")) {
58 | lines[i] = "class " + stepName + " {";
59 | break;
60 | }
61 | }
62 |
63 | StringBuilder sb = new StringBuilder();
64 | sb.append("package " + ppackage + ";\n\n");
65 | for (int i = 0; i < lines.length; i++) {
66 | if (skipLine.contains(i)) continue;
67 | sb.append(lines[i] + "\n");
68 | }
69 | return sb.toString();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/popupMenu/GetIdStep.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.popupMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.actionSystem.CommonDataKeys;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.ui.Messages;
7 | import com.intellij.openapi.vfs.VirtualFile;
8 | import org.stepik.plugin.storages.CourseDefinitionStorage;
9 |
10 | /**
11 | * Created by Petr on 21.05.2016.
12 | */
13 | public class GetIdStep extends PopupMenuAction {
14 |
15 | @Override
16 | public void actionPerformed(AnActionEvent e) {
17 | Project project = e.getProject();
18 | VirtualFile vf = e.getData(CommonDataKeys.VIRTUAL_FILE);
19 | if (vf == null) return;
20 |
21 | CourseDefinitionStorage projectService = CourseDefinitionStorage.getInstance(project);
22 | String stepId = projectService.getStepID(vf.getPath());
23 | Messages.showMessageDialog(project, stepId, "Information", Messages.getInformationIcon());
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/popupMenu/GetStepStatus.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.popupMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.actionSystem.CommonDataKeys;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.ui.Messages;
7 | import com.intellij.openapi.util.Pair;
8 | import com.intellij.openapi.vfs.VirtualFile;
9 | import org.stepik.plugin.stepikConnector.StepikConnector;
10 | import org.stepik.plugin.storages.CourseDefinitionStorage;
11 |
12 | public class GetStepStatus extends PopupMenuAction {
13 |
14 | @Override
15 | public void actionPerformed(AnActionEvent e) {
16 | Project project = e.getProject();
17 | VirtualFile vf = e.getData(CommonDataKeys.VIRTUAL_FILE);
18 | if (vf == null) return;
19 |
20 | String path = vf.getPath();
21 | CourseDefinitionStorage projectService = CourseDefinitionStorage.getInstance(project);
22 | String stepId = projectService.getStepID(path);
23 |
24 | String ans;
25 |
26 |
27 | if (wasItSolved(stepId, project)) {
28 | ans = "Step was solved\n";
29 | } else {
30 | ans = "Step wasn't solved\n";
31 | }
32 |
33 | ans += "last submission from IDEA is ";
34 | String subID = projectService.getSubmissionID(path);
35 | if (subID.isEmpty()) {
36 | ans += "unknown";
37 | } else {
38 | ans += StepikConnector.getStatus(subID, project).get(0).getStatus();
39 | }
40 |
41 |
42 | Messages.showMessageDialog(project, ans, "Information", Messages.getInformationIcon());
43 | }
44 |
45 | private boolean wasItSolved(String stepID, Project project) {
46 | int size = StepikConnector.getStepStatus(stepID, Pair.pair("status", "correct"), project).size();
47 | return size > 0;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/popupMenu/PopupMenuAction.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.popupMenu;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.CommonDataKeys;
6 | import com.intellij.openapi.vfs.VirtualFile;
7 | import org.stepik.plugin.storages.ActionVisibleProperties;
8 |
9 | public abstract class PopupMenuAction extends AnAction {
10 |
11 | @Override
12 | public void update(AnActionEvent anActionEvent) {
13 | VirtualFile vf = anActionEvent.getData(CommonDataKeys.VIRTUAL_FILE);
14 | if (vf == null) return;
15 |
16 | ActionVisibleProperties properties = ActionVisibleProperties.getInstance(anActionEvent.getProject());
17 | anActionEvent.getPresentation().setVisible(properties.isVisible() && !vf.isDirectory());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/actions/popupMenu/SendFile.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.actions.popupMenu;
2 |
3 | import com.intellij.notification.Notification;
4 | import com.intellij.notification.NotificationType;
5 | import com.intellij.openapi.actionSystem.AnActionEvent;
6 | import com.intellij.openapi.actionSystem.CommonDataKeys;
7 | import com.intellij.openapi.application.Application;
8 | import com.intellij.openapi.application.ApplicationManager;
9 | import com.intellij.openapi.editor.Document;
10 | import com.intellij.openapi.fileEditor.FileDocumentManager;
11 | import com.intellij.openapi.project.Project;
12 | import com.intellij.openapi.ui.Messages;
13 | import com.intellij.openapi.vfs.VirtualFile;
14 | import org.stepik.plugin.modules.Submission;
15 | import org.stepik.plugin.stepikConnector.StepikConnector;
16 | import org.stepik.plugin.storages.CourseDefinitionStorage;
17 | import org.stepik.plugin.utils.MyLogger;
18 | import org.stepik.plugin.utils.NotificationUtils;
19 |
20 | import java.util.HashSet;
21 | import java.util.List;
22 | import java.util.Set;
23 |
24 | public class SendFile extends PopupMenuAction {
25 | private static String success = "the Step successfully sent";
26 | private static String error = "the Step is not sent";
27 |
28 | @Override
29 | public void actionPerformed(AnActionEvent event) {
30 | Project project = event.getProject();
31 | VirtualFile vf = event.getData(CommonDataKeys.VIRTUAL_FILE);
32 | if (vf == null) return;
33 |
34 | CourseDefinitionStorage projectService = CourseDefinitionStorage.getInstance(project);
35 | String stepId = projectService.getStepID(vf.getPath());
36 |
37 | String text = renameMainClass(vf);
38 | String path = vf.getPath();
39 |
40 | String attemptId = StepikConnector.getAttemptId(stepId, project);
41 | String submissionId = StepikConnector.sendFile(text, attemptId, project);
42 |
43 | MyLogger.getInstance().getLOG().debug("attId = " + attemptId);
44 | MyLogger.getInstance().getLOG().debug("subId = " + submissionId);
45 |
46 | projectService.setAttemptID(path, attemptId);
47 | projectService.setSubmissionID(path, submissionId);
48 | Messages.showMessageDialog(project, success, "Information", Messages.getInformationIcon());
49 |
50 | String filename = projectService.getFilename(path);
51 | final Application application = ApplicationManager.getApplication();
52 | final String finalSubmissionId = submissionId;
53 | application.executeOnPooledThread(
54 | () -> {
55 | String ans = "evaluation";
56 | final int TIMER = 2;
57 | int count = 0;
58 | Notification notification = null;
59 | List list = null;
60 | String b = "";
61 | while (ans.equals("evaluation") && count < 100) {
62 | try {
63 | Thread.sleep(TIMER * 1000); //1000 milliseconds is one second.
64 | list = StepikConnector.getStatus(finalSubmissionId, project);
65 | if (list != null) {
66 | ans = list.get(0).getStatus();
67 | b = list.get(0).getHint();
68 | }
69 | count += TIMER;
70 | } catch (InterruptedException | NullPointerException e) {
71 | notification = new Notification("Step.sending", "Error", "Get Status error", NotificationType.ERROR);
72 | NotificationUtils.showNotification(notification, project);
73 | return;
74 | }
75 | }
76 |
77 | NotificationType notificationType;
78 |
79 | if (ans.equals("correct")) {
80 | notificationType = NotificationType.INFORMATION;
81 | b = "Success!";
82 | } else {
83 | notificationType = NotificationType.WARNING;
84 | b = b.split("\\.")[0];
85 | }
86 | notification = new Notification("Step.sending", filename + " is " + ans, b, notificationType);
87 | NotificationUtils.showNotification(notification, project);
88 | }
89 | );
90 | }
91 |
92 | private String renameMainClass(VirtualFile vf) {
93 | Document doc = FileDocumentManager.getInstance().getDocument(vf);
94 | String[] lines = doc.getText().split("\n");
95 |
96 | Set skipLine = new HashSet<>();
97 | for (int i = 0; i < lines.length; i++) {
98 | if (lines[i].contains("// Sent from IntelliJ IDEA")) skipLine.add(i);
99 | if (lines[i].contains("package")) skipLine.add(i);
100 | if (lines[i].contains("class Step")) {
101 | lines[i] = "class Main {";
102 | break;
103 | }
104 | }
105 |
106 | StringBuilder sb = new StringBuilder();
107 | sb.append("// Sent from IntelliJ IDEA");
108 | for (int i = 0; i < lines.length; i++) {
109 | if (skipLine.contains(i)) continue;
110 | sb.append(lines[i] + "\n");
111 | }
112 | return sb.toString();
113 | }
114 |
115 | @Override
116 | public void setDefaultIcon(boolean isDefaultIconSet) {
117 | super.setDefaultIcon(isDefaultIconSet);
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/components/MyModuleComponent.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.components;
2 |
3 | import com.intellij.openapi.module.Module;
4 | import com.intellij.openapi.module.ModuleComponent;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | public class MyModuleComponent implements ModuleComponent {
8 | public MyModuleComponent(Module module) {
9 | }
10 |
11 | @Override
12 | public void initComponent() {
13 | // TODO: insert component initialization logic here
14 | }
15 |
16 | @Override
17 | public void disposeComponent() {
18 | // TODO: insert component disposal logic here
19 | }
20 |
21 | @Override
22 | @NotNull
23 | public String getComponentName() {
24 | return "MyModuleComponent";
25 | }
26 |
27 | @Override
28 | public void projectOpened() {
29 | // called when project is opened
30 | }
31 |
32 | @Override
33 | public void projectClosed() {
34 | // called when project is being closed
35 | }
36 |
37 | @Override
38 | public void moduleAdded() {
39 | // Invoked when the module corresponding to this component instance has been completely
40 | // loaded and added to the project.
41 | }
42 |
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/components/MyProjectComponent.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.components;
2 |
3 | import com.intellij.openapi.components.ProjectComponent;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.openapi.wm.ToolWindow;
6 | import com.intellij.openapi.wm.ToolWindowAnchor;
7 | import com.intellij.openapi.wm.ToolWindowManager;
8 | import javafx.application.Platform;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.stepik.plugin.stepikConnector.StepikConnector;
11 | import org.stepik.plugin.storages.CourseDefinitionStorage;
12 | import org.stepik.plugin.toolWindow.StudyToolWindowFactory;
13 | import org.stepik.plugin.toolWindow.StudyUtils;
14 | import org.stepik.plugin.utils.MyLogger;
15 |
16 | public class MyProjectComponent implements ProjectComponent {
17 | private Project project;
18 |
19 | public MyProjectComponent(Project project) {
20 | this.project = project;
21 | }
22 |
23 | @Override
24 | public void initComponent() {
25 | }
26 |
27 | @Override
28 | public void disposeComponent() {
29 | }
30 |
31 | @Override
32 | @NotNull
33 | public String getComponentName() {
34 | return "MyProjectComponent";
35 | }
36 |
37 | @Override
38 | public void projectOpened() {
39 | MyLogger.getInstance().getLOG().debug("projectOpened");
40 |
41 | if (StudyUtils.hasJavaFx()) {
42 | Platform.setImplicitExit(false);
43 | }
44 |
45 | if (project.getName().equals(CourseDefinitionStorage.getInstance(project).getProjectName())) {
46 | StepikConnector.initToken(project);
47 | registerStudyToolWindow();
48 | }
49 | }
50 |
51 | private void registerStudyToolWindow() {
52 | MyLogger.getInstance().getLOG().debug("registerStudyToolWindow");
53 | final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
54 | registerToolWindows(toolWindowManager);
55 | final ToolWindow studyToolWindow = toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
56 | if (studyToolWindow != null) {
57 | StudyUtils.initToolWindows(project);
58 | }
59 | }
60 |
61 | private void registerToolWindows(@NotNull final ToolWindowManager toolWindowManager) {
62 | MyLogger.getInstance().getLOG().debug("registerToolWindows");
63 | final ToolWindow toolWindow = toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
64 | if (toolWindow == null) {
65 | toolWindowManager.registerToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW, true, ToolWindowAnchor.RIGHT, project, true);
66 | }
67 | }
68 |
69 | @Override
70 | public void projectClosed() {
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/icons/PluginIcons.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.icons;
2 |
3 | import com.intellij.icons.AllIcons;
4 | import com.intellij.openapi.util.IconLoader;
5 |
6 | import javax.swing.*;
7 |
8 | //public class PluginIcons {
9 | public interface PluginIcons {
10 | // public static final Icon STEPIK_LOGO = IconLoader.getIcon("/icons/stepik_logo_green.png");
11 | Icon STEPIK_LOGO_MINI = IconLoader.getIcon("/icons/stepik_logotype_13x13-2.png");
12 | Icon STEPIK_LOGO = IconLoader.getIcon("/icons/stepik_logo_green.png");
13 | Icon DOWNLOAD = IconLoader.getIcon("/icons/download_blue.png");
14 | // public static final Icon Question = AllIcons.General.TodoQuestion;
15 | Icon Question = AllIcons.General.TodoQuestion;
16 |
17 | }
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/Attempt.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | public class Attempt {
4 | public int id;
5 | public String status;
6 | public String step;
7 |
8 | @Override
9 | public boolean equals(Object o) {
10 | if (this == o) return true;
11 | if (o == null || getClass() != o.getClass()) return false;
12 |
13 | Attempt attempt = (Attempt) o;
14 |
15 | if (id != attempt.id) return false;
16 | if (status != null ? !status.equals(attempt.status) : attempt.status != null) return false;
17 | return step != null ? step.equals(attempt.step) : attempt.step == null;
18 |
19 | }
20 |
21 | @Override
22 | public int hashCode() {
23 | int result = id;
24 | result = 31 * result + (status != null ? status.hashCode() : 0);
25 | result = 31 * result + (step != null ? step.hashCode() : 0);
26 | return result;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/Course.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import com.intellij.openapi.project.Project;
5 | import org.stepik.plugin.stepikConnector.StepikConnector;
6 | import org.stepik.plugin.storages.CourseDefinitionStorage;
7 | import org.stepik.plugin.utils.Utils;
8 | import org.stepik.plugin.utils.YaTranslator;
9 |
10 | import java.util.ArrayList;
11 | import java.util.HashMap;
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | public class Course {
16 | public int id;
17 | public String title;
18 | public String summary;
19 | private String courseName;
20 |
21 | @SerializedName("sections")
22 | public List sectionsId;
23 |
24 | public transient Map sections = new HashMap<>();
25 |
26 | public String getTitle() {
27 | return title;
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return "Course{" +
33 | "id=" + id +
34 | ", title='" + title + '\'' +
35 | ", sections=" + sections +
36 | '}';
37 | }
38 |
39 | @Override
40 | public boolean equals(Object o) {
41 | if (this == o) return true;
42 | if (o == null || getClass() != o.getClass()) return false;
43 | Course that = (Course) o;
44 | return that.id == this.id;
45 | }
46 |
47 | @Override
48 | public int hashCode() {
49 | int result = id;
50 | result = 31 * result + (title != null ? title.hashCode() : 0);
51 | result = 31 * result + (summary != null ? summary.hashCode() : 0);
52 | result = 31 * result + (courseName != null ? courseName.hashCode() : 0);
53 | result = 31 * result + (sectionsId != null ? sectionsId.hashCode() : 0);
54 | result = 31 * result + (sections != null ? sections.hashCode() : 0);
55 | return result;
56 | }
57 |
58 | public void build(String root, Project project) {
59 | int sectionNo = 0;
60 | List sectionList = StepikConnector.getSections(Utils.getIdQuery(sectionsId), project);
61 | List sectionNames = new ArrayList<>();
62 | sectionList.forEach(x -> sectionNames.add(x.title));
63 |
64 | List newSectionNames = YaTranslator.translateNames(sectionNames, "section", project);
65 |
66 | for (Section section : sectionList) {
67 | section.setSectionName(newSectionNames.get(sectionNo));
68 | sections.put(++sectionNo, section);
69 | section.build(sectionNo, root + "/" + getName(project), project);
70 | }
71 | }
72 |
73 | public String getName(Project project) {
74 | if (courseName == null) {
75 | CourseDefinitionStorage ws = CourseDefinitionStorage.getInstance(project);
76 | if (ws.isTranslate()) {
77 | courseName = YaTranslator.translateRuToEn(title);
78 | } else {
79 | courseName = "course";
80 | }
81 | }
82 | return Utils.normalize(courseName);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/CourseInfo.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import com.intellij.openapi.util.text.StringUtil;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class CourseInfo {
11 | boolean is_public;
12 | public List sections;
13 | @SerializedName("title")
14 | private String myName;
15 | @SerializedName("summary")
16 | private String myDescription;
17 | @SerializedName("course_format")
18 | //course type in format "pycharm "
19 | private String myType = "pycharm Python";
20 |
21 | public List instructors = new ArrayList();
22 |
23 | List myAuthors = new ArrayList();
24 | int id;
25 |
26 | public static CourseInfo INVALID_COURSE = new CourseInfo();
27 |
28 | public String getName() {
29 | return myName;
30 | }
31 |
32 | @NotNull
33 | public List getAuthors() {
34 | return myAuthors;
35 | }
36 |
37 | public String getDescription() {
38 | return myDescription;
39 | }
40 |
41 | public String getType() {
42 | return myType;
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | return myName;
48 | }
49 |
50 | @Override
51 | public boolean equals(Object o) {
52 | if (this == o) return true;
53 | if (o == null || getClass() != o.getClass()) return false;
54 | CourseInfo that = (CourseInfo) o;
55 | if (that.getName() == null || that.getDescription() == null) return false;
56 | return that.getName().equals(myName)
57 | && that.getDescription().equals(myDescription);
58 | }
59 |
60 | @Override
61 | public int hashCode() {
62 | int result = myName != null ? myName.hashCode() : 0;
63 | result = 31 * result + (myDescription != null ? myDescription.hashCode() : 0);
64 | return result;
65 | }
66 |
67 | public static class Author {
68 | int id;
69 | String first_name = "";
70 | String last_name = "";
71 |
72 | public Author() {
73 | }
74 |
75 | public Author(String firstName, String lastName) {
76 | first_name = firstName;
77 | last_name = lastName;
78 | }
79 |
80 | public String getName() {
81 | return StringUtil.join(new String[]{first_name, last_name}, " ");
82 | }
83 |
84 | public int getId() {
85 | return id;
86 | }
87 | }
88 |
89 | public void setName(String name) {
90 | myName = name;
91 | }
92 |
93 | public void setAuthors(List authors) {
94 | myAuthors = authors;
95 | for (Author author : authors) {
96 | if (author.id > 0) {
97 | instructors.add(author.id);
98 | }
99 | }
100 | }
101 |
102 | public void addAuthor(Author author) {
103 | if (myAuthors == null) {
104 | myAuthors = new ArrayList();
105 | }
106 | myAuthors.add(author);
107 | }
108 |
109 | public void setDescription(String description) {
110 | myDescription = description;
111 | }
112 |
113 | public void setType(String type) {
114 | myType = type;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/Lesson.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import com.intellij.openapi.diagnostic.Logger;
5 | import com.intellij.openapi.project.Project;
6 | import org.stepik.plugin.stepikConnector.StepikConnector;
7 | import org.stepik.plugin.storages.CourseDefinitionStorage;
8 | import org.stepik.plugin.utils.Utils;
9 |
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | public class Lesson {
15 |
16 | private static final Logger LOG = Logger.getInstance(Lesson.class);
17 | int id;
18 | @SerializedName("steps")
19 | List stepsId;
20 |
21 | public String title;
22 | private String lessonName;
23 |
24 | public transient Map steps = new HashMap<>();
25 | private int lessonNo;
26 |
27 | public void build(int lessonNo, String courseDir, String sectionDir, Project project) {
28 | this.lessonNo = lessonNo;
29 | CourseDefinitionStorage projectService = CourseDefinitionStorage.getInstance(project);
30 |
31 | List stepsList = StepikConnector.getSteps(Utils.getIdQuery(stepsId), project);
32 |
33 | for (Step step : stepsList) {
34 | if (step.isCode()) {
35 | steps.put(step.position, step);
36 | String filename = "Step" + step.position;
37 | String path = getPath(courseDir, sectionDir, lessonName) + filename + ".java";
38 | StepInfo tmp = new StepInfo(Integer.toString(step.id), sectionDir + "." + lessonName, filename, step.getText());
39 | projectService.addStepInfo(path, tmp);
40 | }
41 | }
42 | }
43 |
44 | public void setLessonName(String lessonName) {
45 | this.lessonName = lessonName;
46 | }
47 |
48 | private String getPath(String... titles) {
49 | StringBuilder sb = new StringBuilder();
50 | for (String title : titles) {
51 | sb.append(title + "/");
52 | }
53 | return sb.toString();
54 | }
55 |
56 | @Override
57 | public String toString() {
58 | return "\n\tLesson{" +
59 | "id=" + id +
60 | ", steps=" + steps +
61 | '}';
62 | }
63 |
64 | @Override
65 | public boolean equals(Object o) {
66 | if (this == o) return true;
67 | if (o == null || getClass() != o.getClass()) return false;
68 |
69 | Lesson lesson = (Lesson) o;
70 |
71 | if (id != lesson.id) return false;
72 | if (lessonNo != lesson.lessonNo) return false;
73 | if (stepsId != null ? !stepsId.equals(lesson.stepsId) : lesson.stepsId != null) return false;
74 | if (title != null ? !title.equals(lesson.title) : lesson.title != null) return false;
75 | if (lessonName != null ? !lessonName.equals(lesson.lessonName) : lesson.lessonName != null) return false;
76 | return steps != null ? steps.equals(lesson.steps) : lesson.steps == null;
77 |
78 | }
79 |
80 | @Override
81 | public int hashCode() {
82 | int result = id;
83 | result = 31 * result + (stepsId != null ? stepsId.hashCode() : 0);
84 | result = 31 * result + (title != null ? title.hashCode() : 0);
85 | result = 31 * result + (lessonName != null ? lessonName.hashCode() : 0);
86 | result = 31 * result + (steps != null ? steps.hashCode() : 0);
87 | result = 31 * result + lessonNo;
88 | return result;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/Section.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import com.intellij.openapi.project.Project;
5 | import org.stepik.plugin.stepikConnector.StepikConnector;
6 | import org.stepik.plugin.utils.Utils;
7 | import org.stepik.plugin.utils.YaTranslator;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | public class Section {
15 | int id;
16 | int course;
17 | public String position;
18 | public String title;
19 | private String sectionName;
20 |
21 | @SerializedName("units")
22 | List unitsId;
23 | public transient Map lessons = new HashMap<>();
24 |
25 | private int sectionNo;
26 |
27 |
28 | public void build(int sectionNo, String courseDir, Project project) {
29 | this.sectionNo = sectionNo;
30 | int lessonNo = 0;
31 |
32 | List units = StepikConnector.getUnits(Utils.getIdQuery(unitsId), project);
33 | if (units == null) return;
34 | List lessonsId = new ArrayList<>();
35 | List lessonNames = new ArrayList<>();
36 | units.forEach(x -> lessonsId.add(x.getLessonId()));
37 | List lessons = StepikConnector.getLessons(Utils.getIdQuery(lessonsId), project);
38 | lessons.forEach(x -> lessonNames.add(x.title));
39 |
40 | List newLessonNames = YaTranslator.translateNames(lessonNames, "lesson", project);
41 |
42 | for (Lesson lesson : lessons) {
43 | lesson.setLessonName(newLessonNames.get(lessonNo));
44 | this.lessons.put(++lessonNo, lesson);
45 | lesson.build(lessonNo, courseDir, sectionName, project);
46 | }
47 | }
48 |
49 | public String getSectionName() {
50 | return sectionName;
51 | }
52 |
53 | @Override
54 | public String toString() {
55 | return "\nSection{" +
56 | "id=" + id +
57 | ", title='" + title + '\'' +
58 | ", lessons=" + lessons +
59 | '}';
60 | }
61 |
62 | public void setSectionName(String sectionName) {
63 | this.sectionName = sectionName;
64 | }
65 |
66 | @Override
67 | public boolean equals(Object o) {
68 | if (this == o) return true;
69 | if (o == null || getClass() != o.getClass()) return false;
70 |
71 | Section section = (Section) o;
72 |
73 | if (id != section.id) return false;
74 | if (course != section.course) return false;
75 | if (sectionNo != section.sectionNo) return false;
76 | if (position != null ? !position.equals(section.position) : section.position != null) return false;
77 | if (title != null ? !title.equals(section.title) : section.title != null) return false;
78 | if (sectionName != null ? !sectionName.equals(section.sectionName) : section.sectionName != null) return false;
79 | if (unitsId != null ? !unitsId.equals(section.unitsId) : section.unitsId != null) return false;
80 | return lessons != null ? lessons.equals(section.lessons) : section.lessons == null;
81 |
82 | }
83 |
84 | @Override
85 | public int hashCode() {
86 | int result = id;
87 | result = 31 * result + course;
88 | result = 31 * result + (position != null ? position.hashCode() : 0);
89 | result = 31 * result + (title != null ? title.hashCode() : 0);
90 | result = 31 * result + (sectionName != null ? sectionName.hashCode() : 0);
91 | result = 31 * result + (unitsId != null ? unitsId.hashCode() : 0);
92 | result = 31 * result + (lessons != null ? lessons.hashCode() : 0);
93 | result = 31 * result + sectionNo;
94 | return result;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/Step.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | import java.util.Map;
4 |
5 | public class Step {
6 | int id;
7 | int lesson;
8 | int position;
9 | Map block;
10 |
11 | public boolean isCode() {
12 | String tmp = (String) block.get("name");
13 | return tmp.equals("code");
14 | }
15 |
16 | public String getText() {
17 | return (String) block.get("text");
18 | }
19 |
20 | @Override
21 | public String toString() {
22 | return "\n\t\tStep{" +
23 | "position=" + position +
24 | '}';
25 | }
26 |
27 | @Override
28 | public boolean equals(Object o) {
29 | if (this == o) return true;
30 | if (o == null || getClass() != o.getClass()) return false;
31 |
32 | Step step = (Step) o;
33 |
34 | if (id != step.id) return false;
35 | if (lesson != step.lesson) return false;
36 | if (position != step.position) return false;
37 | return block != null ? block.equals(step.block) : step.block == null;
38 |
39 | }
40 |
41 | @Override
42 | public int hashCode() {
43 | int result = id;
44 | result = 31 * result + lesson;
45 | result = 31 * result + position;
46 | result = 31 * result + (block != null ? block.hashCode() : 0);
47 | return result;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/StepInfo.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | import java.io.Serializable;
4 |
5 | public class StepInfo implements Serializable {
6 | private String stepID;
7 | private String attemptID;
8 | private String packageName;
9 | private String filename;
10 | private String submissionID;
11 | private String text;
12 |
13 | // public static final StepInfo EMPTY = new StepInfo("");
14 |
15 |
16 | private void setAllEmpy() {
17 | stepID = "";
18 | attemptID = "";
19 | packageName = "";
20 | filename = "";
21 | submissionID = "";
22 | text = "";
23 | }
24 |
25 | public StepInfo() {
26 | setAllEmpy();
27 | }
28 |
29 | public StepInfo(String stepID) {
30 | setAllEmpy();
31 | this.stepID = stepID;
32 | }
33 |
34 | public StepInfo(String stepID, String packageName, String filename) {
35 | setAllEmpy();
36 | this.stepID = stepID;
37 | this.packageName = packageName;
38 | this.filename = filename;
39 | }
40 |
41 | public StepInfo(String stepID, String packageName, String filename, String text) {
42 | setAllEmpy();
43 | this.stepID = stepID;
44 | this.packageName = packageName;
45 | this.filename = filename;
46 | this.text = text;
47 | }
48 |
49 | public String getStepID() {
50 | return stepID;
51 | }
52 |
53 | public void setStepID(String stepID) {
54 | this.stepID = stepID;
55 | }
56 |
57 | public String getAttemptID() {
58 | return attemptID;
59 | }
60 |
61 | public void setAttemptID(String attemptID) {
62 | this.attemptID = attemptID;
63 | }
64 |
65 | public String getPackageName() {
66 | return packageName;
67 | }
68 |
69 | public void setPackageName(String packageName) {
70 | this.packageName = packageName;
71 | }
72 |
73 | public String getSubmissionID() {
74 | return submissionID;
75 | }
76 |
77 | public void setSubmissionID(String submissionID) {
78 | this.submissionID = submissionID;
79 | }
80 |
81 | public String getText() {
82 | return text;
83 | }
84 |
85 | public void setText(String text) {
86 | this.text = text;
87 | }
88 |
89 | @Override
90 | public String toString() {
91 | return "StepInfo{" +
92 | "stepID='" + stepID + '\'' +
93 | ", attemptID='" + attemptID + '\'' +
94 | ", packageName='" + packageName + '\'' +
95 | '}';
96 | }
97 |
98 | public String getFilename() {
99 | return filename;
100 | }
101 |
102 | public void setFilename(String filename) {
103 | this.filename = filename;
104 | }
105 |
106 | @Override
107 | public boolean equals(Object o) {
108 | if (this == o) return true;
109 | if (o == null || getClass() != o.getClass()) return false;
110 |
111 | StepInfo stepInfo = (StepInfo) o;
112 |
113 | if (stepID != null ? !stepID.equals(stepInfo.stepID) : stepInfo.stepID != null) return false;
114 | if (attemptID != null ? !attemptID.equals(stepInfo.attemptID) : stepInfo.attemptID != null) return false;
115 | if (packageName != null ? !packageName.equals(stepInfo.packageName) : stepInfo.packageName != null)
116 | return false;
117 | if (filename != null ? !filename.equals(stepInfo.filename) : stepInfo.filename != null) return false;
118 | if (submissionID != null ? !submissionID.equals(stepInfo.submissionID) : stepInfo.submissionID != null)
119 | return false;
120 | return text != null ? text.equals(stepInfo.text) : stepInfo.text == null;
121 |
122 | }
123 |
124 | @Override
125 | public int hashCode() {
126 | int result = stepID != null ? stepID.hashCode() : 0;
127 | result = 31 * result + (attemptID != null ? attemptID.hashCode() : 0);
128 | result = 31 * result + (packageName != null ? packageName.hashCode() : 0);
129 | result = 31 * result + (filename != null ? filename.hashCode() : 0);
130 | result = 31 * result + (submissionID != null ? submissionID.hashCode() : 0);
131 | result = 31 * result + (text != null ? text.hashCode() : 0);
132 | return result;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/Submission.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | import java.util.Map;
4 |
5 | public class Submission {
6 | public int id;
7 | private String status;
8 | private String time;
9 | private String hint;
10 | private Map reply;
11 |
12 | public String getStatus() {
13 | return status;
14 | }
15 |
16 | public String getTime() {
17 | return time;
18 | }
19 |
20 | public Map getReply() {
21 | return reply;
22 | }
23 |
24 | public String getCode() {
25 | return reply.get("code");
26 | }
27 |
28 | public String getHint() {
29 | return hint;
30 | }
31 |
32 |
33 | @Override
34 | public boolean equals(Object o) {
35 | if (this == o) return true;
36 | if (o == null || getClass() != o.getClass()) return false;
37 |
38 | Submission that = (Submission) o;
39 |
40 | if (id != that.id) return false;
41 | if (status != null ? !status.equals(that.status) : that.status != null) return false;
42 | if (time != null ? !time.equals(that.time) : that.time != null) return false;
43 | if (hint != null ? !hint.equals(that.hint) : that.hint != null) return false;
44 | return reply != null ? reply.equals(that.reply) : that.reply == null;
45 |
46 | }
47 |
48 | @Override
49 | public int hashCode() {
50 | int result = id;
51 | result = 31 * result + (status != null ? status.hashCode() : 0);
52 | result = 31 * result + (time != null ? time.hashCode() : 0);
53 | result = 31 * result + (hint != null ? hint.hashCode() : 0);
54 | result = 31 * result + (reply != null ? reply.hashCode() : 0);
55 | return result;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/TokenInfo.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | public class TokenInfo {
4 | public String refresh_token;
5 | public String token_type;
6 | public String access_token;
7 | public String scope;
8 | public int expires_in;
9 |
10 | @Override
11 | public boolean equals(Object o) {
12 | if (this == o) return true;
13 | if (o == null || getClass() != o.getClass()) return false;
14 |
15 | TokenInfo tokenInfo = (TokenInfo) o;
16 |
17 | if (expires_in != tokenInfo.expires_in) return false;
18 | if (refresh_token != null ? !refresh_token.equals(tokenInfo.refresh_token) : tokenInfo.refresh_token != null)
19 | return false;
20 | if (token_type != null ? !token_type.equals(tokenInfo.token_type) : tokenInfo.token_type != null) return false;
21 | if (access_token != null ? !access_token.equals(tokenInfo.access_token) : tokenInfo.access_token != null)
22 | return false;
23 | return scope != null ? scope.equals(tokenInfo.scope) : tokenInfo.scope == null;
24 |
25 | }
26 |
27 | @Override
28 | public int hashCode() {
29 | int result = refresh_token != null ? refresh_token.hashCode() : 0;
30 | result = 31 * result + (token_type != null ? token_type.hashCode() : 0);
31 | result = 31 * result + (access_token != null ? access_token.hashCode() : 0);
32 | result = 31 * result + (scope != null ? scope.hashCode() : 0);
33 | result = 31 * result + expires_in;
34 | return result;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/modules/Unit.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.modules;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | public class Unit {
6 | int id;
7 | @SerializedName("lesson")
8 | private int lessonId;
9 |
10 | public int getLessonId() {
11 | return lessonId;
12 | }
13 |
14 | @Override
15 | public boolean equals(Object o) {
16 | if (this == o) return true;
17 | if (o == null || getClass() != o.getClass()) return false;
18 |
19 | Unit unit = (Unit) o;
20 |
21 | if (id != unit.id) return false;
22 | return lessonId == unit.lessonId;
23 |
24 | }
25 |
26 | @Override
27 | public int hashCode() {
28 | int result = id;
29 | result = 31 * result + lessonId;
30 | return result;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/projectWizard/StepikModuleBuilder.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.projectWizard;
2 |
3 | import com.intellij.ide.util.PropertiesComponent;
4 | import com.intellij.ide.util.projectWizard.JavaModuleBuilder;
5 | import com.intellij.ide.util.projectWizard.ModuleWizardStep;
6 | import com.intellij.ide.util.projectWizard.WizardContext;
7 | import com.intellij.openapi.diagnostic.Logger;
8 | import com.intellij.openapi.module.ModuleType;
9 | import com.intellij.openapi.options.ConfigurationException;
10 | import com.intellij.openapi.project.Project;
11 | import com.intellij.openapi.roots.ModifiableRootModel;
12 | import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
13 | import com.intellij.openapi.util.Pair;
14 | import com.intellij.openapi.vfs.VirtualFile;
15 | import org.jetbrains.annotations.NotNull;
16 | import org.stepik.plugin.modules.Course;
17 | import org.stepik.plugin.modules.StepInfo;
18 | import org.stepik.plugin.stepikConnector.StepikConnector;
19 | import org.stepik.plugin.storages.ActionVisibleProperties;
20 | import org.stepik.plugin.storages.CourseDefinitionStorage;
21 |
22 | import java.io.File;
23 | import java.io.IOException;
24 | import java.nio.charset.Charset;
25 | import java.nio.file.Files;
26 | import java.nio.file.Path;
27 | import java.nio.file.Paths;
28 | import java.util.ArrayList;
29 | import java.util.List;
30 |
31 | public class StepikModuleBuilder extends JavaModuleBuilder {
32 | private static final Logger LOG = Logger.getInstance(StepikModuleBuilder.class);
33 |
34 | @Override
35 | public void setupRootModel(ModifiableRootModel rootModel) throws ConfigurationException {
36 | Project project = rootModel.getProject();
37 | final VirtualFile root = project.getBaseDir();
38 |
39 | CourseDefinitionStorage projectService = CourseDefinitionStorage.getInstance(project);
40 |
41 | PropertiesComponent props = PropertiesComponent.getInstance();
42 | projectService.setTranslate(Boolean.parseBoolean(props.getValue("translate")));
43 | // projectService.setTranslate(props.getBoolean("translate"));
44 | projectService.setCourseID(props.getValue("courseId"));
45 | projectService.setProjectName(project.getName());
46 |
47 | ActionVisibleProperties visibleProperties = ActionVisibleProperties.getInstance(project);
48 | visibleProperties.setEnabled(true);
49 | visibleProperties.setVisible(true);
50 |
51 | StepikConnector.setLoginAndPassword(props.getValue("login"), props.getValue("password"), project);
52 | LOG.debug("login = " + props.getValue("login"));
53 |
54 | StepikConnector.initToken(project);
55 | String courseId = projectService.getCourseID();
56 | LOG.debug("build course structure " + root.getPath());
57 |
58 | Course course = StepikConnector.getCourse(courseId, project);
59 | course.build(root.getPath(), rootModel.getProject());
60 |
61 | projectService.mapPathInfo.entrySet().forEach(x -> {
62 | String path = x.getKey();
63 | StepInfo stepInfo = x.getValue();
64 |
65 | File file = new File(path);
66 | file.getParentFile().mkdirs();
67 | try {
68 | Path path1 = Paths.get(path);
69 | Files.write(path1, getText(stepInfo.getFilename(), stepInfo.getPackageName()), Charset.forName("UTF-8"));
70 | } catch (IOException e) {
71 | LOG.error("Create file error\n" + e.getMessage());
72 | }
73 | });
74 |
75 | addSourcePath(Pair.create(root.getPath() + "/" + course.getName(project), ""));
76 |
77 | super.setupRootModel(rootModel);
78 | }
79 |
80 | public static List getText(String name, String pack) {
81 | List text = new ArrayList<>();
82 | text.add("package " + pack + ";\n");
83 | text.add("class " + name + " {");
84 | text.add("\tpublic static void main(String[] args){");
85 | text.add("\t\t//Write your code here");
86 | text.add("\t}\n}");
87 | return text;
88 | }
89 |
90 | public ModuleType getModuleType() {
91 | return StepikModuleType.STEPIK_MODULE_TYPE;
92 | }
93 |
94 | @Override
95 | public ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext,
96 | @NotNull ModulesProvider modulesProvider) {
97 | return new StepikModuleWizardStep[]{new StepikModuleWizardStep(this, wizardContext)};
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/projectWizard/StepikModuleType.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.projectWizard;
2 |
3 | import com.intellij.ide.util.projectWizard.*;
4 | import com.intellij.openapi.module.Module;
5 | import com.intellij.openapi.module.ModuleType;
6 | import com.intellij.openapi.module.ModuleTypeManager;
7 | import com.intellij.openapi.projectRoots.Sdk;
8 | import com.intellij.openapi.roots.ModuleRootManager;
9 | import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
10 | import com.intellij.psi.CommonClassNames;
11 | import com.intellij.psi.JavaPsiFacade;
12 | import org.jetbrains.annotations.NotNull;
13 | import org.jetbrains.annotations.Nullable;
14 | import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
15 | import org.stepik.plugin.icons.PluginIcons;
16 |
17 | import javax.swing.*;
18 |
19 | public class StepikModuleType extends ModuleType {
20 | public static final String MODULE_NAME = "Stepik";
21 | public static final StepikModuleType STEPIK_MODULE_TYPE;
22 |
23 | static {
24 | STEPIK_MODULE_TYPE = (StepikModuleType) instantiate("org.stepik.plugin.projectWizard.StepikModuleType");
25 | }
26 |
27 | private static final String ID = "STEPIK_MODULE_TYPE";
28 |
29 | public StepikModuleType() {
30 | super(ID);
31 | }
32 |
33 | public static StepikModuleType getInstance() {
34 | return (StepikModuleType) ModuleTypeManager.getInstance().findByID(ID);
35 | }
36 |
37 | @NotNull
38 | @Override
39 | public StepikModuleBuilder createModuleBuilder() {
40 | return new StepikModuleBuilder();
41 | }
42 |
43 | @NotNull
44 | @Override
45 | public String getName() {
46 | return MODULE_NAME;
47 | }
48 |
49 | @NotNull
50 | @Override
51 | public String getDescription() {
52 | return "Stepik Module Type";
53 | }
54 |
55 | @Override
56 | public Icon getBigIcon() {
57 | return PluginIcons.STEPIK_LOGO;
58 | }
59 |
60 | @Override
61 | public Icon getNodeIcon(@Deprecated boolean b) {
62 | return PluginIcons.STEPIK_LOGO;
63 | }
64 |
65 | @NotNull
66 | @Override
67 | public ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext, @NotNull StepikModuleBuilder moduleBuilder, @NotNull ModulesProvider modulesProvider) {
68 | // return super.createWizardSteps(wizardContext, moduleBuilder, modulesProvider);
69 | return new StepikModuleWizardStep[]{new StepikModuleWizardStep(moduleBuilder, wizardContext)};
70 | }
71 |
72 | @NotNull
73 | private static ModuleType instantiate(String className) {
74 | try {
75 | return (ModuleType) Class.forName(className).newInstance();
76 | } catch (Exception e) {
77 | throw new IllegalArgumentException(e);
78 | }
79 | }
80 |
81 | @Nullable
82 | @Override
83 | public ModuleWizardStep modifyProjectTypeStep(@NotNull SettingsStep settingsStep, @NotNull final ModuleBuilder moduleBuilder) {
84 | return ProjectWizardStepFactory.getInstance().createJavaSettingsStep(settingsStep, moduleBuilder, moduleBuilder::isSuitableSdkType);
85 | }
86 |
87 | @Override
88 | public boolean isValidSdk(@NotNull final Module module, final Sdk projectSdk) {
89 | return isValidJavaSdk(module);
90 | }
91 |
92 | private static boolean isValidJavaSdk(@NotNull Module module) {
93 | if (ModuleRootManager.getInstance(module).getSourceRoots(JavaModuleSourceRootTypes.SOURCES).isEmpty())
94 | return true;
95 | return JavaPsiFacade.getInstance(module.getProject()).findClass(CommonClassNames.JAVA_LANG_OBJECT,
96 | module.getModuleWithLibrariesScope()) != null;
97 | }
98 | }
--------------------------------------------------------------------------------
/src/org/stepik/plugin/projectWizard/StepikModuleWizardStep.form:
--------------------------------------------------------------------------------
1 |
2 |
75 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/projectWizard/StepikModuleWizardStep.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.projectWizard;
2 |
3 | import com.intellij.ide.util.PropertiesComponent;
4 | import com.intellij.ide.util.projectWizard.ModuleWizardStep;
5 | import com.intellij.ide.util.projectWizard.WizardContext;
6 | import com.intellij.openapi.externalSystem.model.project.ProjectData;
7 | import com.intellij.openapi.project.Project;
8 | import org.stepik.plugin.storages.StepikApplicationStorage;
9 | import org.stepik.plugin.utils.Utils;
10 |
11 | import javax.swing.*;
12 |
13 | public class StepikModuleWizardStep extends ModuleWizardStep {
14 | private JPanel panel1;
15 | private JTextField textField1;
16 | private JPasswordField passwordField1;
17 | private JTextField courseLinkFiled;
18 | private JCheckBox CheckBox;
19 |
20 | private final Project myProjectOrNull;
21 | private final StepikModuleBuilder myBuilder;
22 | private final WizardContext myContext;
23 | private ProjectData myParent;
24 |
25 | public StepikModuleWizardStep(StepikModuleBuilder builder, WizardContext context) {
26 | myProjectOrNull = context.getProject();
27 | myBuilder = builder;
28 | myContext = context;
29 |
30 | initComponents();
31 | }
32 |
33 | private void initComponents() {
34 | panel1.setVisible(true);
35 | CheckBox.setSelected(true);
36 | }
37 |
38 | @Override
39 | public JComponent getComponent() {
40 | return panel1;
41 | }
42 |
43 | public String getCourseLink() {
44 | return courseLinkFiled.getText();
45 | }
46 |
47 | @Override
48 | public void updateDataModel() {
49 |
50 | }
51 |
52 | @Override
53 | public void onStepLeaving() {
54 | saveSettings();
55 | }
56 |
57 | private void saveSettings() {
58 | StepikApplicationStorage ws = StepikApplicationStorage.getInstance();
59 | ws.setLogin(textField1.getText());
60 | ws.setPassword(new String(passwordField1.getPassword()));
61 |
62 | PropertiesComponent props = PropertiesComponent.getInstance();
63 | props.setValue("translate", Boolean.toString(CheckBox.isSelected()));
64 | props.setValue("courseId", Utils.parseUrl(courseLinkFiled.getText()));
65 | saveValue("login", textField1.getText());
66 | saveValue("password", new String(passwordField1.getPassword()));
67 | }
68 |
69 | private static void saveValue(String key, String value) {
70 | PropertiesComponent props = PropertiesComponent.getInstance();
71 | props.setValue(key, value);
72 | }
73 |
74 | private void createUIComponents() {
75 | // TODO: place custom component creation code here
76 | StepikApplicationStorage ws = StepikApplicationStorage.getInstance();
77 | textField1 = new JTextField(ws.getLogin());
78 | passwordField1 = new JPasswordField(ws.getPassword());
79 | }
80 |
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/projectWizard/StepikProjectStructureDetector.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.projectWizard;
2 |
3 | import com.intellij.ide.util.projectWizard.importSources.impl.JavaProjectStructureDetector;
4 |
5 | public class StepikProjectStructureDetector extends JavaProjectStructureDetector {
6 | }
7 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/stepikConnector/StepikConnector.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.stepikConnector;
2 |
3 | import com.google.gson.FieldNamingPolicy;
4 | import com.google.gson.Gson;
5 | import com.google.gson.GsonBuilder;
6 | import com.intellij.openapi.diagnostic.Logger;
7 | import com.intellij.openapi.project.Project;
8 | import com.intellij.openapi.util.Pair;
9 | import com.intellij.util.net.HttpConfigurable;
10 | import com.mashape.unirest.http.HttpResponse;
11 | import com.mashape.unirest.http.JsonNode;
12 | import com.mashape.unirest.http.Unirest;
13 | import com.mashape.unirest.http.exceptions.UnirestException;
14 | import org.apache.http.HttpHost;
15 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
16 | import org.apache.http.impl.client.CloseableHttpClient;
17 | import org.apache.http.impl.client.HttpClients;
18 | import org.json.JSONObject;
19 | import org.stepik.plugin.storages.StudentStorage;
20 | import org.stepik.plugin.utils.NotificationTemplates;
21 | import org.stepik.plugin.utils.NotificationUtils;
22 | import org.stepik.plugin.modules.*;
23 |
24 | import javax.net.ssl.SSLContext;
25 | import javax.net.ssl.TrustManager;
26 | import javax.net.ssl.X509TrustManager;
27 | import java.security.KeyManagementException;
28 | import java.security.NoSuchAlgorithmException;
29 | import java.security.SecureRandom;
30 | import java.security.cert.X509Certificate;
31 | import java.util.Date;
32 | import java.util.HashMap;
33 | import java.util.List;
34 | import java.util.Map;
35 |
36 | public class StepikConnector {
37 |
38 | private static final String TOKEN_URL = "https://stepik.org/oauth2/token/";
39 | private static final String API_URL = "https://stepik.org/api/";
40 | private static final String CLIENT_ID = "hUCWcq3hZHCmz0DKrDtwOWITLcYutzot7p4n59vU";
41 |
42 | private static final Logger logger = Logger.getInstance(StepikConnector.class);
43 | private static boolean isInstanceProperty = false;
44 | private static final Gson GSON = new GsonBuilder()
45 | .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
46 | .create();
47 |
48 | public static void setSSLProperty(Project project) {
49 | // Create a trust manager that does not validate certificate for this connection
50 | TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
51 | public X509Certificate[] getAcceptedIssuers() {
52 | return null;
53 | }
54 |
55 | public void checkClientTrusted(X509Certificate[] certs, String authType) {
56 | }
57 |
58 | public void checkServerTrusted(X509Certificate[] certs, String authType) {
59 | }
60 | }};
61 | SSLContext sslContext = null;
62 | try {
63 | sslContext = SSLContext.getInstance("TLS");
64 | sslContext.init(null, trustAllCerts, new SecureRandom());
65 | } catch (NoSuchAlgorithmException | KeyManagementException e) {
66 | NotificationUtils.initRuntimeException(NotificationTemplates.CERTIFICATE_ERROR, project);
67 | }
68 |
69 | HttpConfigurable instance = HttpConfigurable.getInstance();
70 | CloseableHttpClient httpClient;
71 |
72 | SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
73 | if (instance.USE_HTTP_PROXY) {
74 | HttpHost host = new HttpHost(instance.PROXY_HOST, instance.PROXY_PORT);
75 | httpClient = HttpClients.custom()
76 | .setSSLSocketFactory(socketFactory)
77 | .setProxy(host)
78 | .build();
79 | } else {
80 | httpClient = HttpClients.custom()
81 | .setSSLSocketFactory(socketFactory)
82 | .build();
83 | }
84 |
85 | Unirest.setHttpClient(httpClient);
86 | }
87 |
88 | public static void initToken(Project project) {
89 | if (!isInstanceProperty) {
90 | setSSLProperty(project);
91 | isInstanceProperty = true;
92 | }
93 |
94 | setTokenGRP(project);
95 | }
96 |
97 | private static void setTokenGRP(Project project) {
98 | StudentStorage ws = StudentStorage.getInstance(project);
99 | String user = ws.getLogin();
100 | String pass = ws.getPassword();
101 |
102 | Map parameters = new HashMap<>();
103 | parameters.put("grant_type", "password");
104 | parameters.put("username", user);
105 | parameters.put("password", pass);
106 | parameters.put("client_id", CLIENT_ID);
107 |
108 | TokenInfo tokenInfo = postToStepikMapLinkReset(TOKEN_URL, parameters, TokenInfo.class, project);
109 |
110 | String token = tokenInfo.access_token;
111 | if (token != null && !token.isEmpty()) {
112 | ws.setToken(tokenInfo.access_token);
113 | ws.setRefresh_token(tokenInfo.refresh_token);
114 | }
115 | }
116 |
117 | private static T getFromStepik(String link, final Class container, Project project) {
118 |
119 | String token = getToken(project);
120 | HttpResponse response = null;
121 | try {
122 | response = Unirest
123 | .get(API_URL + link)
124 | .header("Authorization", "Bearer " + token)
125 | .asString();
126 | } catch (UnirestException e) {
127 | NotificationUtils.initRuntimeException(project, e.getMessage());
128 | }
129 |
130 | if (response.getStatus() != 200) {
131 | NotificationUtils.initRuntimeException(project, "Status " + Integer.toString(response.getStatus()));
132 | }
133 | final String responseString = response.getBody();
134 |
135 | return GSON.fromJson(responseString, container);
136 | }
137 |
138 | private static T getFromStepik(String link, Map queryMap, final Class container, Project project) {
139 |
140 | String token = getToken(project);
141 | HttpResponse response = null;
142 | try {
143 | response = Unirest
144 | .get(API_URL + link)
145 | .header("Authorization", "Bearer " + token)
146 | .queryString(queryMap)
147 | .asString();
148 | } catch (UnirestException e) {
149 | NotificationUtils.initRuntimeException(project);
150 | }
151 | final String responseString = response.getBody();
152 |
153 | return GSON.fromJson(responseString, container);
154 | }
155 |
156 | private static T postToStepik(String link, JSONObject jsonObject, final Class container, Project project) {
157 | HttpResponse response = null;
158 | String token = getToken(project);
159 | try {
160 | response = Unirest
161 | .post(API_URL + link)
162 | .header("Authorization", "Bearer " + token)
163 | .header("Content-Type", "application/json")
164 | .body(jsonObject)
165 | .asJson();
166 | } catch (UnirestException e) {
167 | NotificationUtils.initRuntimeException(project);
168 | }
169 | final JSONObject responseJson = response.getBody().getObject();
170 |
171 | return GSON.fromJson(responseJson.toString(), container);
172 | }
173 |
174 | private static T postToStepikMapLinkReset(String link, Map parameters, final Class container, Project project) {
175 | HttpResponse response = null;
176 | try {
177 | response = Unirest
178 | .post(link)
179 | .fields(parameters)
180 | .asString();
181 | } catch (UnirestException e) {
182 | NotificationUtils.initRuntimeException(project);
183 | }
184 | final String responseString = response.getBody();
185 |
186 | return GSON.fromJson(responseString, container);
187 | }
188 |
189 | public static AuthorWrapper getCurrentUser(Project project) {
190 | return getFromStepik("stepiks/1", AuthorWrapper.class, project);
191 | }
192 |
193 | public static String getUserName(Project project) {
194 | AuthorWrapper aw = getCurrentUser(project);
195 | return aw.users.get(0).getName();
196 | }
197 |
198 | public static Course getCourse(String courseId, Project project) {
199 | final String url = "courses/" + courseId;
200 | return getFromStepik(url, CoursesContainer.class, project).courses.get(0);
201 | }
202 |
203 | public static List getSections(String idsQuery, Project project) {
204 | final String url = "sections" + idsQuery;
205 | return getFromStepik(url, SectionsContainer.class, project).sections;
206 | }
207 |
208 | public static List getUnits(String idsQuery, Project project) {
209 | final String url = "units" + idsQuery;
210 | return getFromStepik(url, UnitsContainer.class, project).units;
211 | }
212 |
213 | public static List getLessons(String idsQuery, Project project) {
214 | final String url = "lessons" + idsQuery;
215 | return getFromStepik(url, LessonsContainer.class, project).lessons;
216 | }
217 |
218 | public static List getStatus(String submissionID, Project project) {
219 | final String url = "submissions/" + submissionID;
220 | return getFromStepik(url, SubmissionsContainer.class, project).submissions;
221 | }
222 |
223 | public static List getSteps(String stepIdQuery, Project project) {
224 | final String url = "steps" + stepIdQuery;
225 | return getFromStepik(url, StepsContainer.class, project).steps;
226 | }
227 |
228 | public static String getAttemptId(String stepId, Project project) {
229 | String attempts = "attempts";
230 | JSONObject first = new JSONObject();
231 | JSONObject second = new JSONObject();
232 |
233 | first.put("step", stepId);
234 | second.put("attempt", first);
235 |
236 | List attemptsL = postToStepik(attempts, second, AttemptsContainer.class, project).attempts;
237 | if (attemptsL == null) {
238 | NotificationUtils.initRuntimeException(project);
239 | }
240 | int id = attemptsL.get(0).id;
241 | return Integer.toString(id);
242 | }
243 |
244 | public static String sendFile(String file, String att_id, Project project) {
245 |
246 | JSONObject wrapper = new JSONObject();
247 | JSONObject submission = new JSONObject();
248 | JSONObject reply = new JSONObject();
249 |
250 | reply.put("language", "java8");
251 | reply.put("code", file);
252 |
253 | submission.put("attempt", att_id);
254 | submission.put("reply", reply);
255 |
256 | wrapper.put("submission", submission);
257 |
258 | int id = postToStepik("submissions", wrapper, SubmissionsContainer.class, project).submissions.get(0).id;
259 | return Integer.toString(id);
260 | }
261 |
262 | public static List getStepStatus(String stepId, Pair pair, Project project) {
263 |
264 | Map queryMap = new HashMap<>();
265 | queryMap.put("step", stepId);
266 | queryMap.put(pair.first, pair.second);
267 |
268 | return getFromStepik("submissions", queryMap, SubmissionsContainer.class, project).submissions;
269 | }
270 |
271 | public static void setLoginAndPassword(String login, String password, Project project) {
272 | StudentStorage storage = StudentStorage.getInstance(project);
273 | storage.setLoginAndPassword(login, password);
274 | }
275 |
276 | public static String getLogin(Project project) {
277 | return StudentStorage.getInstance(project).getLogin();
278 | }
279 |
280 | public static void setLogin(String login, Project project) {
281 | StudentStorage.getInstance(project).setLogin(login);
282 | }
283 |
284 | public static class AuthorWrapper {
285 | public List users;
286 | }
287 |
288 | public static class CoursesContainer {
289 | public List courses;
290 | public Map meta;
291 | }
292 |
293 | public static class SectionsContainer {
294 | public List sections;
295 | public Map meta;
296 | }
297 |
298 | public static class UnitsContainer {
299 | public List units;
300 | public Map meta;
301 | }
302 |
303 | public static class LessonsContainer {
304 | public List lessons;
305 | public Map meta;
306 | }
307 |
308 | public static class StepsContainer {
309 | public List steps;
310 | public Map meta;
311 | }
312 |
313 | public static class SubmissionsContainer {
314 | public List submissions;
315 | public Map meta;
316 | }
317 |
318 | public static class AttemptsContainer {
319 | public List attempts;
320 | public Map meta;
321 | }
322 |
323 | public static List getSubmissions(String stepId, Project project) {
324 | Map map = new HashMap<>();
325 | map.put("step", stepId);
326 | return getFromStepik("submissions", map, SubmissionsContainer.class, project).submissions;
327 | }
328 |
329 | public static String getToken(Project project) {
330 | StudentStorage storage = StudentStorage.getInstance(project);
331 | long baseTime = storage.getTokenTimeCreate();
332 |
333 | if (!timePassedLessThen(baseTime, new Date().getTime(), 32400L)) { // 9 hours in sec
334 | StepikConnector.initToken(project);
335 | }
336 | return storage.getToken();
337 | }
338 |
339 | private static boolean timePassedLessThen(long base, long current, long sec) {
340 | long delta = current - base;
341 | return delta - sec * 1000L < 0L;
342 | }
343 |
344 | public static boolean isPasswordSet(Project project) {
345 | StudentStorage storage = StudentStorage.getInstance(project);
346 | String password = storage.getPassword();
347 | return !(password == null || password.isEmpty());
348 | }
349 | }
350 |
351 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/storages/ActionVisibleProperties.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.storages;
2 |
3 | import com.intellij.openapi.components.*;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.util.xmlb.XmlSerializerUtil;
6 | import org.jetbrains.annotations.Nullable;
7 |
8 | @State(name = "ActionVisibleProperties", storages = @Storage(id = "ActionVisibleProperties", file = StoragePathMacros.PROJECT_CONFIG_DIR + "/ActionVisibleProperties.xml"))
9 | public class ActionVisibleProperties implements PersistentStateComponent {
10 | private boolean visible;
11 | private boolean enabled;
12 |
13 |
14 | private ActionVisibleProperties() {
15 | visible = false;
16 | enabled = false;
17 | }
18 |
19 | public static ActionVisibleProperties getInstance(Project project) {
20 | return ServiceManager.getService(project, ActionVisibleProperties.class);
21 | }
22 |
23 | @Nullable
24 | @Override
25 | public ActionVisibleProperties getState() {
26 | return this;
27 | }
28 |
29 | @Override
30 | public void loadState(ActionVisibleProperties state) {
31 | XmlSerializerUtil.copyBean(state, this);
32 | }
33 |
34 | public boolean isVisible() {
35 | return visible;
36 | }
37 |
38 | public void setVisible(boolean visible) {
39 | this.visible = visible;
40 | }
41 |
42 | public boolean isEnabled() {
43 | return enabled;
44 | }
45 |
46 | public void setEnabled(boolean enabled) {
47 | this.enabled = enabled;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/storages/CourseDefinitionStorage.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.storages;
2 |
3 | import com.intellij.openapi.components.*;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.util.xmlb.XmlSerializer;
6 | import org.jdom.Element;
7 | import org.jetbrains.annotations.NotNull;
8 | import org.jetbrains.annotations.Nullable;
9 | import org.stepik.plugin.modules.StepInfo;
10 |
11 | import java.util.HashMap;
12 | import java.util.Map;
13 | import java.util.Set;
14 |
15 | @State(name = "CourseDefinitionStorage", storages = @Storage(id = "CourseDefinitionStorage", file = StoragePathMacros.PROJECT_CONFIG_DIR + "/CourseDefinitionStorage.xml"))
16 | public class CourseDefinitionStorage implements PersistentStateComponent {
17 |
18 | public Map mapPathInfo = new HashMap<>();
19 | private String courseID;
20 | private boolean translate;
21 | private String projectName;
22 |
23 | public static final String MAIN_ELEMENT = "ProjectService";
24 |
25 | public static CourseDefinitionStorage getInstance(@NotNull final Project project) {
26 | return ServiceManager.getService(project, CourseDefinitionStorage.class);
27 | }
28 |
29 | @Nullable
30 | @Override
31 | public Element getState() {
32 | Element el = new Element("projectService");
33 | Element courseElement = new Element(MAIN_ELEMENT);
34 | XmlSerializer.serializeInto(this, courseElement);
35 | el.addContent(courseElement);
36 | return el;
37 | }
38 |
39 | @Override
40 | public void loadState(Element state) {
41 | final Element mainElement = state.getChild(MAIN_ELEMENT);
42 | if (mainElement != null) {
43 | final CourseDefinitionStorage projectService = XmlSerializer.deserialize(mainElement, CourseDefinitionStorage.class);
44 | if (projectService != null) {
45 | mapPathInfo = projectService.mapPathInfo;
46 | courseID = projectService.courseID;
47 | translate = projectService.translate;
48 | projectName = projectService.projectName;
49 | }
50 | }
51 |
52 | // there can be your init
53 | }
54 |
55 | private StepInfo getStepInfo(String path) {
56 | // return mapPathInfo.getOrDefault(path, StepInfo.EMPTY);
57 | return mapPathInfo.getOrDefault(path, new StepInfo(""));
58 | }
59 |
60 | private StepInfo getOrCreateStepInfo(String path) {
61 | if (mapPathInfo.containsKey(path)) {
62 | return mapPathInfo.get(path);
63 | } else {
64 | StepInfo stepInfo = new StepInfo("");
65 | mapPathInfo.put(path, stepInfo);
66 | return stepInfo;
67 | }
68 | }
69 |
70 | public String getStepID(String path) {
71 | return getStepInfo(path).getStepID();
72 | }
73 |
74 | public String getAttemptID(String path) {
75 | return getStepInfo(path).getAttemptID();
76 | }
77 |
78 | public String getPackageName(String path) {
79 | return getStepInfo(path).getPackageName();
80 | }
81 |
82 | public String getFilename(String path) {
83 | return getStepInfo(path).getFilename();
84 | }
85 |
86 | public String getSubmissionID(String path) {
87 | return getStepInfo(path).getSubmissionID();
88 | }
89 |
90 | public String getText(String path) {
91 | return getStepInfo(path).getText();
92 | }
93 |
94 | public void setStepID(String path, String stepID) {
95 | StepInfo stepInfo = getOrCreateStepInfo(path);
96 | stepInfo.setStepID(stepID);
97 | }
98 |
99 | public void setAttemptID(String path, String attemptID) {
100 | StepInfo stepInfo = getOrCreateStepInfo(path);
101 | stepInfo.setAttemptID(attemptID);
102 | }
103 |
104 | public void setPackageName(String path, String packageName) {
105 | StepInfo stepInfo = getOrCreateStepInfo(path);
106 | stepInfo.setPackageName(packageName);
107 | }
108 |
109 | public void setFilename(String path, String filename) {
110 | StepInfo stepInfo = getOrCreateStepInfo(path);
111 | stepInfo.setFilename(filename);
112 | }
113 |
114 | public void setSubmissionID(String path, String submissionID) {
115 | StepInfo stepInfo = getOrCreateStepInfo(path);
116 | stepInfo.setSubmissionID(submissionID);
117 | }
118 |
119 | public void setText(String path, String text) {
120 | StepInfo stepInfo = getOrCreateStepInfo(path);
121 | stepInfo.setText(text);
122 | }
123 |
124 | public void addStepInfo(String path, StepInfo stepInfo) {
125 | mapPathInfo.put(path, stepInfo);
126 | }
127 |
128 | public String getCourseID() {
129 | return courseID;
130 | }
131 |
132 | public void setCourseID(String courseID) {
133 | this.courseID = courseID;
134 | }
135 |
136 | public boolean isTranslate() {
137 | return translate;
138 | }
139 |
140 | public void setTranslate(boolean translate) {
141 | this.translate = translate;
142 | }
143 |
144 | public String getProjectName() {
145 | return projectName;
146 | }
147 |
148 | public void setProjectName(String projectName) {
149 | this.projectName = projectName;
150 | }
151 |
152 | public Map getMapPathInfo() {
153 | return mapPathInfo;
154 | }
155 |
156 | public void removeAll(Set removed) {
157 | mapPathInfo.keySet().removeAll(removed);
158 | }
159 |
160 | public boolean contains(String path) {
161 | return mapPathInfo.containsKey(path);
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/storages/StepikApplicationStorage.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.storages;
2 |
3 | import com.intellij.ide.passwordSafe.PasswordSafe;
4 | import com.intellij.ide.passwordSafe.PasswordSafeException;
5 | import com.intellij.openapi.components.*;
6 | import com.intellij.openapi.diagnostic.Logger;
7 | import com.intellij.openapi.util.text.StringUtil;
8 | import com.intellij.util.xmlb.XmlSerializerUtil;
9 | import com.intellij.util.xmlb.annotations.Transient;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 |
13 | @State(name = "StepikApplicationStorage", storages = @Storage(id = "StepikApplicationStorage", file = StoragePathMacros.APP_CONFIG + "/StepikApplicationStorage.xml"))
14 | public class StepikApplicationStorage implements PersistentStateComponent {
15 | private final String clientId = "hUCWcq3hZHCmz0DKrDtwOWITLcYutzot7p4n59vU";
16 | private String login;
17 | private long tokenTimeCreate;
18 |
19 | @Transient
20 | private static final Logger LOG = Logger.getInstance(StepikApplicationStorage.class);
21 |
22 | public static StepikApplicationStorage getInstance() {
23 | return ServiceManager.getService(StepikApplicationStorage.class);
24 | }
25 |
26 | public StepikApplicationStorage() {
27 | }
28 |
29 | public StepikApplicationStorage getState() {
30 | return this;
31 | }
32 |
33 | public void loadState(StepikApplicationStorage state) {
34 | XmlSerializerUtil.copyBean(state, this);
35 | }
36 |
37 | private String getPasswordKey() {
38 | return "STEPIK_SETTINGS_PASSWORD_KEY: " + getLogin();
39 | }
40 |
41 |
42 | // setters and getters -------------------------------
43 |
44 | @NotNull
45 | public String getPassword() {
46 | final String login = getLogin();
47 | if (StringUtil.isEmptyOrSpaces(login)) return "";
48 |
49 | String password;
50 | try {
51 | password = PasswordSafe.getInstance().getPassword(null, StepikApplicationStorage.class, getPasswordKey());
52 | } catch (PasswordSafeException e) {
53 | LOG.info("Couldn't get password for key [" + getPasswordKey() + "]", e);
54 | password = "";
55 | }
56 |
57 | return StringUtil.notNullize(password);
58 | }
59 |
60 | public void setPassword(@NotNull String password) {
61 | try {
62 | PasswordSafe.getInstance().storePassword(null, StepikApplicationStorage.class, getPasswordKey(), password);
63 | } catch (PasswordSafeException e) {
64 | LOG.info("Couldn't set password for key [" + getPasswordKey() + "]", e);
65 | }
66 | }
67 |
68 | public String getClientId() {
69 | return clientId;
70 | }
71 |
72 | public String getLogin() {
73 | return login;
74 | }
75 |
76 | public void setLogin(String login) {
77 | this.login = login;
78 | }
79 |
80 | public void setTokenTimeCreate(long tokenTimeCreate) {
81 | this.tokenTimeCreate = tokenTimeCreate;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/storages/StudentStorage.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.storages;
2 |
3 | import com.intellij.ide.passwordSafe.PasswordSafe;
4 | import com.intellij.ide.passwordSafe.PasswordSafeException;
5 | import com.intellij.openapi.components.*;
6 | import com.intellij.openapi.diagnostic.Logger;
7 | import com.intellij.openapi.project.Project;
8 | import com.intellij.openapi.util.text.StringUtil;
9 | import com.intellij.util.xmlb.XmlSerializerUtil;
10 | import com.intellij.util.xmlb.annotations.Transient;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import java.util.Date;
14 |
15 |
16 | @State(name = "StudentStorage", storages = @Storage(id = "StudentStorage", file = StoragePathMacros.PROJECT_CONFIG_DIR + "/StudentStorage.xml"))
17 | public class StudentStorage implements PersistentStateComponent {
18 | private String token;
19 | private String refresh_token;
20 | private String login;
21 | private long tokenTimeCreate;
22 |
23 | @Transient
24 | private static final Logger LOG = Logger.getInstance(StudentStorage.class);
25 |
26 | public static StudentStorage getInstance(Project project) {
27 | return ServiceManager.getService(project, StudentStorage.class);
28 | }
29 |
30 | public StudentStorage() {
31 | }
32 |
33 | public StudentStorage getState() {
34 | return this;
35 | }
36 |
37 | public void loadState(StudentStorage state) {
38 | XmlSerializerUtil.copyBean(state, this);
39 | }
40 |
41 | private String getPasswordKey() {
42 | return "STEPIK_SETTINGS_PASSWORD_KEY: " + getLogin();
43 | }
44 |
45 |
46 | // setters and getters -------------------------------
47 |
48 | @NotNull
49 | public String getPassword() {
50 | final String login = getLogin();
51 | if (StringUtil.isEmptyOrSpaces(login)) return "";
52 |
53 | String password;
54 | try {
55 | password = PasswordSafe.getInstance().getPassword(null, StudentStorage.class, getPasswordKey());
56 | } catch (PasswordSafeException e) {
57 | LOG.info("Couldn't get password for key [" + getPasswordKey() + "]", e);
58 | password = "";
59 | }
60 |
61 | return StringUtil.notNullize(password);
62 | }
63 |
64 | private void setPassword(@NotNull String password) {
65 | try {
66 | PasswordSafe.getInstance().storePassword(null, StudentStorage.class, getPasswordKey(), password);
67 | } catch (PasswordSafeException e) {
68 | LOG.info("Couldn't set password for key [" + getPasswordKey() + "]", e);
69 | }
70 | }
71 |
72 | public String getToken() {
73 | return token;
74 | }
75 |
76 | private boolean timePassedLessThen(long base, long current, long sec) {
77 | // long delta = d1.getTime() - d0.getTime();
78 | long delta = current - base;
79 | return delta - sec * 1000L < 0L;
80 | }
81 |
82 | public void setToken(String token) {
83 | tokenTimeCreate = new Date().getTime();
84 | this.token = token;
85 | }
86 |
87 | public String getRefresh_token() {
88 | return refresh_token;
89 | }
90 |
91 | public void setRefresh_token(String refresh_token) {
92 | this.refresh_token = refresh_token;
93 | }
94 |
95 | public String getLogin() {
96 | return login;
97 | }
98 |
99 | public void setLogin(String login) {
100 | this.login = login;
101 | }
102 |
103 | public void setLoginAndPassword(String login, String password) {
104 | setLogin(login);
105 | setPassword(password);
106 | }
107 |
108 | public void setTokenTimeCreate(long tokenTimeCreate) {
109 | this.tokenTimeCreate = tokenTimeCreate;
110 | }
111 |
112 | public long getTokenTimeCreate() {
113 | return tokenTimeCreate;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/JavaStudyPluginConfigurator.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.toolWindow;
2 |
3 | import com.intellij.openapi.actionSystem.DefaultActionGroup;
4 | import com.intellij.openapi.project.Project;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | public class JavaStudyPluginConfigurator extends StudyBasePluginConfigurator {
8 |
9 | @NotNull
10 | @Override
11 | public DefaultActionGroup getActionGroup(Project project) {
12 | final DefaultActionGroup baseGroup = super.getActionGroup(project);
13 | final DefaultActionGroup group = new DefaultActionGroup();
14 | // group.add(new PyStudyCheckAction());
15 | group.addAll(baseGroup);
16 | return group;
17 | }
18 |
19 | @NotNull
20 | @Override
21 | public String getDefaultHighlightingMode() {
22 | return "java";
23 | }
24 |
25 | @NotNull
26 | @Override
27 | public String getLanguageScriptUrl() {
28 | return getClass().getResource("/python.js").toExternalForm();
29 | }
30 |
31 | @Override
32 | public boolean accept(@NotNull Project project) {
33 | // StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
34 | // if (taskManager == null) return false;
35 | // Course course = taskManager.getCourse();
36 | // return course != null && "Python".equals(course.getLanguage()) && "PyCharm".equals(course.getCourseType());
37 | return true;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudyBasePluginConfigurator.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.toolWindow;
2 |
3 | import com.intellij.openapi.actionSystem.DefaultActionGroup;
4 | import com.intellij.openapi.fileEditor.FileEditorManager;
5 | import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
6 | import com.intellij.openapi.fileEditor.FileEditorManagerListener;
7 | import com.intellij.openapi.project.Project;
8 | import com.intellij.openapi.vfs.VirtualFile;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.stepik.plugin.storages.CourseDefinitionStorage;
11 |
12 | import javax.swing.*;
13 | import java.util.Collections;
14 | import java.util.Map;
15 |
16 | public abstract class StudyBasePluginConfigurator implements StudyPluginConfigurator {
17 | @NotNull
18 | @Override
19 | public DefaultActionGroup getActionGroup(Project project) {
20 | final DefaultActionGroup group = new DefaultActionGroup();
21 | // group.add(new StudyPreviousStudyTaskAction());
22 | // group.add(new StudyNextStudyTaskAction());
23 | // group.add(new StudyRefreshTaskFileAction());
24 | // group.add(new StudyShowHintAction());
25 | //
26 | // group.add(new StudyRunAction());
27 | // group.add(new StudyEditInputAction());
28 | return group;
29 | }
30 |
31 | @NotNull
32 | @Override
33 | public Map getAdditionalPanels(Project project) {
34 | return Collections.emptyMap();
35 | }
36 |
37 | @NotNull
38 | @Override
39 | public FileEditorManagerListener getFileEditorManagerListener(@NotNull Project project, @NotNull StudyToolWindow toolWindow) {
40 |
41 | return new FileEditorManagerListener() {
42 |
43 | private final CourseDefinitionStorage cs = CourseDefinitionStorage.getInstance(project);
44 | private static final String EMPTY_STEP_TEXT = "Please, open any Step to see Step description";
45 |
46 | @Override
47 | public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
48 | if (cs.contains(file.getPath())) {
49 | setStepText(file);
50 | }
51 | }
52 |
53 | @Override
54 | public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
55 | toolWindow.setStepText(EMPTY_STEP_TEXT);
56 | }
57 |
58 | @Override
59 | public void selectionChanged(@NotNull FileEditorManagerEvent event) {
60 | VirtualFile file = event.getNewFile();
61 | if (file != null && cs.contains(file.getPath())) {
62 | setStepText(file);
63 | }
64 | }
65 |
66 | private void setStepText(final VirtualFile virtualFile) {
67 | String text = CourseDefinitionStorage.getInstance(project).getText(virtualFile.getPath());
68 | toolWindow.setStepText(text);
69 | }
70 | };
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudyCondition.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.toolWindow;
2 |
3 | import com.intellij.openapi.project.DumbAware;
4 | import com.intellij.openapi.util.Condition;
5 |
6 | /**
7 | * author: liana
8 | * data: 7/29/14.
9 | */
10 | public class StudyCondition implements Condition, DumbAware {
11 | @Override
12 | public boolean value(Object o) {
13 | return false;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudyEditor.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.toolWindow;
2 |
3 | import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl;
4 | import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.vfs.VirtualFile;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | public class StudyEditor extends PsiAwareTextEditorImpl {
10 | // public StudyEditor(@NotNull Project project, @NotNull VirtualFile virtualFile, TextEditorProvider textEditorProvider) {
11 | // super(project, virtualFile, textEditorProvider);
12 | // }
13 | // private final TaskFile myTaskFile;
14 | // private static final Map myDocumentListeners = new HashMap();
15 | //
16 | // public TaskFile getTaskFile() {
17 | // return myTaskFile;
18 | // }
19 |
20 | // public static void addDocumentListener(@NotNull final Document document, @NotNull final EduDocumentListener listener) {
21 | // document.addDocumentListener(listener);
22 | // myDocumentListeners.put(document, listener);
23 | // }
24 | //
25 | public StudyEditor(@NotNull final Project project, @NotNull final VirtualFile file) {
26 | super(project, file, TextEditorProvider.getInstance());
27 | // myTaskFile = StudyUtils.getTaskFile(project, file);
28 | }
29 | //
30 | // public static void removeListener(Document document) {
31 | // final EduDocumentListener listener = myDocumentListeners.get(document);
32 | // if (listener != null) {
33 | // document.removeDocumentListener(listener);
34 | // }
35 | // myDocumentListeners.remove(document);
36 | // }
37 | }
38 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudyEditorFactoryListener.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.toolWindow;
2 |
3 |
4 | import com.intellij.openapi.application.ApplicationManager;
5 | import com.intellij.openapi.editor.Document;
6 | import com.intellij.openapi.editor.Editor;
7 | import com.intellij.openapi.editor.LogicalPosition;
8 | import com.intellij.openapi.editor.event.EditorFactoryEvent;
9 | import com.intellij.openapi.editor.event.EditorFactoryListener;
10 | import com.intellij.openapi.editor.event.EditorMouseAdapter;
11 | import com.intellij.openapi.editor.event.EditorMouseEvent;
12 | import com.intellij.openapi.fileEditor.FileDocumentManager;
13 | import com.intellij.openapi.project.Project;
14 | import com.intellij.openapi.vfs.VirtualFile;
15 | import com.intellij.openapi.wm.ToolWindow;
16 | import com.intellij.openapi.wm.ToolWindowManager;
17 | import org.jetbrains.annotations.NotNull;
18 |
19 | import java.awt.*;
20 |
21 |
22 | public class StudyEditorFactoryListener implements EditorFactoryListener {
23 |
24 | private static class WindowSelectionListener extends EditorMouseAdapter {
25 | @Override
26 | public void mouseClicked(EditorMouseEvent e) {
27 | final Editor editor = e.getEditor();
28 | final Point point = e.getMouseEvent().getPoint();
29 | final LogicalPosition pos = editor.xyToLogicalPosition(point);
30 | }
31 | }
32 |
33 | @Override
34 | public void editorCreated(@NotNull final EditorFactoryEvent event) {
35 | final Editor editor = event.getEditor();
36 |
37 | final Project project = editor.getProject();
38 | if (project == null) {
39 | return;
40 | }
41 | ApplicationManager.getApplication().invokeLater(
42 | () -> ApplicationManager.getApplication().runWriteAction(() -> {
43 | final Document document = editor.getDocument();
44 | final VirtualFile openedFile = FileDocumentManager.getInstance().getFile(document);
45 | if (openedFile != null) {
46 | final ToolWindow studyToolWindow = ToolWindowManager.getInstance(project).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
47 | if (studyToolWindow != null) {
48 | StudyUtils.updateToolWindows(project);
49 | studyToolWindow.show(null);
50 | }
51 | }
52 | })
53 | );
54 | }
55 |
56 | @Override
57 | public void editorReleased(@NotNull EditorFactoryEvent event) {
58 | final Editor editor = event.getEditor();
59 | final Document document = editor.getDocument();
60 | // StudyEditor.removeListener(document);
61 | // editor.getMarkupModel().removeAllHighlighters();
62 | // editor.getSelectionModel().removeSelection();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudyJavaFxToolWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2015 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.stepik.plugin.toolWindow;
17 |
18 | import com.intellij.openapi.project.Project;
19 | import com.intellij.openapi.project.ProjectUtil;
20 | import org.stepik.plugin.utils.MyLogger;
21 |
22 | import javax.swing.*;
23 |
24 | public class StudyJavaFxToolWindow extends StudyToolWindow {
25 | private StudyBrowserWindow myBrowserWindow;
26 |
27 | public StudyJavaFxToolWindow() {
28 | super();
29 | }
30 |
31 | @Override
32 | public JComponent createStepInfoPanel(String stepText, Project project) {
33 | MyLogger.getInstance().getLOG().debug("createStepInfoPanel");
34 | myBrowserWindow = new StudyBrowserWindow(true, false);
35 | // myBrowserWindow.addBackAndOpenButtons();
36 | JPanel panel = new JPanel();
37 | panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
38 | panel.add(myBrowserWindow.getPanel());
39 | return panel;
40 | }
41 |
42 | @Override
43 | public void setStepText(String text) {
44 | StudyPluginConfigurator configurator = StudyUtils.getConfigurator(ProjectUtil.guessCurrentProject(this));
45 | myBrowserWindow.loadContent(text, configurator);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudyPluginConfigurator.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.toolWindow;
2 |
3 | import com.intellij.openapi.actionSystem.DefaultActionGroup;
4 | import com.intellij.openapi.extensions.ExtensionPointName;
5 | import com.intellij.openapi.fileEditor.FileEditorManagerListener;
6 | import com.intellij.openapi.project.Project;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | import javax.swing.*;
10 | import java.util.Map;
11 |
12 | public interface StudyPluginConfigurator {
13 | ExtensionPointName EP_NAME = ExtensionPointName.create("Edu.studyToolWindowConfigurator");
14 |
15 | /**
16 | * Provide action group that should be placed on the tool window toolbar.
17 | *
18 | * @param project
19 | * @return
20 | */
21 | @NotNull
22 | DefaultActionGroup getActionGroup(Project project);
23 |
24 | /**
25 | * Provide panels, that could be added to Task tool window.
26 | *
27 | * @param project
28 | * @return Map from panel id, i.e. "Task description", to panel itself.
29 | */
30 | @NotNull
31 | Map getAdditionalPanels(Project project);
32 |
33 | @NotNull
34 | FileEditorManagerListener getFileEditorManagerListener(@NotNull final Project project, @NotNull final StudyToolWindow toolWindow);
35 |
36 | /**
37 | * @return parameter for CodeMirror script. Available languages: @see <@linktourl http://codemirror.net/mode/>
38 | */
39 | @NotNull
40 | String getDefaultHighlightingMode();
41 |
42 | @NotNull
43 | String getLanguageScriptUrl();
44 |
45 | boolean accept(@NotNull final Project project);
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudySwingToolWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2015 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.stepik.plugin.toolWindow;
17 |
18 | import com.intellij.openapi.editor.colors.EditorColorsManager;
19 | import com.intellij.openapi.editor.colors.EditorColorsScheme;
20 | import com.intellij.openapi.project.Project;
21 | import com.intellij.ui.BrowserHyperlinkListener;
22 | import com.intellij.ui.ColorUtil;
23 | import com.intellij.ui.components.JBScrollPane;
24 | import com.intellij.util.ui.UIUtil;
25 | import org.jetbrains.annotations.NotNull;
26 |
27 | import javax.swing.*;
28 | import javax.swing.border.EmptyBorder;
29 | import javax.swing.text.html.HTMLDocument;
30 | import javax.swing.text.html.HTMLEditorKit;
31 | import java.awt.*;
32 |
33 | public class StudySwingToolWindow extends StudyToolWindow {
34 | private JTextPane myTaskTextPane;
35 |
36 | public StudySwingToolWindow() {
37 | super();
38 | }
39 |
40 | @Override
41 | public JComponent createStepInfoPanel(String stepText, Project project) {
42 | myTaskTextPane = new JTextPane();
43 | final JBScrollPane scrollPane = new JBScrollPane(myTaskTextPane);
44 | myTaskTextPane.setContentType(new HTMLEditorKit().getContentType());
45 | final EditorColorsScheme editorColorsScheme = EditorColorsManager.getInstance().getGlobalScheme();
46 | int fontSize = editorColorsScheme.getEditorFontSize();
47 | final String fontName = editorColorsScheme.getEditorFontName();
48 | final Font font = new Font(fontName, Font.PLAIN, fontSize);
49 | String bodyRule = "body { font-family: " + font.getFamily() + "; " +
50 | "font-size: " + font.getSize() + "pt; }" +
51 | "pre {font-family: Courier; display: inline; ine-height: 50px; padding-top: 5px; padding-bottom: 5px; padding-left: 5px; background-color:"
52 | + ColorUtil.toHex(ColorUtil.dimmer(UIUtil.getPanelBackground())) + ";}" +
53 | "code {font-family: Courier; display: flex; float: left; background-color:"
54 | + ColorUtil.toHex(ColorUtil.dimmer(UIUtil.getPanelBackground())) + ";}";
55 | ((HTMLDocument) myTaskTextPane.getDocument()).getStyleSheet().addRule(bodyRule);
56 | myTaskTextPane.setEditable(false);
57 | if (!UIUtil.isUnderDarcula()) {
58 | myTaskTextPane.setBackground(EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground());
59 | }
60 | myTaskTextPane.setBorder(new EmptyBorder(20, 20, 0, 10));
61 | myTaskTextPane.addHyperlinkListener(BrowserHyperlinkListener.INSTANCE);
62 | return scrollPane;
63 | }
64 |
65 | public void setStepText(@NotNull String text) {
66 | // myTaskTextPane.setText("step_link\n" + text);
67 | myTaskTextPane.setText(text);
68 | }
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudyToolWindow.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2000-2015 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.stepik.plugin.toolWindow;
17 |
18 | import com.intellij.openapi.Disposable;
19 | import com.intellij.openapi.actionSystem.DataProvider;
20 | import com.intellij.openapi.diagnostic.Logger;
21 | import com.intellij.openapi.fileEditor.FileEditorManagerListener;
22 | import com.intellij.openapi.project.DumbAware;
23 | import com.intellij.openapi.project.Project;
24 | import com.intellij.openapi.ui.SimpleToolWindowPanel;
25 | import com.intellij.ui.JBCardLayout;
26 | import com.intellij.ui.OnePixelSplitter;
27 | import org.jetbrains.annotations.NotNull;
28 | import org.stepik.plugin.utils.MyLogger;
29 |
30 | import javax.swing.*;
31 | import java.awt.*;
32 | import java.util.Map;
33 |
34 | public abstract class StudyToolWindow extends SimpleToolWindowPanel implements DataProvider, Disposable, DumbAware {
35 | private static final Logger LOG = Logger.getInstance(StudyToolWindow.class);
36 | private static final String STEP_INFO_ID = "stepInfo";
37 | private final JBCardLayout myCardLayout;
38 | private final JPanel myContentPanel;
39 | private final OnePixelSplitter mySplitPane;
40 |
41 | public StudyToolWindow() {
42 | super(true, true);
43 | myCardLayout = new JBCardLayout();
44 | myContentPanel = new JPanel(myCardLayout);
45 | mySplitPane = new OnePixelSplitter(myVertical = true);
46 | }
47 |
48 | public void init(Project project) {
49 | MyLogger.getInstance().getLOG().debug("init");
50 | String stepText = StudyUtils.getStepText(project);
51 | if (stepText == null) return;
52 |
53 | // JPanel toolbarPanel = createToolbarPanel(project);
54 | // setToolbar(toolbarPanel);
55 |
56 | myContentPanel.add(STEP_INFO_ID, createStepInfoPanel(stepText, project));
57 | mySplitPane.setFirstComponent(myContentPanel);
58 | addAdditionalPanels(project);
59 | myCardLayout.show(myContentPanel, STEP_INFO_ID);
60 |
61 | setContent(mySplitPane);
62 |
63 | StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
64 | if (configurator != null) {
65 | final FileEditorManagerListener listener = configurator.getFileEditorManagerListener(project, this);
66 | project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, listener);
67 | }
68 |
69 | setStepText(stepText);
70 | }
71 |
72 | private void addAdditionalPanels(Project project) {
73 | StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
74 | assert configurator != null;
75 | Map panels = configurator.getAdditionalPanels(project);
76 | for (Map.Entry entry : panels.entrySet()) {
77 | myContentPanel.add(entry.getKey(), entry.getValue());
78 | }
79 | }
80 |
81 | public void dispose() {
82 | }
83 |
84 | //used in checkiO plugin.
85 | @SuppressWarnings("unused")
86 | public void showPanelById(@NotNull final String panelId) {
87 | myCardLayout.swipe(myContentPanel, panelId, JBCardLayout.SwipeDirection.AUTO);
88 | }
89 |
90 | //used in checkiO plugin.
91 | @SuppressWarnings("unused")
92 | public void setBottomComponent(JComponent component) {
93 | mySplitPane.setSecondComponent(component);
94 | }
95 |
96 | //used in checkiO plugin.
97 | @SuppressWarnings("unused")
98 | public JComponent getBottomComponent() {
99 | return mySplitPane.getSecondComponent();
100 | }
101 |
102 | //used in checkiO plugin.
103 | @SuppressWarnings("unused")
104 | public void setTopComponentPrefferedSize(@NotNull final Dimension dimension) {
105 | myContentPanel.setPreferredSize(dimension);
106 | }
107 |
108 | //used in checkiO plugin.
109 | @SuppressWarnings("unused")
110 | public JPanel getContentPanel() {
111 | return myContentPanel;
112 | }
113 |
114 |
115 | public abstract JComponent createStepInfoPanel(String stepText, Project project);
116 |
117 | // private static JPanel createToolbarPanel(@NotNull final Project project) {
118 | // final DefaultActionGroup group = getActionGroup(project);
119 |
120 | // final ActionToolbar actionToolBar = ActionManager.getInstance().createActionToolbar("Study", group, true);
121 | // return JBUI.Panels.simplePanel(actionToolBar.getComponent());
122 | // }
123 |
124 | // private static DefaultActionGroup getActionGroup(@NotNull final Project project) {
125 | // Course course = StudyTaskManager.getInstance(project).getCourse();
126 | // if (course == null) {
127 | // LOG.debug("Course is null");
128 | // return new DefaultActionGroup();
129 | // }
130 | // StudyPluginConfigurator configurator = StudyUtils.getConfigurator(project);
131 | // assert configurator != null;
132 | //
133 | // return configurator.getActionGroup(project);
134 | // }
135 |
136 | public abstract void setStepText(String text);
137 | }
138 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudyToolWindowFactory.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.toolWindow;
2 |
3 | import com.intellij.openapi.project.DumbAware;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.openapi.util.Disposer;
6 | import com.intellij.openapi.wm.ToolWindow;
7 | import com.intellij.openapi.wm.ToolWindowFactory;
8 | import com.intellij.ui.content.Content;
9 | import com.intellij.ui.content.ContentManager;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.stepik.plugin.icons.PluginIcons;
12 | import org.stepik.plugin.utils.MyLogger;
13 |
14 | public class StudyToolWindowFactory implements ToolWindowFactory, DumbAware {
15 | public static final String STUDY_TOOL_WINDOW = "Step Description";
16 |
17 |
18 | @Override
19 | public void createToolWindowContent(@NotNull final Project project, @NotNull final ToolWindow toolWindow) {
20 | MyLogger.getInstance().getLOG().debug("createToolWindowContent");
21 | toolWindow.setIcon(PluginIcons.STEPIK_LOGO_MINI);
22 |
23 | final StudyToolWindow studyToolWindow;
24 | if (StudyUtils.hasJavaFx()) {
25 | studyToolWindow = new StudyJavaFxToolWindow();
26 | } else {
27 | studyToolWindow = new StudySwingToolWindow();
28 | }
29 | studyToolWindow.init(project);
30 | final ContentManager contentManager = toolWindow.getContentManager();
31 | final Content content = contentManager.getFactory().createContent(studyToolWindow, null, false);
32 | contentManager.addContent(content);
33 | Disposer.register(project, studyToolWindow);
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/toolWindow/StudyUtils.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.toolWindow;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.actionSystem.Presentation;
5 | import com.intellij.openapi.diagnostic.Logger;
6 | import com.intellij.openapi.editor.Editor;
7 | import com.intellij.openapi.fileEditor.FileEditor;
8 | import com.intellij.openapi.fileEditor.FileEditorManager;
9 | import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
10 | import com.intellij.openapi.project.Project;
11 | import com.intellij.openapi.ui.popup.Balloon;
12 | import com.intellij.openapi.util.Disposer;
13 | import com.intellij.openapi.vfs.VirtualFile;
14 | import com.intellij.openapi.wm.ToolWindow;
15 | import com.intellij.openapi.wm.ToolWindowManager;
16 | import com.intellij.ui.awt.RelativePoint;
17 | import com.intellij.ui.content.Content;
18 | import com.intellij.util.ui.UIUtil;
19 | import org.jetbrains.annotations.NotNull;
20 | import org.jetbrains.annotations.Nullable;
21 | import org.stepik.plugin.storages.CourseDefinitionStorage;
22 |
23 | import javax.swing.*;
24 | import java.awt.*;
25 | import java.io.*;
26 | import java.util.Collection;
27 |
28 | public class StudyUtils {
29 | private StudyUtils() {
30 | }
31 |
32 | private static final Logger LOG = Logger.getInstance(StudyUtils.class.getName());
33 | private static final String EMPTY_STEP_TEXT = "Please, open any Step to see Step description";
34 |
35 | public static void closeSilently(@Nullable final Closeable stream) {
36 | if (stream != null) {
37 | try {
38 | stream.close();
39 | } catch (IOException e) {
40 | // close silently
41 | }
42 | }
43 | }
44 |
45 | public static boolean isZip(String fileName) {
46 | return fileName.contains(".zip");
47 | }
48 |
49 | public static T getFirst(@NotNull final Iterable container) {
50 | return container.iterator().next();
51 | }
52 |
53 | public static boolean indexIsValid(int index, @NotNull final Collection collection) {
54 | int size = collection.size();
55 | return index >= 0 && index < size;
56 | }
57 |
58 | @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
59 | @Nullable
60 | public static String getFileText(@Nullable final String parentDir, @NotNull final String fileName, boolean wrapHTML,
61 | @NotNull final String encoding) {
62 | final File inputFile = parentDir != null ? new File(parentDir, fileName) : new File(fileName);
63 | if (!inputFile.exists()) return null;
64 | final StringBuilder stepText = new StringBuilder();
65 | BufferedReader reader = null;
66 | try {
67 | reader = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), encoding));
68 | String line;
69 | while ((line = reader.readLine()) != null) {
70 | stepText.append(line).append("\n");
71 | if (wrapHTML) {
72 | stepText.append("
");
73 | }
74 | }
75 | return wrapHTML ? UIUtil.toHtml(stepText.toString()) : stepText.toString();
76 | } catch (IOException e) {
77 | LOG.info("Failed to get file text from file " + fileName, e);
78 | } finally {
79 | closeSilently(reader);
80 | }
81 | return null;
82 | }
83 |
84 | public static void updateAction(@NotNull final AnActionEvent e) {
85 | final Presentation presentation = e.getPresentation();
86 | presentation.setEnabled(false);
87 | final Project project = e.getProject();
88 | if (project != null) {
89 | final StudyEditor studyEditor = getSelectedStudyEditor(project);
90 | if (studyEditor != null) {
91 | presentation.setEnabledAndVisible(true);
92 | }
93 | }
94 | }
95 |
96 | public static void updateToolWindows(@NotNull final Project project) {
97 | update(project);
98 |
99 | // final ToolWindowManager windowManager = ToolWindowManager.getInstance(project);
100 | // createProgressToolWindowContent(project, windowManager);
101 | }
102 |
103 | public static void initToolWindows(@NotNull final Project project) {
104 | final ToolWindowManager windowManager = ToolWindowManager.getInstance(project);
105 | windowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW).getContentManager().removeAllContents(false);
106 | StudyToolWindowFactory factory = new StudyToolWindowFactory();
107 | factory.createToolWindowContent(project, windowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW));
108 |
109 | // createProgressToolWindowContent(project, windowManager);
110 | }
111 |
112 | private static void createProgressToolWindowContent(@NotNull Project project, ToolWindowManager windowManager) {
113 | // windowManager.getToolWindow(StudyProgressToolWindowFactory.ID).getContentManager().removeAllContents(false);
114 | // StudyProgressToolWindowFactory windowFactory = new StudyProgressToolWindowFactory();
115 | // windowFactory.createToolWindowContent(project, windowManager.getToolWindow(StudyProgressToolWindowFactory.ID));
116 | }
117 |
118 | @Nullable
119 | public static StudyToolWindow getStudyToolWindow(@NotNull final Project project) {
120 | ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW);
121 | if (toolWindow != null) {
122 | Content[] contents = toolWindow.getContentManager().getContents();
123 | for (Content content : contents) {
124 | JComponent component = content.getComponent();
125 | if (component != null && component instanceof StudyToolWindow) {
126 | return (StudyToolWindow) component;
127 | }
128 | }
129 | }
130 | return null;
131 | }
132 |
133 | public static void deleteFile(@NotNull final VirtualFile file) {
134 | try {
135 | file.delete(StudyUtils.class);
136 | } catch (IOException e) {
137 | LOG.error(e);
138 | }
139 | }
140 |
141 | public static void showCheckPopUp(@NotNull final Project project, @NotNull final Balloon balloon) {
142 | final StudyEditor studyEditor = getSelectedStudyEditor(project);
143 | assert studyEditor != null;
144 |
145 | balloon.show(computeLocation(studyEditor.getEditor()), Balloon.Position.above);
146 | Disposer.register(project, balloon);
147 | }
148 |
149 | public static RelativePoint computeLocation(Editor editor) {
150 |
151 | final Rectangle visibleRect = editor.getComponent().getVisibleRect();
152 | Point point = new Point(visibleRect.x + visibleRect.width + 10,
153 | visibleRect.y + 10);
154 | return new RelativePoint(editor.getComponent(), point);
155 | }
156 |
157 |
158 | @Nullable
159 | public static StudyEditor getSelectedStudyEditor(@NotNull final Project project) {
160 | try {
161 | final FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow().
162 | getSelectedEditor().getSelectedEditorWithProvider().getFirst();
163 | if (fileEditor instanceof StudyEditor) {
164 | return (StudyEditor) fileEditor;
165 | }
166 | } catch (Exception e) {
167 | return null;
168 | }
169 | return null;
170 | }
171 |
172 | @Nullable
173 | public static Editor getSelectedEditor(@NotNull final Project project) {
174 | final StudyEditor studyEditor = getSelectedStudyEditor(project);
175 | if (studyEditor != null) {
176 | return studyEditor.getEditor();
177 | }
178 | return null;
179 | }
180 |
181 | @Nullable
182 | public static String getStepTextFromStep(VirtualFile file, Project project) {
183 | return CourseDefinitionStorage.getInstance(project).getText(file.getPath());
184 | }
185 |
186 | @Nullable
187 | public static StudyPluginConfigurator getConfigurator(@NotNull final Project project) {
188 | StudyPluginConfigurator[] extensions = StudyPluginConfigurator.EP_NAME.getExtensions();
189 | for (StudyPluginConfigurator extension : extensions) {
190 | if (extension.accept(project)) {
191 | return extension;
192 | }
193 | }
194 | return null;
195 | }
196 |
197 | public static String getStepText(@NotNull final Project project) {
198 | VirtualFile[] files = FileEditorManager.getInstance(project).getSelectedFiles();
199 | // TaskFile taskFile = null;
200 | CourseDefinitionStorage ps = CourseDefinitionStorage.getInstance(project);
201 | String text = null;
202 | for (VirtualFile file : files) {
203 | text = ps.getText(file.getPath());
204 | if (text != null && !text.isEmpty()) {
205 | break;
206 | }
207 | }
208 | if (text == null) {
209 | return EMPTY_STEP_TEXT;
210 | }
211 | return text;
212 | }
213 |
214 | public static void update(Project project) {
215 | final StudyToolWindow studyToolWindow = getStudyToolWindow(project);
216 | if (studyToolWindow != null) {
217 | String stepText = getStepText(project);
218 | studyToolWindow.setStepText(stepText);
219 | }
220 | }
221 |
222 | public static boolean hasJavaFx() {
223 | try {
224 | Class.forName("javafx.application.Platform");
225 | return true;
226 | } catch (ClassNotFoundException e) {
227 | return false;
228 | }
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/utils/MyLogger.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.utils;
2 |
3 | import com.intellij.openapi.diagnostic.Logger;
4 |
5 | public class MyLogger {
6 | private Logger LOG;
7 | private static MyLogger ourInstance = new MyLogger();
8 |
9 | public static MyLogger getInstance() {
10 | return ourInstance;
11 | }
12 |
13 | private MyLogger() {
14 | LOG = Logger.getInstance(MyLogger.class);
15 | }
16 |
17 | public Logger getLOG() {
18 | return LOG;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/utils/NotificationTemplates.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.utils;
2 |
3 | import com.intellij.notification.Notification;
4 | import com.intellij.notification.NotificationType;
5 |
6 | public class NotificationTemplates {
7 | public static final Notification CONNECTION_ERROR =
8 | new Notification("Connection.error", "Connection error", "Please check your internet configuration.", NotificationType.ERROR);
9 |
10 | public static final Notification CERTIFICATE_ERROR =
11 | new Notification("Certificate.error", "Certificate error", "Please check your internet configuration.", NotificationType.ERROR);
12 |
13 | public static final Notification DOWNLOAD_WARNING =
14 | new Notification("Step.download", "Download error", "You didn't send a Step", NotificationType.WARNING);
15 | }
16 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/utils/NotificationUtils.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.utils;
2 |
3 | import com.intellij.notification.Notification;
4 | import com.intellij.openapi.project.Project;
5 |
6 | public class NotificationUtils {
7 | private NotificationUtils() {
8 | }
9 |
10 | public static void initRuntimeException(Notification notification, Project project) {
11 | notification.notify(project);
12 | throw new RuntimeException();
13 | }
14 |
15 | public static void initRuntimeException(Project project) {
16 | initRuntimeException(NotificationTemplates.CONNECTION_ERROR, project);
17 | }
18 |
19 | public static void initRuntimeException(Project project, String text) {
20 | NotificationTemplates.CONNECTION_ERROR.notify(project);
21 | throw new RuntimeException(text);
22 | }
23 |
24 | public static void showNotification(Notification notification, Project project) {
25 | notification.notify(project);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.utils;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.intellij.openapi.vfs.LocalFileSystem;
5 | import org.stepik.plugin.storages.CourseDefinitionStorage;
6 |
7 | import java.util.HashSet;
8 | import java.util.List;
9 | import java.util.Set;
10 |
11 | public class Utils {
12 | public static void refreshFiles(Project project) {
13 | CourseDefinitionStorage projectService = CourseDefinitionStorage.getInstance(project);
14 |
15 | LocalFileSystem lfs = LocalFileSystem.getInstance();
16 | Set set = projectService.getMapPathInfo().keySet();
17 | Set removed = new HashSet<>();
18 | set.forEach(x -> {
19 | if (lfs.findFileByPath(x) == null)
20 | removed.add(x);
21 | });
22 |
23 | projectService.removeAll(removed);
24 | set.removeAll(removed);
25 | }
26 |
27 | public static String normalize(String text) {
28 | String[] words = text.split("\\W+");
29 | StringBuilder sb = new StringBuilder();
30 | for (int i = 0; i < words.length - 1; i++) {
31 | sb.append(words[i] + "_");
32 | }
33 | if (words.length > 0)
34 | sb.append(words[words.length - 1]);
35 | return sb.toString();
36 | }
37 |
38 | public static String getIdQuery(List list) {
39 | StringBuilder sb = new StringBuilder();
40 | sb.append("?");
41 | for (Integer id : list) {
42 | sb.append("ids[]=" + id + "&");
43 | }
44 | return sb.toString();
45 | }
46 |
47 | public static String parseUrl(String url) {
48 | if (url == null || url.isEmpty()) return "";
49 | url = url.trim();
50 | if (Character.isDigit(url.charAt(0))) {
51 | return url;
52 | } else {
53 | String[] path = url.split("/");
54 | if (path[3].equals("course")) {
55 | String tmp[] = path[4].split("-");
56 | return tmp[tmp.length - 1];
57 | }
58 | }
59 | return "";
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/org/stepik/plugin/utils/YaTranslator.java:
--------------------------------------------------------------------------------
1 | package org.stepik.plugin.utils;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.mashape.unirest.http.HttpResponse;
5 | import com.mashape.unirest.http.JsonNode;
6 | import com.mashape.unirest.http.Unirest;
7 | import com.mashape.unirest.http.exceptions.UnirestException;
8 | import org.json.JSONArray;
9 | import org.stepik.plugin.storages.CourseDefinitionStorage;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | public class YaTranslator {
15 | final static private String API_URL = "https://translate.yandex.net/api/v1.5/tr.json/translate";
16 | final static private String APP_KEY = "trnsl.1.1.20160514T085113Z.7ee4b2a3baf18163.933b409b8a7ee466edcb2682f2cec46eadb65f5e";
17 | final static private String TEXT = "text";
18 | final static private String KEY = "key";
19 | final static private String LANG = "lang";
20 | final static private String EN_RU = "en-ru";
21 | final static private String RU_EN = "ru-en";
22 |
23 | public static String translateRuToEn(String text) {
24 | HttpResponse response = null;
25 | try {
26 | response = Unirest
27 | .post(API_URL)
28 | .field(KEY, APP_KEY)
29 | .field(LANG, RU_EN)
30 | .field(TEXT, text)
31 | .asJson();
32 | } catch (UnirestException e) {
33 | e.printStackTrace();
34 | }
35 |
36 | return (String) response.getBody().getObject().getJSONArray(TEXT).get(0);
37 | }
38 |
39 | public static JSONArray translateRuToEn(List list) {
40 | HttpResponse response = null;
41 | try {
42 | response = Unirest
43 | .post(API_URL)
44 | .field(KEY, APP_KEY)
45 | .field(LANG, RU_EN)
46 | .field(TEXT, list)
47 | .asJson();
48 | } catch (UnirestException e) {
49 | e.printStackTrace();
50 | }
51 |
52 | return response.getBody().getObject().getJSONArray(TEXT);
53 | }
54 |
55 | public static List translateNames(List names, String level, Project project) {
56 | CourseDefinitionStorage ws = CourseDefinitionStorage.getInstance(project);
57 | List ans = new ArrayList<>();
58 | if (ws.isTranslate()) {
59 | JSONArray arr = YaTranslator.translateRuToEn(names);
60 | for (int i = 0; i < names.size(); i++) {
61 | ans.add("_" + (i + 1) + "_" + Utils.normalize(arr.getString(i)));
62 | }
63 | } else {
64 | for (int i = 0; i < names.size(); i++) {
65 | ans.add(level + (i + 1));
66 | }
67 | }
68 | return ans;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------