kawigi
Class KawigiEdit
java.lang.Object
kawigi.KawigiEdit
public class KawigiEdit
- extends java.lang.Object
This class is the actual TopCoder arena plugin.
When KawigiEdit is run as a plugin, this is where everything basically
starts.
Kawigi's Discourse on KawigiEdit's Source Code
You'll notice that most of KawigiEdit's source code files don't know
anything about TopCoder classes (this one is necessarily an exception, since
the plugin interface needs to pass me TopCoder-defined objects). This is to
make it so that KawigiEdit can be run as a standalone application without
ContestApplet.jar needing to be in the classpath. The classes that do still
reference TopCoder classes directly are currently:
- kawigi.KawigiEdit (for reasons mentioned above)
- kawigi.properties.TCPrefs (in general, this will be referenced by
the kawigi.properties.PrefProxy interface, which is TopCoder-agnostic
and has another implementation for Standalone mode)
- kawigi.problem.TCProblemConverter, which converts TopCoder's
ProblemComponent and Language objects into KawigiEdit objects to be used
by the rest of the application. This is also usually called through an
interface, but it has different calling semantics than the standalone
equivalent, which is the ProblemParser (and it works better).
Aside from classes that have to decide whether to use those classes or
standalone classes, the only thing that currently requires the code to check
which mode we're in is the action for the Generate Code button, which does
something completely different in standalone mode than in plugin mode. In
general, where possible, any additions made to KawigiEdit should try to
conform to that convention where a class is either strictly specific to
plugin mode or doesn't reference TC classes directly. An interface/factory
pattern is an easy way to do this in most cases.
I'm assuming that people wanting to modify KawigiEdit will start by looking
at this file. There isn't much here in the way of juicy code, but that does
make it an opportune place to describe the general organization of the code
and make suggestions on how to modify it if you so desire. Note that the
HTML will be more readable if you look at the javadocs that should have been
in the jar with any official release of KawigiEdit.
First, here's a rundown of what's in each package. For those of you who are
less initiated in Java, a package is basically a folder full of classes. In
KawigiEdit, the source files are found in those folders along with the class
files. The kawigi package is found in the kawigi
folder, and the kawigi.cmd package is found in the
kawigi/cmd folder. Also, the source code for each public class
is always in a source code file of the same name, so the source code for
kawigi.cmd.ActID is in kawigi\cmd\ActID.java.
- kawigi.* - Just has
KawigiEdit (the plugin) and
KawigiEditStandalone (the standalone executable).
- kawigi.cmd.* - This contains KawigiEdit 2.0's new command and
UI infrastructures. A pretty large percentage of what actually
happens in KawigiEdit, when you click on buttons, use context
menus, add snippets, hit keystrokes in the editor, or even just open up
KawigiEdit, stuff is happening in this package. The classes in this
package fall into a few categories:
- Most of the classes here are Action classes. Each Action class
manages properties and execution of some set of related commands.
- A few of the classes are Context classes - these hold data that
instances of some Action might need to share.
- There are two public enums in this package - ActID and MenuID.
Both of these may be important to you if you want to add commands
to KawigiEdit. Also, reading through ActID.java will give you a
good idea of what KawigiEdit knows how to do.
- There are two very important classes that are the core
implementation of command/action processing and GUIs in KawigiEdit.
the Dispatcher class is KawigiEdit 2.0's command
infrastructure, and one could theoretically use it and some ActIDs
to automate certain processes in KawigiEdit beyond what is already
done. The UIHandler class is KawigiEdit 2.0's UI infrastructure.
Its main purpose is to read .ui files (either loaded from resources
or from customizations saved locally by the user). The .ui files
are XML files that specify the hierarchy and organization of some
GUI container, and the UIHandler basically reads these and converts
them into GUI components. It also binds these GUI components to
the appropriate actions from the Dispatcher and saves off important
controls to the Dispatcher for use by the Actions.
- The WindowListener implementation for KawigiEditStandalone is
also in this package, mainly for lack of a better place to put it.
- kawigi.editor.* - This package has the implementation behind
the editor part of KawigiEdit. This includes:
- Classes that customize the editor window itself -
CodePane, ConfigurableEditorKit and
ObedientViewFactory.
- "View" classes, which manage rendering the text. That includes
syntax highlighting and any other rendering actions.
- There are a few "accessory" classes that do things that go
around the editor itself -
Interval,
LineNumbers and EditorPanel.
- Finally, there's the
KawigiEditKeyMap, which sort
of connects the kawigi.editor package to the
kawigi.cmd package by mapping keystrokes to actions.
- kawigi.language.* - This package is responsible for
supporting language-specific features besides syntax highlighting. This
includes:
- Two fairly important enums,
EditorLanguage and
EditorDataType, which are basically KawigiEdit's
versions of classes defined by TopCoder. Aside from the obvious
stuff, the EditorLanguage enum is the way to get language-specfic
settings (like how to save, compile and run code in that language),
and it also has a method called fixLiteral, which is the result of
lots of learning about where it's harder to generate valid testing
code in various languages. Fixing these problems in the past has
sometimes destablized other code generation scenarios, but in the
end, KawigiEdit should generate valid and correct testing code for
all languages all the time. The LanguageFactory class
can be used to get EditorLanguages by name.
- The rest of the classes in this package are test code generators
for each language.
- kawigi.problem.* - This package has problem description and
code-generation stuff that isn't language-specific:
- Some of these are representations of parts of the problem -
ClassDecl, MethodDecl and
Test.
- Some are used to create
ClassDecls -
ClassDeclGenerator, ProblemParser,
TCProblemConverter and ClassDeclFactory.
Skeleton and TemplateGenerator are
related to skeleton code generation.
- kawigi.properties.* - This package is how KawigiEdit manages
preferences and settings. Outside packages will basically always access
this functionality through the
PrefFactory class and the
PrefProxy interface. The only PrefProxy
implementation that should ever really be referenced directly outside of
this package is the ChainedPrefs class, which is used
directly by the config dialog. Perhaps the other implementations
shouldn't even be public, but I don't have a good enough reason to
"lock" them up.
- kawigi.util.* - Usually, "util" packages in Java are a wide
variety of helpful classes that don't belong anywhere else, but this
package is mostly pretty unified. The only odd-ball class in here is
the AppEnvironment enum, which keeps track of what mode KawigiEdit is
running in (standalone or plugin mode). All the other classes in here
are used to enable KawigiEdit to start and manage native processes,
which enables language-independent compiling and running of test code.
The
ProcessContainer class executes a process, capturing
the output from the process using to asynchronous
ProcessOutputs which display output on an implementation of
ConsoleDisplay. If the process doesn't terminate in a
reasonable amount of time (configured by the user), the
KillThread will attempt to end the process forcibly.
- kawigi.widget.* - I'm a user interface programmer at heart,
so in that sense, it shouldn't be surprising that the package with all
my custom controls is one of the biggest packages in KawigiEdit. Well,
don't be alarmed about it. A class ended up here in one of a few ways:
- Java's implementation of some control didn't adequately support
some property I needed to expose through Actions in order to fit
things in my command infrastructure. These won't appear to be
real custom widgets to the user, they look just like Java's default
stuff. This is what
ActionLabel,
ActionSpinner, ActionStateCheckBox,
ActionStateRadioButton, ActionTextField
and HideableButton are.
- It was more convenient either for .ui XML or for mapping Actions
to groups of UI elements to make a special or aggregated control.
Again, these won't look like particularly exciting custom widgets.
This includes
FilePanel, FontPanel,
HorizontalPanel and VerticalPanel.
- I required a control to do something somewhat abnormal, and it
easiest to subclass an existing control and add the functionality
this way. This includes
Snippet and
Category, as well as
SimpleOutputComponent.
- I really just wanted a control type that just plain didn't exist
in Java. This explains the
ColorSwatch,
ColorSwatchDropdown and ProblemTimer.
- The last few classes are just things used by the custom control
classes (
ProblemTimingInfo is needed by
ProblemTimer, ChipIcon is used by
ColorSwatchDropdown).
Next, it might be useful to understand the resources included with and used
by KawigiEdit.
Aside from a bunch of icons and images (that are mostly referenced in
ActID.java, although some aren't used), there are four .words files directly
in the rc folder, one for each language. These are text files that contain
keywords and tokens and how the Views should highlight them.
Then there's a folder called rc/templates which contains the default
template for each language. There's no reason to change these directly,
since you can set it to use a modified version of the template using the
KawigiEdit settings dialog. If you think one of the templates should be
modified for everyone, let me know.
Finally, there's a folder called rc/ui which has a bunch of .ui files in it.
The .ui files are XML representations of GUI hierarchies, and each one is
loaded for different reasons (kawigi/cmd/MenuID.java will give you some idea
of what each one is for). If you want to change the organization of the UI
in KawigiEdit, you can edit these directly, or alternatively, you can write
your own version and save it somewhere, then change your config file
(contestapplet.conf for KawigiEdit as a plugin, or KawigiEdit.properties in
standalone mode) to set a property called
kawigi.ui.[a name from MenuID.java] to be the path to your
version of the .ui file.
Perhaps I'll someday make a way to easily add commands to KawigiEdit without
modifying KawigiEdit at all. While I don't mind people hacking up
KawigiEdit to their liking, it makes it hard for people to upgrade to a new
version, so consider that if you want to make private modifications to the
source code and try to make it as easy as possible to re-modify the
KawigiEdit sources you touched. For now, the best way to add commands to
KawigiEdit is basically like this:
- Create a class (perhaps in your own package) that extends
kawigi.cmd.DefaultAction. The constructor of your action
should take an ActID as a parameter if it's a global action or an ActID
and CodePane as parameters if it's an editing action.
- Edit ActID.java and add elements to that enum for any commands you
want to make. You can use the existing commands as a pattern, and you
want to use your own action class as the class for your commands. You
may need to use a fully qualified classname for it to be found (i.e.
package.classname.class).
- Implement what should happen when your command is executed in the
actionPerformed method of your action class. You may also
want to customize the behavior of isEnabled or
isVisible (note that isVisible won't work on
many control types) and the getProperty and
putProperty methods for overriding other properties.
- If you want to access your commands by keystrokes, you'll have to
modify
kawigi.editor.KawigiEditKeyMap to recognize those
keystrokes.
- If you want your commands to be accessed by buttons or context menu
items, follow the instructions above to customize .ui files. You may
want to make a copy of the existing .ui file to use as a starting point.
Feel free to use other .ui files as examples as well. If you want to
make a whole new dialog or window or menu or something, you may have to
add an entry to MenuID.java (although you can decide whether to add a
.ui file to rc/ui or not - I think if you have the ui customized in the
config files, it doesn't really matter if the resource file exists.
Then you'll have to write the code to make that UI show up at the right
time.
Consider that you may not actually need to write code to customize
KawigiEdit to your liking - for instance, if all you want to do is add a
button to the main KawigiEdit UI that inserts your tokenizer, you could
just customize Plugin.ui to include a Snippet item there and hardcode your
tokenizer code (with appropriate XML escape sequences) into your version of
Plugin.ui.
If you want to add some kind of post-processing to your code before saving
it locally, you probably need to modify
kawigi.cmd.LocalTestAction.saveLocal(). I'm fairly certain
that someday there will be something which allows you to do this without
modifying KawigiEdit, I'm just not exactly sure what it will look like.
On the other hand, if you want to add some kind of post-processing to your
code before submitting it to TopCoder, you should modify
kawigi.KawigiEdit.getSource(). Again, it's pretty likely that
this will be specifically addressed in some way in a future version of
KawigiEdit.
|
Constructor Summary |
KawigiEdit()
KawigiEdit plugin constructor - sets the AppEnvironment to PluginMode. |
|
Method Summary |
void |
clear()
Empties the text pane. |
void |
configure()
Brings up a configure dialog to set options in the editor plugin. |
javax.swing.JPanel |
getEditorPanel()
Returns the magic KawigiEdit panel. |
java.lang.String |
getSource()
Returns the text in the editor. |
void |
install()
Verifies or sets several properties used by parts of the editor to set
up. |
void |
setName(java.lang.String n)
Sets the name given to this plugin. |
void |
setProblemComponent(com.topcoder.client.contestant.ProblemComponentModel component,
com.topcoder.shared.language.Language lang,
com.topcoder.shared.problem.Renderer renderer)
Notifies the editor of a new problem being opened, or the language
being changed, or whatever. |
void |
setSource(java.lang.String source)
Sets the text in the editor. |
void |
setTextEnabled(java.lang.Boolean b)
Enables/disables the text pane. |
void |
startUsing()
Clears the text pane for a new problem. |
void |
stopUsing()
Doesn't do anything. |
| Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
KawigiEdit
public KawigiEdit()
- KawigiEdit plugin constructor - sets the AppEnvironment to PluginMode.
getEditorPanel
public javax.swing.JPanel getEditorPanel()
- Returns the magic KawigiEdit panel.
From the TopCoder plugin interface.
getSource
public java.lang.String getSource()
- Returns the text in the editor.
This is the text that TopCoder thinks is in the editor - what it saves
remotely, compiles, tests and submits. This is the code that can't
break the UCR ;-)
From the TopCoder plugin interface.
setSource
public void setSource(java.lang.String source)
- Sets the text in the editor.
This implementation will ignore the request if the source provided is empty.
This is to maintain auto-generated code. Note that if you get code from
TC and you want to keep it but use it for testing, you'll have to stick
a <%:testing-code%> tag in there wherever the main method/testing code
should be.
From the TopCoder plugin interface.
clear
public void clear()
- Empties the text pane.
From the TopCoder plugin interface.
setTextEnabled
public void setTextEnabled(java.lang.Boolean b)
- Enables/disables the text pane.
I've considered ignoring this request, I think TC just started actually
calling it, but it doesn't get called consistently (like it might not
be called if you close and reopen the problem).
From the TopCoder plugin interface.
setProblemComponent
public void setProblemComponent(com.topcoder.client.contestant.ProblemComponentModel component,
com.topcoder.shared.language.Language lang,
com.topcoder.shared.problem.Renderer renderer)
- Notifies the editor of a new problem being opened, or the language
being changed, or whatever.
If the editor is empty, we will generate skeleton code.
From the TopCoder plugin interface.
startUsing
public void startUsing()
- Clears the text pane for a new problem.
From the TopCoder plugin interface.
stopUsing
public void stopUsing()
- Doesn't do anything.
From the TopCoder plugin interface.
configure
public void configure()
- Brings up a configure dialog to set options in the editor plugin.
From the TopCoder plugin interface.
install
public void install()
- Verifies or sets several properties used by parts of the editor to set
up.
For awhile, I was using this, but all the code pretty much checks to
make sure I have all my configurations intact. I may start using this
again very soon to offer an optional wizard-like initial configuration.
From the TopCoder plugin interface.
setName
public void setName(java.lang.String n)
- Sets the name given to this plugin.
From the TopCoder plugin interface.