devel:plugins:start
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
devel:plugins:start [2018/10/03 14:09] – Added [End result] section alex_chan | devel:plugins:start [2018/10/09 11:10] (current) – removed danil | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Plugin development ====== | ||
- | This exercise aims at developing a basic plugin that enables editing of a new type of graph model in Workcraft. Follow the step-by-step instructions to proceed from the initial setup of the project all the way to the implementation of the model components. If you want to skip some of the steps, then just download the complete plugin source code: <wrap download> | ||
- | |||
- | ===== Project setup ===== | ||
- | |||
- | To begin, create a new project directory called '' | ||
- | |||
- | Next either create or download and add the following '' | ||
- | |||
- | <file shell build.gradle> | ||
- | dependencies { | ||
- | compile project(': | ||
- | } | ||
- | </ | ||
- | |||
- | Now let us call the package for our Exercise01 plugin: '' | ||
- | |||
- | To complete the set up, go to the top directory of Workcraft and follow either step depending on your development IDE: | ||
- | |||
- | For IntelliJ IDEA | ||
- | - Run the '' | ||
- | - Open the '' | ||
- | |||
- | For Eclipse | ||
- | - Run the '' | ||
- | - Once opening Eclipse, ensure that you have selected '' | ||
- | |||
- | If everything has went smoothly, you are now set to go. | ||
- | ===== Module class ===== | ||
- | |||
- | As a first step to creating any new Workcraft plugin, a module class needs to be created. This class is essentially the plugin' | ||
- | |||
- | <file java BasicModule.java> | ||
- | package org.workcraft.plugins.basic; | ||
- | |||
- | import org.workcraft.Framework; | ||
- | import org.workcraft.Module; | ||
- | import org.workcraft.PluginManager; | ||
- | |||
- | public class BasicModule implements Module { | ||
- | |||
- | @Override | ||
- | public String getDescription() { | ||
- | return "Basic Module"; | ||
- | } | ||
- | |||
- | @Override | ||
- | public void init() { | ||
- | final Framework framework = Framework.getInstance(); | ||
- | final PluginManager pm = framework.getPluginManager(); | ||
- | pm.registerModelDescriptor(BasicDescriptor.class); | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | One may notice that inside the '' | ||
- | |||
- | In the case of the '' | ||
- | |||
- | <file java BasicDescriptor.java> | ||
- | package org.workcraft.plugins.basic; | ||
- | |||
- | import org.workcraft.dom.ModelDescriptor; | ||
- | import org.workcraft.dom.VisualModelDescriptor; | ||
- | import org.workcraft.dom.math.MathModel; | ||
- | |||
- | public class BasicDescriptor implements ModelDescriptor { | ||
- | |||
- | @Override | ||
- | public String getDisplayName() { | ||
- | return "Basic Model"; | ||
- | } | ||
- | |||
- | @Override | ||
- | public MathModel createMathModel() { | ||
- | return new Basic(); | ||
- | } | ||
- | |||
- | @Override | ||
- | public VisualModelDescriptor getVisualModelDescriptor() { | ||
- | return new VisualBasicDescriptor(); | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | However, unlike how the '' | ||
- | |||
- | The class does this by implementing the '' | ||
- | |||
- | <file java VisualBasicDescriptor.java> | ||
- | package org.workcraft.plugins.basic; | ||
- | |||
- | import org.workcraft.dom.VisualModelDescriptor; | ||
- | import org.workcraft.dom.math.MathModel; | ||
- | import org.workcraft.dom.visual.VisualModel; | ||
- | |||
- | public class VisualBasicDescriptor implements VisualModelDescriptor { | ||
- | |||
- | @Override | ||
- | public VisualModel create(MathModel mathModel) { | ||
- | if (mathModel instanceof Basic) { | ||
- | return new VisualBasic((Basic) mathModel); | ||
- | } | ||
- | throw new RuntimeException(" | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | As a result, we have registered the '' | ||
- | |||
- | ===== Mathematical layer classes ===== | ||
- | |||
- | To describe how our mathematical model works, we need to first determine its node(s) and their functionality and interactivity with each other. Fortunately, | ||
- | |||
- | For our exercise, we will simply make our '' | ||
- | |||
- | <file java Basic.java> | ||
- | package org.workcraft.plugins.basic; | ||
- | |||
- | import org.workcraft.dom.Container; | ||
- | import org.workcraft.dom.Node; | ||
- | import org.workcraft.dom.math.AbstractMathModel; | ||
- | import org.workcraft.dom.math.MathConnection; | ||
- | import org.workcraft.dom.math.MathNode; | ||
- | import org.workcraft.dom.references.HierarchicalUniqueNameReferenceManager; | ||
- | import org.workcraft.dom.references.ReferenceManager; | ||
- | import org.workcraft.serialisation.References; | ||
- | import org.workcraft.util.Hierarchy; | ||
- | |||
- | public class Basic extends AbstractMathModel { | ||
- | |||
- | public Basic() { | ||
- | this(null); | ||
- | } | ||
- | |||
- | public Basic(Container root) { | ||
- | super(root); | ||
- | } | ||
- | |||
- | public MathConnection connect(Node first, Node second) { | ||
- | MathConnection con = new MathConnection((MathNode) first, (MathNode) second); | ||
- | Hierarchy.getNearestContainer(first, | ||
- | return con; | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | To make our example simple, this model will only make use one type of node that is implemented as a relatively trivial '' | ||
- | |||
- | <file java Vertex.java> | ||
- | package org.workcraft.plugins.basic; | ||
- | |||
- | import org.workcraft.annotations.VisualClass; | ||
- | import org.workcraft.dom.math.MathNode; | ||
- | |||
- | @VisualClass(VisualVertex.class) | ||
- | public class Vertex extends MathNode { | ||
- | } | ||
- | </ | ||
- | |||
- | It is also worth noting that our '' | ||
- | |||
- | ===== Visual layer classes ===== | ||
- | |||
- | When describing our visual model, we need to determine how our node(s) will be represented (visually) and how they connect with each other (using the notation provided by our mathematical model). Again, fortunately most of the necessary core features (for describing any existing/ | ||
- | |||
- | This eventually leads us to creating our '' | ||
- | |||
- | <file java VisualBasic.java> | ||
- | package org.workcraft.plugins.basic; | ||
- | |||
- | import org.workcraft.annotations.DisplayName; | ||
- | import org.workcraft.annotations.ShortName; | ||
- | import org.workcraft.dom.Container; | ||
- | import org.workcraft.dom.Node; | ||
- | import org.workcraft.dom.math.MathConnection; | ||
- | import org.workcraft.dom.visual.AbstractVisualModel; | ||
- | import org.workcraft.dom.visual.VisualComponent; | ||
- | import org.workcraft.dom.visual.VisualGroup; | ||
- | import org.workcraft.dom.visual.connections.VisualConnection; | ||
- | import org.workcraft.exceptions.InvalidConnectionException; | ||
- | import org.workcraft.exceptions.NodeCreationException; | ||
- | import org.workcraft.gui.graph.generators.DefaultNodeGenerator; | ||
- | import org.workcraft.gui.graph.tools.*; | ||
- | import org.workcraft.util.Hierarchy; | ||
- | |||
- | import java.util.ArrayList; | ||
- | import java.util.List; | ||
- | |||
- | @DisplayName(" | ||
- | @ShortName(" | ||
- | public class VisualBasic extends AbstractVisualModel { | ||
- | |||
- | public VisualBasic(Basic model) { | ||
- | this(model, null); | ||
- | } | ||
- | |||
- | public VisualBasic(Basic model, VisualGroup root) { | ||
- | super(model, | ||
- | setGraphEditorTools(); | ||
- | if (root == null) { | ||
- | try { | ||
- | createDefaultFlatStructure(); | ||
- | } catch (NodeCreationException e) { | ||
- | throw new RuntimeException(e); | ||
- | } | ||
- | } | ||
- | } | ||
- | |||
- | private void setGraphEditorTools() { | ||
- | List< | ||
- | tools.add(new SelectionTool()); | ||
- | tools.add(new CommentGeneratorTool()); | ||
- | tools.add(new ConnectionTool()); | ||
- | tools.add(new NodeGeneratorTool(new DefaultNodeGenerator(Vertex.class))); | ||
- | setGraphEditorTools(tools); | ||
- | } | ||
- | |||
- | @Override | ||
- | public void validateConnection(Node first, Node second) throws InvalidConnectionException { | ||
- | if ((first instanceof VisualVertex) && (second instanceof VisualVertex)) return; | ||
- | |||
- | throw new InvalidConnectionException(" | ||
- | } | ||
- | |||
- | @Override | ||
- | public VisualConnection connect(Node first, Node second, MathConnection mConnection) | ||
- | throws InvalidConnectionException { | ||
- | validateConnection(first, | ||
- | |||
- | VisualComponent v1 = (VisualComponent) first; | ||
- | VisualComponent v2 = (VisualComponent) second; | ||
- | Node m1 = v1.getReferencedComponent(); | ||
- | Node m2 = v2.getReferencedComponent(); | ||
- | |||
- | if (mConnection == null) { | ||
- | mConnection = ((Basic) getMathModel()).connect(m1, | ||
- | } | ||
- | VisualConnection vConnection = new VisualConnection(mConnection, | ||
- | Container container = Hierarchy.getNearestContainer(v1, | ||
- | container.add(vConnection); | ||
- | return vConnection; | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | As shown in the annotation tag of our '' | ||
- | |||
- | <file java VisualVertex.java> | ||
- | package org.workcraft.plugins.basic; | ||
- | |||
- | import org.workcraft.dom.visual.DrawRequest; | ||
- | import org.workcraft.dom.visual.VisualComponent; | ||
- | import org.workcraft.gui.Coloriser; | ||
- | |||
- | import java.awt.*; | ||
- | import java.awt.geom.Rectangle2D; | ||
- | |||
- | public class VisualVertex extends VisualComponent { | ||
- | |||
- | public VisualVertex(Vertex vertex) { | ||
- | super(vertex); | ||
- | } | ||
- | |||
- | @Override | ||
- | public void draw(DrawRequest r) { | ||
- | Graphics2D g = r.getGraphics(); | ||
- | |||
- | double xy = -size / 2 + strokeWidth / 2; | ||
- | double wh = size - strokeWidth; | ||
- | Shape shape = new Rectangle2D.Double(xy, | ||
- | |||
- | Color background = r.getDecoration().getBackground(); | ||
- | g.setColor(Coloriser.colorise(getFillColor(), | ||
- | g.fill(shape); | ||
- | |||
- | Color colorisation = r.getDecoration().getColorisation(); | ||
- | g.setColor(Coloriser.colorise(getForegroundColor(), | ||
- | g.setStroke(new BasicStroke((float) strokeWidth)); | ||
- | g.draw(shape); | ||
- | |||
- | drawLabelInLocalSpace(r); | ||
- | drawNameInLocalSpace(r); | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | ===== End result ===== | ||
- | |||
- | Template |
Copyright © 2014-2024 workcraft.org