|
Plugin Support API is placed on %VP_SUITE%/lib/openapi.jar. In order to working with VP-UML, developer must import the jar into the development classpaths.
plugin.xml is the base of a plugin, to develop a plugin, should be start from writing the plugin.xml. The basic directory structure is "VP_SUITE_HOME/plugins/YOUR_PLUGIN_ID/plugin.xml"
For improving the variability of the plugin.xml, a properties file (plugin.properties) can be used for storing the value of the xml. Developer can assignment the value of the attributes in xml starts with '%', then the value will be read from the properties file. For example
In plugin.xml: <plugin id="sample.plugin name="%plugin.name" .../>
In plugin.properties: plugin.name=sample.plugin
Sample on XML:
id="sample.plugin"</plugin>
name="Sample Plugin"
description="Sample Plugin"
provider="Visual Paradigm"
class="sample.plugin.SamplePlugin">
<runtime><library path="lib/sampleplugin.jar" relativePath="true"/></runtime>
<!-- to be continued -->
Table shows the description of elements in the plugin.xml.
| Element | Attribute | Description |
|---|---|---|
| plugin | The root element of plugin.xml, specify the basic information of the plugin (id, name, provider, etc...) | |
| plugin | class | The class of the plugin, required to implements com.vp.plugin.VPPlugin. |
| runtime | The element specified the runtime environment of the plugin. | |
| library (1..*) | Specifies the .jar or directory as the classpaths required on the plugin. Such as the classes of the plugin and some libraries the plugin required. | |
| library (1..*) | Path | The path of the .jar or directory. |
| library (1..*) | relativePath (optional, default: true) | Specifies whether the path is relative path. |
Description on Code:
VPPlugin (com.vp.plugin.VPPlugin)
This class must be implemented and ref on <plugin class="xxx"... Otherwise, the plugin will not be loaded completely. In fact, the class can do nothing on it.
The following is the sample code:
// make sure there is a constructor without any parameters}
public void loaded(com.vp.plugin.VPPluginInfo info) {// called when the plugin is loaded}
// developer can get the current plugin's id and the
// current plugin directory (default: %VP_SUITE%/plugins)of VP-UML from the VPPluginInfo.
public void unloaded() {// called when the plugin is unloaded (when the VP-UML will be exited)}
There are 2 main components for an Action: Action and Action Controller. Action represents the outlook, Action Controller responses to work as function call. In order to create custom action, developer needs to define the Action on xml, and implement the Action Controller on code.
Sample on XML:
<actionSets></plugin><!-- to be continued --></actionSets>
<!-- to be continued -->
Table shows the description of elements in the above XML.
| Element | Attribute | Description |
|---|---|---|
| actionSets | It is a collection of ActionSet. There 2 kinds of ActionSet: actionSet and contextSensitiveActionSet. actionSet is a set of actions which will be shown on menu/toolbar or diagram toolbar. contextSensitiveActionSet is set of actions which will be shown on popup menu. |
There are differences on xml definition and code implementation of the 3 kinds of Actions (menu/toolbar, popup menu, diagram toolbar).
Developer can define the menu, menu item, toolbar, toolbar button and etc... on the plugin.xml. In order to trigger the menu item and toolbar button's function call, Action Controller is required to be implemented and added into the Action. The Action Controller class on menu/toolbar actions is com.vp.plugin.action.VPActionController.
There are 2 important attributes used on menu, action and separator: menuPath and toolbarPath.
menuPath is the path specified where is the item placed on menu, toolbarPath is the path specified where is the item placed on toolbar. The path is formed by a set of 'name'. The 'name' is similar with the caption of the menu items (caption in English, ignores the "..." and remind the 'space'). '/' is used as delimiter of the path. '#' is used to represent the front of the menu. 4 examples will be given:
![]() |
|---|
| Figure 2.1 - Customer Action on MenuBar |
Sample on XML:
<toolbar<menuid="sample.plugin.actions.Toolbar1"
orientation="north"
index="last"/>
id="sample.plugin.actions.Menu1"<action
label="Sample Menu 1"
mnemonic="M"
menuPath="Tools/Report"/>
id="sample.plugin.actions.Action1"
actionType="generalAction"
label="Sample Action 1"
tooltip="Sample Action 1"
icon="icons/red.png"
style="normal"
menuPath="Tools/Report"
toolbarPath="sample.plugin.actions.Toolbar1/#">
id="sample.plugin.actions.Separator1"</actionSet>
menuPath="Tools/sample.plugin.actions.Action1"
toolbarPath="sample.plugin.actions.Toolbar1/sample.plugin.action.Action1"/>
Table shows the description of elements in the above XML.
| Element | Attribute | Description |
|---|---|---|
| actionSet | It is a collection of toolbar, menu, action, separator on the toolbar or menu of the plugin. The child elements should be ordered if they have the relationship on the position (e.g. developer prefers Action1 is placed into Menu1, then please define the Menu1 on the xml first). | |
| toolbar (0..*) | Specifies a toolbar, contains the location information of the toolbar. | |
| toolbar (0..*) | orientation [north | east |south | west] | Specifies which side will be the toolbar placed on. |
| toolbar (0..*) | index [(number) | last |new] | Based on the orientation, where will be the toolbar placed. e.g. the orientation is "north" and there is 2 rows toolbars already. If the index is "0", then the toolbar will be placed on the first row's last position. If the index is "last", the toolbar will be placed on the last row, last position. If the index is "new", the toolbar will be placed on the third row (new row). |
| menu (0..*) | Specifies a menu or pull down button on menu bar or toolbar. It contains the outlook information of the menu. | |
| action (0..*) | Specifies a menu item or button on menu bar or toolbar. It contains the outlook information of the menu item. | |
| action (0..*) | actionType [generalAction | shapeAction | connectorAction] (optional, default: generalAction) | There are 3 types: generalAction, shapeAction and connectorAction. As the action on menu/toolbar, generalAction should be assigned. |
| actionController | Specifies the Action Controller for the action (the parent node in the xml). | |
| actionController | class | The class name of the Action Controller. For the action on menu/toolbar, it is required to implement com.vp.plugin.action.VPActionController. |
| separator (0..*) | Specified a separator on menu bar or toolbar. |
Description on Code:
VPActionController (com.vp.plugin.action.VPActionController)
This class is used to perform the function call when the action is clicked. One Action Controller class refers to multi Actions is allowed.
Sample:
// make sure there is an constructor without any parameters}
public void performAction(com.vp.plugin.action.VPAction action) {// called when the button is clicked, the parameter action represents the Action which be clicked.}
// developer also can set the properties of the action
public void updated(com.vp.plugin.action.VPAction action) {// *for the actions located on menu bar only}
// when the parent menu is selected, this will be called,
// developer can set the properties of the action before it is shown (e.g. enable/disable the menu item)
Developer can define the menu, menu item and separator on the popup menu shown on the diagram. The popup menu on diagram is context sensitive which based on what diagram element or diagram is selected. In order to make the menu item trigger the function call, Action Controller is required to be implemented. For popup menu, com.vp.plugin.action.VPContextActionController is the interface required developer to implement.
Same as Action on Menu/Toolbar, menuPath is used to specify the location of the action (menu/menu item on popup menu).
Sample on XML:
<contextTypes all="false"></contextSensitiveActionSet><include type="Class"/></contextTypes>
<!-- ignored when contextTypes.all = true -->
<exclude type="Package"/> <!-- ignored when contextTypes.all = false -->
<actionid="sample.plugin.actions.ContextAction1"</action>
label="Sample Action [1]"
icon="icons/blue.png"
style="toggle"
menuPath="OpenSpecification">
<actionController class="sample.plugin.actions.ContextActionController"/>
Table shows the description of elements in the above XML.
| Element | Attribute | Description |
|---|---|---|
| contextSensitvieActionSet (0..*) | It is a collection of menu, action, separator on the popup menu of the plugin. The child elements should be ordered if they have the relationship on the position (e.g. developer prefers Action1 is placed into Menu1, then please define the Menu1 on the xml first | |
| contextTypes | It is a collection of the model of diagram element of diagram types which the contextSensitiveActionSet is considering. | |
| contextTypes | all [true | false] (optional, default: false) | Specify whether all the types of the models, diagram elements and diagrams will be considered by this actionSet. |
| Include | Specify the model, diagram element or diagram type will be considered by this ActionSet. (This will be ignored if the contextTypes's attribute 'all' is assigned 'true'. | |
| Include | type | It is type of the element. Such as "Class", "Actor", "ClassDiagram", "Attribute", etc... |
| exclude | Specify the model, diagram element or diagram type will not be considered by this ActionSet. (This will be ignored if the contextTypes's attribute 'all' is assigned 'false'. | |
| type | It is type of the element. Such as "Class", "Actor", "ClassDiagram", "Attribute", etc... | |
| actionController | Specifies the Action Controller for the action (the parent node in the xml). | |
| actionController | class | The class name of the Action Controller. For the action on popup menu, it is required to implement com.vp.plugin.action.VPContextActionController. |
Description on Code:
VPContextActionController (com.vp.plugin.action.VPContextActionController)
This class is used to perform the function call when the action is clicked. One Action Controller class refers to multi Actions is allowed.
Sample:
// make sure there is an constructor without any parameters}
public void performAction(com.vp.plugin.action.VPAction action,) {
com.vp.plugin.action.VPContext context,
ActionEvent e// called when the button is clicked}
public void updated(com.vp.plugin.action.VPAction action,) {
com.vp.plugin.action.VPContext context// when the popup menu is selected, this will be called,}
// developer can set the properties of the action before it is shown (e.g. enable/disable the menu item)
VPContext (com.vp.plugin.action.VPContext)
Context will be passed into the Action Controller when the popup menu is shown or action is trigger. It is what the user selected on the diagram, can be model, diagram element or/and diagram.A diagram may contain many diagram elements, when user right-click on the diagram element or the diagram, a popup menu will be shown. So, the context may be diagram element or diagram. However, the diagram element must be contained by diagram, then if popup menu shown on a diagram element, the context must contain both diagram element and diagram. And the diagram element always represents for a model, so that is possible the context contains model, diagram element and diagram as same time. However, sometime, the popup menu is shown for a model only (e.g. select on an attribute of a class, because there is no diagram element for the attribute, the class's diagram element will be contained in the context).
Developer can define the shape of connect on the specified diagram. But it is not allowed to develop a custom model. ActionSet and Action are used on definition of custom diagram element.
Sample on XML:
<action</action>id="sample.plugin.actions.ShapeAction1"
actionType="shapeAction"
label="Sample Action {1}"
tooltip="Sample Action {1}"
icon="icons/yellow.png"
editorToolbarPath="com.vp.diagram.ClassDiagram/Class">
<shapeCreatorInfoshapeType="sample.plugin.shape.Shape1"
defaultWidth="30"
defaultHeight="30"
controllerClass="sample.plugin.actions.ShapeController1"
multilineCaption="false"
captionStyle="north"
resizable="true"/>
id="sample.plugin.actions.ConnectorAction1"
actionType="connectorAction"
label="Sample Action {2}"
tooltip="Sample Action {2}"
icon="icons/green.png"
editorToolbarPath="com.vp.diagram.ClassDiagram/sample.plugin.actions.ShapeAction1">
shapeType="sample.plugin.connector.Connector1"
fromArrowHeadStyle="Arrow1"
toArrowHeadStyle="Arrow2"
fromArrowHeadSize="verySmall"
toArrowHeadSize="large"
dashes="7,10"
lineWeight="3"
connectorStyle="rectilinear">
<connectionRule<connectionRulefromShapeType="sample.plugin.shape.Shape1"
toShapeType="sample.plugin.shape.Shape1"
bidirection="true"/>
fromShapeType="Class"<connectionRule
toShapeType="sample.plugin.shape.Shape1"
bidirection="true"/>
fromShapeType="Package"</connectionRules> </connectorCreatorInfo> </action> </actionSet>
toShapeType="sample.plugin.shape.Shape1"
bidirection="true"/>
Table shows the description of elements in the above XML.
| Element | Attribute | Description |
|---|---|---|
| Action | It is a collection of menu, action, separator on the popup menu of the plugin. The child elements should be ordered if they have the relationship on the position (e.g. developer prefers Action1 is placed into Menu1, then please define the Menu1 on the xml first | |
| Action | actionType[generalAction | shapeAction | connectorAction] (optional, default: generalAction) | There are 3 types: generalAction, shapeAction and connectorAction. As the action for custom shape, "shapeAction" should be assigned. For custom connector, "connectorAction" should be assigned. |
| Action | editorToolbarPath | Specify which diagram toolbar contains this action. e.g. to add a shapeAction on class diagram after the button for creating a new class, "com.vp.diagram.ClassDiagram/Class" should be assigned. "com.vp.diagram.ClassDiagram" is the id of the class diagram. "/" is the delimiter. "Class" is the button id. |
| shapeCreatorInfo | If the actionType is "shapeAction", shapeCreatorInfo is required. It is used to specify the details of the custom shape. | |
| shapeCreatorInfo | shapeType | The shape type assigned by developer, unique value is required. |
| shapeCreatorInfo | captionStyle [center | north | none] (optional) | Specify where the caption of the shape is displayed. |
| shapeCreatorInfo | controllerClass | The class name which the class is responsible to draw the shape on the diagram, com.vp.plugin.diagram.VPShapeController is required to be implemented. com.vp.plugin.diagram.AbstractShapeController is an abstract class of the VPShapeController. |
| connectorCreatorInfo | If the actionType is "connectorShape", connectorCreatorInfo is required. It is used to specify the defails of the custom connector. | |
| connectorCreatorInfo | shapeType | The shape type assigned by developer, unique value is required. |
| connectorCreatorInfo | connectorStyle [oblique | rectilinear] (optional, default: oblique) | Specify the style of the connector. |
| connectorCreatorInfo | fromArrowHeadStyle (optional) | Specify the arrow head style of the "from" side of the connector. |
| connectorCreatorInfo | toArrowHeadStyle (optional) | Specify the arrow head style of the "to" side of the connector. |
| connectorCreatorInfo | fromArrowHeadSize [verySmall | small | medium | large | extraLarge | jumbo | colossal] (optional) | Specify the arrow head size of the "from" side of the connector. |
| connectorCreatorInfo | toArrowHeadSize [verySmall | small | medium | large | extraLarge | jumbo | colossal] (optional) | Specify the arrow head size of the "to" side of the connector. |
| connectorCreatorInfo | dashes (optional) | Specify the dashes pattern of the connector. A list of float, written in the pattern "%f, %f, %f, ...". |
| connectorCreatorInfo | lineWeight (optional) | Specify the weight of the connector. |
| connectorRules | It is a collection of connectorRule. | |
| connectorRule (1..*) | Specify this connector can connect with what diagram element. |
Description on Code:
VPShapeController (com.vp.plugin.diagram.VPShapeController)
It response to handle the outlook of the shape on the diagram.
Sample:
public void drawShape(}Graphics2D g, Paint lineColor, Paint fillColor, Stoke stroke,){
Com.vp.plugin.diagram.VPShapeInfo shapeInfo// draw the shape by the graphics}
// shapeInfo contains the information of the shape, e.g. the bounds of the shape.
public boolean contains(int x, int y, com.vp.plugin.diagram.VPShapeInfo shapeInfo) {// check whether the x, y is inside the shape,}
// it is used to checking what is selected by the user
Plugin Support provides interface for the developer to create, retrieve update and delete the models in VP-UML. The base class of the model is com.vp.plugin.model.IModelElement. All models are contained in the project (com.vp.plugin.model.IProject). Each model has a model type, to access all the model type, please refers to the class com.vp.plugin.model.IModelElementFactory, it is the class to create the models.
Developer can use the model element factory (com.vp.plugin.model.IModelElementFactory) to create the model. Or based on a parent model (com.vp.plugin.model.IModelElementParent) to create a child model.
IModelElementFactory can be access by IModelElementFactory.instance(). It provides the functions to create all the models.
IModelElementParent is subclass of IModelElement. It provides the function to create the child into it. If the parent class is more specified, it may support a more details function to create the child. For example, IClass is subclass of IModelElementParent, it provides createOperation() to create an operation into it.
Sample on Code:
Developer can use the project (com.vp.plugin.model.IProject) or the context (com.vp.plugin.action.VPContext) from ActionController to retrieve the models.
IProject is the project of VP-UML. The project contains all models, diagram and diagram elements. It provides function (modelElementIterator()) for the developer to iterate the models.
VPContext is the context of a popup menu. Developer can access the context by popup menu's action controller (com.vp.plugin.action.VPContextActionController). Context may contain a model element if the popup menu is shown on a diagram element or model.
Sample on Code:
IModelEmenet modelElement = (IModelElement) iter.next();}
// model element retrieved
IModelElement modelElement = context.getModelElement();}
// model element retrieved, but please take care,
// context.getModelElement() may return null if the popup menu is shown for the diagram
// or the selected diagram element doesn't refer to a model element.
IRelationship relationship = (IRelationship) genIter.next();}
// found out the another side's model of the relationship
IModelElement otherModel = relationship.getTo();
IRelationshipEnd relationshipEnd = (IRelationshipEnd) assoIter.next();}
IModelElement otherModel = relationshipEnd.getEndRelationship().getToEnd().getModelElement();
Developer can call a set of get/set methods on a model. Different model type has different properties. For setting and getting the model's property, cast the IModelElement into it sub-class is necessary. For example, developer get the IModelElement from the popup menu's context. Developer check whether the model is a IClass, then developer cast the IModelElement into IClass, and call the function IClass.setVisibility(xxx).
Sample on Code:
IClass classModel = (IClassModel) model;}
// set the class to be 'private'
classModel.setVisibility(IClass.VISIBILITY_PRIVATE);
// set super class
IClass superClassModel = ...; // another class model is retrieved, it will be set to be the previous model's super class
IGeneralization generalizationModel = IModelElementFactory.instance().createGeneralization();
generalizationModel.setFrom(superClassModel);
generalizationModel.setTo(classModel);
// get all "setName" operation from the class and set to be "protected final"
Iterator operationIter = classModel.operationIterator();
while (operationIter.hasNext()) {IOperation operation = (IOperation) operationIter.next();}
if ("setName".equals(operation.getName()) ) {operation.getJavaDetail(true).setJavaFinal(true);}
operation.setVisibility(IOperation.VISIBILITY_PROTECTED);
Developer can delete the model by simple way, just call the IModelElement.delete().
Plugin Support provides interface for the developer to create, retrieve update and delete the diagrams or diagram elements in VP-UML. The base class of the diagram is com.vp.plugin.diagram.IDiagramUIModel. The base class of the diagram element is com.vp.plugin.diagram.DiagramElement. All diagrams are contained in the project (com.vp.plugin.model.IProject). And the diagram elements can be found in the diagrams. The diagram elements can contains by the diagrams.
Developer can create the diagram or diagram element by com.vp.plugin.DiagramManager. DiagramManager can be access by ApplicationManager.instance().getDiagramManager().
Sample on Code:
Developer can use the project (com.vp.plugin.model.IProject) to retrieve the diagrams. Use a diagram (com.vp.plugin.diagram.IDiagramUIModel) to retrieve the contained diagram elements. Or use the context (com.vp.plugin.action.VPContext) from ActionController to retrieve the diagram and/or diagram element.
IProject is the project of VP-UML. The project contains all models, diagram and diagram elements. It provides function (diagramIterator()) for the developer to iterate the diagrams.
IDiagramUIModel is a diagram, which may contain many diagram elements.
VPContext is the context of a popup menu. Developer can access the context by popup menu's action controller (com.vp.plugin.action.VPContextActionController). Context may contain a diagram and/or diagram elements.
Sample on Code:
IDiagramUIModel diagram = (IDiagramUIModel) diagramIter.next();}
/*
* retrieve diagram element from IDiagramUIModel
*/
Iterator diagramElementIter = diagram.diagramElementIterator();
while (diagramElementIter.hasNext()) {IDiagramElement diagramElement = (IDiagramElement) diagramElementIter.next();}
IDiagramUIModel diagram = context.getDiagram();}
IDiagramElement diagramElement = context.getDiagramElement();
// diagramElement may be null, if the popup menu shown for the diagram
IDiagramElement toDiagramElement = connectors[i].getToShape();}
if (toDiagramElement == null) {toDiagramElement = connectors[i].getToConnector();}
IDiagramUIModel provides the functions to set the diagram outlook (size, background, etc...).
IDiagramElement is the super class of IShapeUIModel and IConnectorUIModel. Because there is difference between shape and connector, the IShapeUIModel and IConnectorUIModel provide different set of functions to update them.
Sample Code:
Developer can delete the diagram and diagram element by simple way, just call the IDiagramUIModel.delete() and IDiagramElement.delete().
Since VP-UML may be integrated with different platforms which may not support Swing (e.g. Eclipse, Visual Studio). That may make to hang on the process if using the Swing dialog technology (e.g. JOptionPane and JDialog). So, there is necessary to use a special method to show the dialog with Swing technology.
com.vp.plugin.ViewManager is an interface provides function for developer to show the dialog as same as show dialog by JOptionPane. Besides that, Viewmanager supports developer to show message on VP-UML's message pane and show custom dialog by implementing an interface (com.vp.plugin.view.IDialogHandler).
Same as JOptionPane, to show a dialog, it is better to have a component as the invoker/parent component. To get the component in VP-UML, just call ViewManager.getRootFrame().
ViewManager provides function showMessage(msg:String, msgTabId:String) to show the message on Message Pane. The parameter msg is the content of the message, msgTabId is the id to identify the tab on Message Pane, which can be defined by developer.
![]() |
|---|
| Figure 2.2 |
Sample on Code:
In Swing, we may use the javax.swing.JOptionPane to show a message dialog (e.g. JOptionPane.showMessageDialog(...)). ViewManager provides the functions which simulate the JOptionPane. ViewManger provides a set of showXXXXDialog(...) functions for showing the dialog. The signature of the functions are same with the JOptionPane. Developer need not feel strange on calling the showXXXXDialog(...) functions.
In Swing, we may implement the javax.swing.JDialog and add our component on the dialog's content pane. But in plugin, developer is required to implement an interface com.vp.plugin.view.IDialogHandler to work for the dialog.
IDialogHandler specify the behaviors of a dialog. There are 4 functions need to be implemented
It is called once before the dialog is shown. Developer should return the content of the dialog (similar to the content pane).
It is called after the getComponent(). A dialog is created on VP-UML internally (it still not shown out). Developer can set the outlook of the dialog on prepare(), such as title, bounds and modal, etc... For your convenience, the dialog will be shown on the screen center as default. If developer don't want change the location, there is no necessary to call the setLocation() function.
It is called when the dialog is shown. Developer may need to do something when the dialog is shown, such as checking something before user to input data on the dialog.
It is called when the dialog is closed by the user clicking on the close button of the frame. Developer may not allow the user to close the dialog (e.g. failed on validation check), then please return 'false' on canClosed().
Sample on Code:
private IDialog _dialog;}
private Component _component;
private JTextField _inputField1, _inputField2, _answerField;
public Component getComponent() {this._inputField1 = new JTextField(10);}
this._inputField2 = new JTextField(10);
this._answerField = new JTextField(10);
JLabel addLabel = new JLabel(" + "); JLabel equalLabel = new JLabel(" = ");
JButton okButton = new JButton("Apply");
okButton.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) { ok();}
} );
JPanel pane = new JPanel();
pane.add(this._inputField1); pane.add(addLabel); pane.add(this._inputField2);
pane.add(equalLabel); pane.add(this._answerField); pane.add(okButton);
this._component = pane;
return pane;
public void prepare(IDialog dialog) {this._dialog = dialog;}
dialog.setModal(true);
dialog.setTitle("Maths Test");
dialog.setResizable( false ); dialog.pack();
this._inputField1.setText(String.valueOf((int)(Math.random()*10000)));
this._inputField2.setText(String.valueOf((int)(Math.random()*10000)));
public void shown() {ApplicationManager.instance().getViewManager().showMessageDialog(}
this._component, "Maths Test is started, you have an half hour to finish this test.",
"Maths Test", JOptionPane.INFORMATION_MESSAGE
);
public boolean canClosed() {if (this.checkAnswer()) { return true; }}
else {ApplicationManager.instance().getViewManager().showMessageDialog(}this._component, "Incorrect",);
"Maths Test", JOptionPane.ERROR_MESSAGE
return false;
private void ok() {if ( this.checkAnswer() ) { this._dialog.close(); }}
else {ApplicationManager.instance().getViewManager().showMessageDialog(}this._component, "Incorrect",);
"Maths Test", JOptionPane.ERROR_MESSAGE
private boolean checkAnswer() {try {}int a = Integer.parseInt(this._inputField1.getText());}
int b = Integer.parseInt(this._inputField2.getText());
int c = Integer.parseInt(this._answerField.getText());
return (a+b == c);
catch (Exception ex) { return false; }
|
|
|||||||