-
Notifications
You must be signed in to change notification settings - Fork 3
Plugable Dialogs
Metingear can be extended easily with 'plugable dialogs'. The scope falls short of a full plugin framework which may be implemented in future but allows quick and easy extension to perform algorithms, edit and create entities by simply adding classes to the java classpath.
To start with we will create a simple dialog that will rename entities in our model with a regular expression.
Metingear exposes the interface ControlDialog
which provides most of tools you will need to 'Control' the UI (User Interface). Although you could specify the entire interface yourself there would be a lot of overhead in handling required some required methods and it is easier to use the abstract class AbstractControlDialog
available in the metingear-extension
module.
public class PatternRename extends AbstractControlDialog {
// constructor needed for instantiation
public PatternRename(Window window){
super(window);
}
}
The next task is to create the Swing UI components for the dialog. The control dialog has a set* layout of three sections; information
, form
and navigation
. The information
provides a brief description of the dialog function, form
provides a location for variable input and the navigation
provides run/close buttons. In most case you will only need to override the creation of information and form sections. Overriding of the navigation is only needed if you have a more complex control structure (e.g. in a wizard a single dialog show multiple forms). For our pattern rename dialog we will
need two text fields for the find/replace strings for this we will use JTextField
from Swing. Although you can use the default JTextField
I recommend using the factories provided by CAF which will make your fields/labels look the same as the rest of the application.
public class PatternRename extends AbstractControlDialog {
private JTextField pattern = FieldFactory.newField(15);
private JTextField replace = FieldFactory.newField(15);
public PatternRename(Window window) {
super(window);
}
@Override
public JComponent createForm() {
Box box = Box.createVerticalBox();
box.add(pattern);
box.add(replace);
return box;
}
}
The above code creates a dialog that looks as so:
To improve the look of the dialog we can add some labels to the input. Form layout can get very complex, to help improve the layout you can use the JGoodies Forms library. The PanelFactory
also has a convenience method to set the JGoodies specification during instantiation
public class PatternRename extends AbstractControlDialog {
private JTextField pattern = FieldFactory.newField(15);
private JTextField replace = FieldFactory.newField(15);
public PatternRename(Window window) {
super(window);
}
@Override
public JLabel createInformation() {
return LabelFactory.newLabel("Rename metabolites using a pattern and a replacement");
}
@Override
public JComponent createForm() {
JPanel panel = PanelFactory.createDialogPanel("p, 4dlu, p:grow",
"p, 4dlu, p");
CellConstraints cc = new CellConstraints();
panel.add(LabelFactory.newFormLabel("Pattern:"), cc.xy(1, 1));
panel.add(pattern, cc.xy(3, 1));
panel.add(LabelFactory.newFormLabel("Replace:"), cc.xy(1, 3));
panel.add(replace, cc.xy(3, 3));
return panel;
}
}
New dialog look:
Now we have our dialog specified we need add the processing. This is done be overriding the processing method with your desired function.
@Override
public void process() {
// get the field values
Pattern pattern = Pattern.compile(this.pattern.getText());
String replacement = replace.getText();
// iterate over selected metabolites and set the name
// replacement if a match is found
for(Metabolite metabolite : getSelection(Metabolite.class)){
String name = metabolite.getName();
Matcher matcher = pattern.matcher(name);
if(matcher.find()){
metabolite.setName(matcher.replaceAll(replacement));
}
}
}
We now need to add additional information about the dialog such as where it will be in the menu, the name of the action as well as the context needed (when it is active). This is achieved via the PlugableDialog
interface. The plugable dialog provides three simple methods:
public interface PlugableDialog {
public List<String> getMenuPath();
public Class<? extends ControlDialog> getDialogClass();
public ContextResponder getContext();
}
-
getMenuPath()
- provides the path on the menu system where the dialog will be added. New menus are automatically created for the dialog if needed. -
getDialogClass()
- provides the class of the dialog (the dialog is instantiated using reflection) -
getContext()
- the context needed for the dialog (e.g. when it is active)
public class PatternRenamePlugin implements PlugableDialog {
@Override
public List<String> getMenuPath() {
// dialog will be on menu Tools>Plugins>...
return Arrays.asList("Tools", "Plugins");
}
@Override
public Class<? extends ControlDialog> getDialogClass() {
// our dialog class
return PatternRename.class;
}
@Override
public ContextResponder getContext() {
return new ContextResponder() {
@Override
public boolean getContext(ReconstructionManager reconstructionManager,
Reconstruction reconstruction,
EntityCollection selection) {
// only available when one or more metabolites are selected
return selection.hasSelection(Metabolite.class);
}
};
}
}
The final step is create the configuration files. The service provider interface requires implementing classes to list themselves in the META-INF/services/*
of the java archive .jar
. We therefore need to create a file uk.ac.ebi.metingear.view.PlugableDialog
and list our new dialog <your.package>.PatternRename
. We also need more information about the menu item. This is provided by an action.properties
file in the same package as the dialog:
PatternRename.Action.Name=Pattern Rename
PatternRename.Action.ShortDescription=Rename metabolites using a given pattern
To run Metingear with the plugin simply include the jar in the classpath (with any additionally required classpaths):
java -Xmx1G -Xms500M -cp Metingear-0.9-SNAPSHOT.jar:sample-extension-1.0.jar uk.ac.ebi.metingear.Main
*Although you can create custom looking dialogs this is outside the scope of this tutorial.