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