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