]> Dogcows Code - chaz/vimcoder/blob - src/com/dogcows/VimCoder.java
5841a42e7772fe6847d02793dded2e2a06b86831
[chaz/vimcoder] / src / com / dogcows / VimCoder.java
1
2 package com.dogcows;
3
4 import java.awt.*;
5 import java.awt.event.*;
6 import java.io.*;
7 import java.text.SimpleDateFormat;
8 import java.util.*;
9 import javax.swing.*;
10 import javax.swing.border.*;
11
12 import com.topcoder.client.contestApplet.common.Common;
13 import com.topcoder.client.contestApplet.common.LocalPreferences;
14 import com.topcoder.client.contestant.ProblemComponentModel;
15 import com.topcoder.shared.language.Language;
16 import com.topcoder.shared.problem.Renderer;
17
18 /**
19 * @author Charles McGarvey
20 * The TopCoder Arena editor plug-in providing support for Vim.
21 *
22 * Distributable under the terms and conditions of the 2-clause BSD license;
23 * see the file COPYING for a complete text of the license.
24 */
25 public class VimCoder
26 {
27 /**
28 * The name and version of this plugin.
29 */
30 public final static String version = "VimCoder 0.3.5";
31
32 /**
33 * The website of the plugin project.
34 */
35 public final static String website = "http://github.com/chazmcgarvey/vimcoder";
36
37
38 /**
39 * The first part of the command used to invoke the Vim server.
40 */
41 private static String vimCommand = "gvim";
42
43 /**
44 * The path to the main VimCoder directory.
45 */
46 private static File rootDir;
47 static
48 {
49 if (System.getProperty("os.name").toLowerCase().equals("win"))
50 {
51 vimCommand = "C:\\WINDOWS\\gvim.bat";
52 }
53 rootDir = new File(System.getProperty("user.home") +
54 System.getProperty("file.separator") + ".vimcoder");
55 }
56
57 /**
58 * Whether or not to use the contest name and point value as problem
59 * directory names.
60 */
61 private static boolean contestDirNames = false;
62
63
64 /**
65 * The panel given to the Arena applet when it is requested.
66 */
67 private JPanel panel;
68
69 /**
70 * The text widget where log messages are appended.
71 */
72 private JTextArea logArea;
73
74 /**
75 * The current editor object (or null if there is none).
76 */
77 private Editor editor;
78
79 /**
80 * The configuration panel.
81 */
82 private JDialog configDialog;
83
84
85 /**
86 * The key for the vim command preference.
87 */
88 private final static String VIMCOMMAND = "com.dogcows.VimCoder.config.vimcommand";
89
90 /**
91 * The key for the root directory preference.
92 */
93 private final static String ROOTDIR = "com.dogcows.VimCoder.config.rootdir";
94
95 /**
96 * The key for the problem directory name preference.
97 */
98 private final static String CONTESTDIRNAMES = "com.dogcows.VimCoder.config.contestdirnames";
99
100 /**
101 * The preferences object for storing plugin settings.
102 */
103 private static LocalPreferences prefs = LocalPreferences.getInstance();
104
105
106 /**
107 * Get the command for invoking vim.
108 * @return The command.
109 */
110 public static String getVimCommand()
111 {
112 return vimCommand;
113 }
114
115 /**
116 * Get the storage directory.
117 * @return The directory.
118 */
119 public static File getStorageDirectory()
120 {
121 return rootDir;
122 }
123
124 /**
125 * Get whether or not to save problems in a human-readable directory
126 * structure.
127 * @return The directory name setting.
128 */
129 public static boolean isContestDirNames()
130 {
131 return contestDirNames;
132 }
133
134
135 /**
136 * Instantiate the entry point of the editor plugin.
137 * Sets up the log widget and panel.
138 */
139 public VimCoder()
140 {
141 logArea = new JTextArea();
142 logArea.setForeground(Color.GREEN);
143 logArea.setBackground(Color.BLACK);
144 logArea.setEditable(false);
145 Font font = new Font("Courier", Font.PLAIN, 12);
146 if (font != null) logArea.setFont(font);
147
148 panel = new JPanel(new BorderLayout());
149 panel.add(new JScrollPane(logArea), BorderLayout.CENTER);
150 }
151
152
153 /**
154 * Called by the Arena when the plugin is about to be used.
155 */
156 public void startUsing()
157 {
158 Runnable task = new Runnable()
159 {
160 public void run()
161 {
162 logArea.setText("");
163 }
164 };
165 if (SwingUtilities.isEventDispatchThread())
166 {
167 task.run();
168 }
169 else
170 {
171 SwingUtilities.invokeLater(task);
172 }
173 loadConfiguration();
174 }
175
176 /**
177 * Called by the Arena when the plugin is no longer needed.
178 */
179 public void stopUsing()
180 {
181 editor = null;
182 }
183
184 /**
185 * Called by the Arena to obtain the editor panel which we will use to
186 * show log messages.
187 * @return The editor panel.
188 */
189 public JPanel getEditorPanel()
190 {
191 return panel;
192 }
193
194 /**
195 * Called by the Arena to obtain the current source.
196 * This happens when the user is saving, compiling, and/or submitting.
197 * @return The current source code.
198 * @throws Exception If the source file edited by Vim couldn't be read.
199 */
200 public String getSource() throws Exception
201 {
202 try
203 {
204 String source = editor.getSource();
205 logInfo("Source code uploaded to server.");
206 return source;
207 }
208 catch (Exception exception)
209 {
210 logError("Failed to get source code: " + exception.getLocalizedMessage());
211 throw exception;
212 }
213 }
214
215 /**
216 * Called by the Arena to pass the source it has.
217 * @param source The source code.
218 */
219 public void setSource(String source)
220 {
221 try
222 {
223 editor.setSource(source);
224 logInfo("Source code downloaded from server.");
225 }
226 catch (Exception exception)
227 {
228 logError("Failed to save the source given by the server: " +
229 exception.getLocalizedMessage());
230 return;
231 }
232 }
233
234 /**
235 * Called by the Arena to pass along information about the current
236 * problem.
237 * @param component A container for the particulars of the problem.
238 * @param language The currently selected language.
239 * @param renderer A helper object to help format the problem
240 * statement.
241 */
242 public void setProblemComponent(ProblemComponentModel component,
243 Language language, Renderer renderer)
244 {
245 try
246 {
247 editor = new Editor(component, language, renderer);
248 }
249 catch (Exception exception)
250 {
251 logError("An error occured while loading the problem: " +
252 exception.getLocalizedMessage());
253 }
254 }
255
256 /**
257 * Called by the Arena when it's time to show our configuration panel.
258 */
259 public void configure()
260 {
261 final int border = 10;
262 final int inset = 2;
263
264 loadConfiguration();
265
266 configDialog = new JDialog();
267 Container container = configDialog.getContentPane();
268 container.setForeground(Common.FG_COLOR);
269 container.setBackground(Common.WPB_COLOR);
270
271 JPanel pane = new JPanel();
272 container.add(pane);
273
274 BoxLayout boxLayout = new BoxLayout(pane, BoxLayout.Y_AXIS);
275 pane.setLayout(boxLayout);
276 pane.setBorder(BorderFactory.createEmptyBorder(border, border, border, border));
277
278 JPanel fieldPanel = new JPanel(new GridBagLayout());
279 pane.add(fieldPanel);
280 pane.add(Box.createRigidArea(new Dimension(0, border)));
281
282 GridBagConstraints c = new GridBagConstraints();
283 c.fill = GridBagConstraints.HORIZONTAL;
284 c.insets = new Insets(inset, inset, inset, inset);
285
286 JLabel rootDirLabel = new JLabel("Storage Directory:");
287 rootDirLabel.setForeground(Common.FG_COLOR);
288 c.gridx = 0;
289 c.gridy = 0;
290 c.gridwidth = 1;
291 fieldPanel.add(rootDirLabel, c);
292
293 final JTextField rootDirField = new JTextField(rootDir.getPath());
294 rootDirField.setPreferredSize(new Dimension(0, 24));
295 c.gridx = 1;
296 c.gridy = 0;
297 c.weightx = 1.0;
298 fieldPanel.add(rootDirField, c);
299
300 JButton browseButton = new JButton("Browse");
301 c.gridx = 2;
302 c.gridy = 0;
303 c.weightx = 0.0;
304 c.anchor = GridBagConstraints.BASELINE_LEADING;
305 fieldPanel.add(browseButton, c);
306
307 final JCheckBox contestDirNamesButton = new JCheckBox(
308 "Store problems according to contest name and point value.",
309 contestDirNames
310 );
311 contestDirNamesButton.setForeground(Common.FG_COLOR);
312 contestDirNamesButton.setBackground(Common.WPB_COLOR);
313 contestDirNamesButton.setFont(rootDirLabel.getFont());
314 c.gridx = 1;
315 c.gridy = 1;
316 c.gridwidth = 2;
317 fieldPanel.add(contestDirNamesButton, c);
318
319 JLabel vimCommandLabel = new JLabel("Vim Command:");
320 vimCommandLabel.setForeground(Common.FG_COLOR);
321 c.gridx = 0;
322 c.gridy = 2;
323 c.gridwidth = 1;
324 fieldPanel.add(vimCommandLabel, c);
325
326 final JTextField vimCommandField = new JTextField(vimCommand);
327 vimCommandField.setPreferredSize(new Dimension(0, 24));
328 c.gridx = 1;
329 c.gridy = 2;
330 c.weightx = 1.0;
331 c.gridwidth = 2;
332 fieldPanel.add(vimCommandField, c);
333
334 JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, inset, inset));
335 buttonPanel.setPreferredSize(new Dimension(400, 24 + 2 * inset));
336 pane.add(buttonPanel);
337
338 JButton saveButton = new JButton("Save");
339 buttonPanel.add(saveButton);
340 buttonPanel.add(Box.createRigidArea(new Dimension(1, 0)));
341
342 JButton closeButton = new JButton("Close");
343 buttonPanel.add(closeButton);
344
345 browseButton.addActionListener(new ActionListener()
346 {
347 public void actionPerformed(ActionEvent actionEvent)
348 {
349 JFileChooser chooser = new JFileChooser();
350 chooser.setCurrentDirectory(new File("."));
351 chooser.setDialogTitle("Choose Storage Directory");
352 chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
353 chooser.setAcceptAllFileFilterUsed(false);
354
355 if (chooser.showOpenDialog(configDialog) == JFileChooser.APPROVE_OPTION)
356 {
357 rootDirField.setText(chooser.getSelectedFile().getPath());
358 }
359 }
360 });
361
362 closeButton.addActionListener(new ActionListener()
363 {
364 public void actionPerformed(ActionEvent actionEvent)
365 {
366 configDialog.dispose();
367 }
368 });
369
370 saveButton.addActionListener(new ActionListener()
371 {
372 public void actionPerformed(ActionEvent actionEvent)
373 {
374 prefs.setProperty(VIMCOMMAND, vimCommandField.getText());
375 prefs.setProperty(ROOTDIR, rootDirField.getText());
376 prefs.setProperty(CONTESTDIRNAMES, String.valueOf(contestDirNamesButton.isSelected()));
377 JOptionPane.showMessageDialog(null, "Preferences were saved successfully.");
378 }
379 });
380
381 configDialog.setTitle("VimCoder Preferences");
382 configDialog.pack();
383 configDialog.setLocationRelativeTo(null); // Center dialog in screen.
384 configDialog.setModalityType(Dialog.DEFAULT_MODALITY_TYPE);
385 configDialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
386 configDialog.setVisible(true);
387 }
388
389
390 /**
391 * Load the local preferences related to this plugin.
392 */
393 private void loadConfiguration()
394 {
395 String vc = prefs.getProperty(VIMCOMMAND);
396 if (vc != null) vimCommand = vc;
397
398 String dir = prefs.getProperty(ROOTDIR);
399 if (dir != null) rootDir = new File(dir);
400
401 String cn = prefs.getProperty(CONTESTDIRNAMES);
402 if (cn != null) contestDirNames = Boolean.parseBoolean(cn);
403 }
404
405
406 /**
407 * A generic logging function, appends text to the text area. A timestamp
408 * is also prepended to the next text.
409 * @param what The text to append.
410 */
411 private void log(final String what)
412 {
413 Runnable task = new Runnable()
414 {
415 public void run()
416 {
417 SimpleDateFormat format = new SimpleDateFormat("kk:mm:ss");
418 logArea.append(format.format(new Date()) + ", " + what);
419 }
420 };
421 if (SwingUtilities.isEventDispatchThread())
422 {
423 task.run();
424 }
425 else
426 {
427 SwingUtilities.invokeLater(task);
428 }
429 }
430
431 /**
432 * Output non-critical messages to the log.
433 * @param what The text of the message.
434 */
435 private void logInfo(String what)
436 {
437 log(" INFO: " + what + System.getProperty("line.separator"));
438 }
439
440 /**
441 * Output critical messages and errors to the log.
442 * @param what The text of the message.
443 */
444 private void logError(String what)
445 {
446 log("ERROR: " + what + System.getProperty("line.separator"));
447 }
448 }
449
450 // vim:noet:ts=8
This page took 0.050756 seconds and 3 git commands to generate.