5 import java
.awt
.event
.*;
7 import java
.text
.SimpleDateFormat
;
10 import javax
.swing
.border
.*;
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
;
19 * @author Charles McGarvey
20 * The TopCoder Arena editor plug-in providing support for Vim.
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.
28 * The name and version of this plugin.
30 public final static String version
= "VimCoder 0.3.4";
33 * The website of the plugin project.
35 public final static String website
= "http://github.com/chazmcgarvey/vimcoder";
39 * The first part of the command used to invoke the Vim server.
41 private static String vimCommand
= "gvim";
44 * The path to the main VimCoder directory.
46 private static File rootDir
;
49 if (System
.getProperty("os.name").toLowerCase().equals("win"))
51 vimCommand
= "C:\\WINDOWS\\gvim.bat";
53 rootDir
= new File(System
.getProperty("user.home") +
54 System
.getProperty("file.separator") + ".vimcoder");
58 * Whether or not to use the contest name and point value as problem
61 private static boolean contestDirNames
= false;
65 * The panel given to the Arena applet when it is requested.
70 * The text widget where log messages are appended.
72 private JTextArea logArea
;
75 * The current editor object (or null if there is none).
77 private Editor editor
;
80 * The configuration panel.
82 private JDialog configDialog
;
86 * The key for the vim command preference.
88 private final static String VIMCOMMAND
= "com.dogcows.VimCoder.config.vimcommand";
91 * The key for the root directory preference.
93 private final static String ROOTDIR
= "com.dogcows.VimCoder.config.rootdir";
96 * The key for the problem directory name preference.
98 private final static String CONTESTDIRNAMES
= "com.dogcows.VimCoder.config.contestdirnames";
101 * The preferences object for storing plugin settings.
103 private static LocalPreferences prefs
= LocalPreferences
.getInstance();
107 * Get the command for invoking vim.
108 * @return The command.
110 public static String
getVimCommand()
116 * Get the storage directory.
117 * @return The directory.
119 public static File
getStorageDirectory()
125 * Get whether or not to save problems in a human-readable directory
127 * @return The directory name setting.
129 public static boolean isContestDirNames()
131 return contestDirNames
;
136 * Instantiate the entry point of the editor plugin.
137 * Sets up the log widget and panel.
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
);
148 panel
= new JPanel(new BorderLayout());
149 panel
.add(new JScrollPane(logArea
), BorderLayout
.CENTER
);
154 * Called by the Arena when the plugin is about to be used.
156 public void startUsing()
158 Runnable task
= new Runnable()
165 if (SwingUtilities
.isEventDispatchThread())
171 SwingUtilities
.invokeLater(task
);
177 * Called by the Arena when the plugin is no longer needed.
179 public void stopUsing()
185 * Called by the Arena to obtain the editor panel which we will use to
187 * @return The editor panel.
189 public JPanel
getEditorPanel()
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.
200 public String
getSource() throws Exception
204 String source
= editor
.getSource();
205 logInfo("Source code uploaded to server.");
208 catch (Exception exception
)
210 logError("Failed to get source code: " + exception
.getLocalizedMessage());
216 * Called by the Arena to pass the source it has.
217 * @param source The source code.
219 public void setSource(String source
)
223 editor
.setSource(source
);
224 logInfo("Source code downloaded from server.");
226 catch (Exception exception
)
228 logError("Failed to save the source given by the server: " +
229 exception
.getLocalizedMessage());
235 * Called by the Arena to pass along information about the current
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
242 public void setProblemComponent(ProblemComponentModel component
,
243 Language language
, Renderer renderer
)
247 editor
= new Editor(component
, language
, renderer
);
249 catch (Exception exception
)
251 logError("An error occured while loading the problem: " +
252 exception
.getLocalizedMessage());
257 * Called by the Arena when it's time to show our configuration panel.
259 public void configure()
261 final int border
= 10;
266 configDialog
= new JDialog();
267 Container container
= configDialog
.getContentPane();
268 container
.setForeground(Common
.FG_COLOR
);
269 container
.setBackground(Common
.WPB_COLOR
);
271 JPanel pane
= new JPanel();
274 BoxLayout boxLayout
= new BoxLayout(pane
, BoxLayout
.Y_AXIS
);
275 pane
.setLayout(boxLayout
);
276 pane
.setBorder(BorderFactory
.createEmptyBorder(border
, border
, border
, border
));
278 JPanel fieldPanel
= new JPanel(new GridBagLayout());
279 pane
.add(fieldPanel
);
280 pane
.add(Box
.createRigidArea(new Dimension(0, border
)));
282 GridBagConstraints c
= new GridBagConstraints();
283 c
.fill
= GridBagConstraints
.HORIZONTAL
;
284 c
.insets
= new Insets(inset
, inset
, inset
, inset
);
286 JLabel rootDirLabel
= new JLabel("Storage Directory:");
287 rootDirLabel
.setForeground(Common
.FG_COLOR
);
291 fieldPanel
.add(rootDirLabel
, c
);
293 final JTextField rootDirField
= new JTextField(rootDir
.getPath());
294 rootDirField
.setPreferredSize(new Dimension(0, 24));
298 fieldPanel
.add(rootDirField
, c
);
300 JButton browseButton
= new JButton("Browse");
304 c
.anchor
= GridBagConstraints
.BASELINE_LEADING
;
305 fieldPanel
.add(browseButton
, c
);
307 final JCheckBox contestDirNamesButton
= new JCheckBox(
308 "Store problems according to contest name and point value.",
311 contestDirNamesButton
.setForeground(Common
.FG_COLOR
);
312 contestDirNamesButton
.setBackground(Common
.WPB_COLOR
);
313 contestDirNamesButton
.setFont(rootDirLabel
.getFont());
317 fieldPanel
.add(contestDirNamesButton
, c
);
319 JLabel vimCommandLabel
= new JLabel("Vim Command:");
320 vimCommandLabel
.setForeground(Common
.FG_COLOR
);
324 fieldPanel
.add(vimCommandLabel
, c
);
326 final JTextField vimCommandField
= new JTextField(vimCommand
);
327 vimCommandField
.setPreferredSize(new Dimension(0, 24));
332 fieldPanel
.add(vimCommandField
, c
);
334 JPanel buttonPanel
= new JPanel(new FlowLayout(FlowLayout
.TRAILING
, inset
, inset
));
335 buttonPanel
.setPreferredSize(new Dimension(400, 24 + 2 * inset
));
336 pane
.add(buttonPanel
);
338 JButton saveButton
= new JButton("Save");
339 buttonPanel
.add(saveButton
);
340 buttonPanel
.add(Box
.createRigidArea(new Dimension(1, 0)));
342 JButton closeButton
= new JButton("Close");
343 buttonPanel
.add(closeButton
);
345 browseButton
.addActionListener(new ActionListener()
347 public void actionPerformed(ActionEvent actionEvent
)
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);
355 if (chooser
.showOpenDialog(configDialog
) == JFileChooser
.APPROVE_OPTION
)
357 rootDirField
.setText(chooser
.getSelectedFile().getPath());
362 closeButton
.addActionListener(new ActionListener()
364 public void actionPerformed(ActionEvent actionEvent
)
366 configDialog
.dispose();
370 saveButton
.addActionListener(new ActionListener()
372 public void actionPerformed(ActionEvent actionEvent
)
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.");
381 configDialog
.setTitle("VimCoder Preferences");
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);
391 * Load the local preferences related to this plugin.
393 private void loadConfiguration()
395 String vc
= prefs
.getProperty(VIMCOMMAND
);
396 if (vc
!= null) vimCommand
= vc
;
398 String dir
= prefs
.getProperty(ROOTDIR
);
399 if (dir
!= null) rootDir
= new File(dir
);
401 String cn
= prefs
.getProperty(CONTESTDIRNAMES
);
402 if (cn
!= null) contestDirNames
= Boolean
.parseBoolean(cn
);
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.
411 private void log(final String what
)
413 Runnable task
= new Runnable()
417 SimpleDateFormat format
= new SimpleDateFormat("kk:mm:ss");
418 logArea
.append(format
.format(new Date()) + ", " + what
);
421 if (SwingUtilities
.isEventDispatchThread())
427 SwingUtilities
.invokeLater(task
);
432 * Output non-critical messages to the log.
433 * @param what The text of the message.
435 private void logInfo(String what
)
437 log(" INFO: " + what
+ System
.getProperty("line.separator"));
441 * Output critical messages and errors to the log.
442 * @param what The text of the message.
444 private void logError(String what
)
446 log("ERROR: " + what
+ System
.getProperty("line.separator"));