User Tools

Site Tools


tutorials:create-groimp-plugin

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorials:create-groimp-plugin [2024/12/05 23:57] – [Change the main data] gaetantutorials:create-groimp-plugin [2024/12/06 08:54] (current) gaetan
Line 1: Line 1:
 This tutorial aims at showing how to get started on GroIMP plugin development. It is assumed that you are able to compile the plugin using Maven (either the plugin alone, or the whole project). This tutorial aims at showing how to get started on GroIMP plugin development. It is assumed that you are able to compile the plugin using Maven (either the plugin alone, or the whole project).
-In this tutorial we are going to create a new plugin (from the empty template), add a new MimeType (format of file accepted by GroIMP) for both import and export, and add a menu item that run a specific command.+In this tutorial we are going to create a new plugin (from the empty template), add a new MimeType (format of file accepted by GroIMP) for import, and add a menu item that run a specific command.
  
 See: See:
Line 22: Line 22:
  
 A plugin requires to: have a maven (pom) file working, and a groimp (plugin.xml) file working. A plugin requires to: have a maven (pom) file working, and a groimp (plugin.xml) file working.
 +
 +=== Pom file ===
  
 Let's start with the maven file:  Let's start with the maven file: 
Line 33: Line 35:
 </code> </code>
  
-  * The plugin needs a java name, this is the java identifier of the plugin. Here we can use template.plugin.tutorial.+  * The plugin needs a java name, this is the java identifier of the plugin. Here we can use template.tutorial.
 <code xml> <code xml>
-<artifactId>template.plugin.tutorial</artifactId>+<artifactId>template.tutorial</artifactId>
 </code> </code>
  
Line 51: Line 53:
   </dependencies>   </dependencies>
 </code> </code>
 +
 +Replace x.x by the version you want to use, 2.1.5 for instance.
 +
 +=== Plugin xml ===
  
 Now, we need to change the GroIMP files, go in the directory ''src/main/resources'' and open plugin.xml: Now, we need to change the GroIMP files, go in the directory ''src/main/resources'' and open plugin.xml:
-  * The plugin id should match the java id:#+  * The plugin id should match the java id:
 <code xml> <code xml>
 <plugin <plugin
-  id="de.grogra.template.plugin.tutorial"+  id="de.grogra.template.tutorial"
   ...   ...
 </code> </code>
   * The file name must match the directory name:   * The file name must match the directory name:
 <code xml> <code xml>
-  <library file="newplugin" prefixes="{de.grogra.template.plugin.tutorial}"/>+  <library file="newplugin" prefixes="{de.grogra.template.tutorial}"/>
 </code> </code>
   * All imports must also be declared here:   * All imports must also be declared here:
 <code xml> <code xml>
-  <import plugin="de.grogra.graph"/>+  <import plugin="de.grogra.pf"/>
   ...   ...
 +</code>
 +
 +=== Plugin properties ===
 +
 +Now edit the ''plugin.properties'' file to update the plugin name, it needs to match the directory name:
 +<code>
 +pluginName = newplugin
 +</code>
 +
 +=== Java module and package info ===
 +
 +Now we need to change the base java files: the module-info and the package name.
 +First, open the ''src/main/java/module.info'' file and update the plugin name:
 +<code java>
 +module template.tutorial {
 + exports de.grogra.template.tutorial;
 +
 + requires graph;
 +}
 +</code>
 +
 +  * The module name needs to be the same as the ''<artifactId>template.tutorial</artifactId>'' from the pom.xml file.
 +  * The ''exports de.grogra.template.tutorial;'' must match the java package name, i.e. the name of the sub folders from here.
 +  * All dependencies must be declared here with ''requires ...''.
 +
 +Then, the name of the package should be updated, we just called it //de.grogra.template.tutorial//, so open the sub folders de, then grogra, then template. You can rename the folder (or create a new one) to //tutorial//, and create (or copy) a java file in, ''Hello.java'' for instance.
 +Your ''src'' directory should then, have one java file at the path: ''src/main/java/de/grogra/template/tutorial/Hello.java''.
 +
 +Open ''Hello.java'' and fill the following:
 +<code java>
 +package de.grogra.template.tutorial;
 +
 +public class Hello {
 +}
 +</code>
 +
 +Now, the plugin should be entirely functional. To try it needs to be compiled.
 +At the root of the plugin (where the ''pom.xml'' file is) run the command line: ''mvn compile''.
 +It should download a lot of dependencies and after some time properly compile.
 +
 +
 +===== Add content =====
 +
 +The current plugin compile and can be "used" by GroIMP, but it doesn't do anything. So Let's add some features.
 +
 +In the following, the directory ''src/main/resources'' will be referred as the resource directory and ''src/main/java/de/grogra/template/tutorial'' as the java directory.
 +
 +==== New file filter ====
 +
 +This will enables GroIMP to read a new type of file (or an existing one but differently). See [[dev-guide:create-new-mimetypes-and-file-types|here]] for the complete explanation of how to set up a new file filter and mimetype. In this tutorial we will only do the basic steps.
 +
 +=== Update GroIMP registry ===
 +
 +In the resource directory, open the ''plugin.xml'' file and add to the registry: 
 +<code xml>
 +<registry>
 +   <ref name="io">
 +      <ref name="filetypes">
 +         <ext name="example" extensions="{.example}" mimeType="text/example"/>
 +      </ref>
 +      <ref name="mimetypes">
 +         <mimetype name="text/example">
 +            <filter input="freader" create="de.grogra.template.tutorial.ExampleFilter$LoadAsNode"/>
 +         </mimetype>
 +      </ref>
 +   </ref>
 +</registry>
 +</code>
 +
 +This enables GroIMP to know on startup that a new file filter exists for files with the extension: //.example//. When it will try to open one, it will use the class //ExampleFilter$LoadAsNode// (which do not exists yet).
 +
 +=== Create the filter in java ===
 +
 +In the java directory create a file called ''ExampleFilter.java'' and add its content:
 +<code java> 
 +package de.grogra.template.tutorial;
 +
 +import java.io.IOException;
 +
 +import de.grogra.pf.io.FilterBase;
 +import de.grogra.pf.io.FilterItem;
 +import de.grogra.pf.io.FilterSource;
 +import de.grogra.pf.io.IOFlavor;
 +import de.grogra.pf.io.ObjectSource;
 +
 +public class ExampleFilter {
 +
 + public static class LoadAsNode extends FilterBase implements ObjectSource  {
 + public LoadAsNode(FilterItem item, FilterSource source) {
 + super(item, source);
 + setFlavor (IOFlavor.NODE);
 + }
 +
 + @Override
 + public Object getObject() throws IOException {
 + // TODO Auto-generated method stub
 + return null;
 + }
 + }
 +}
 +</code>
 +
 +=== Add dependencies to the project ===
 +
 +The project only misses the import of dependencies we used: Platform and Platform-Core. Let's add them in:
 +  * The ''module.info'' file:
 +<code java>
 +        requires platform;
 + requires platform.core;
 +</code>
 +  * The ''plugin.xml'' file in the resource directory, (to add before the <registry> tag):
 +<code xml>
 +  <import plugin="de.grogra.pf"/>
 +</code>
 +  * In the ''pom.xml'' file int the root directory of the plugin:
 +<code xml>
 +    <dependency>
 +      <groupId>de.grogra</groupId>
 +      <artifactId>platform</artifactId>
 +      <version>2.1.5</version>
 +    </dependency>
 +
 +    <dependency>
 +      <groupId>de.grogra</groupId>
 +      <artifactId>platform.core</artifactId>
 +      <version>2.1.5</version>
 +    </dependency>
 +</code>
 +
 +=== Compile and use in GroIMP ===
 +
 +The plugin can now be compiled AND be used in GroIMP. Let's create a compiled version of the plugin with the command : ''mvn package'' (run at the root directory of the plugin).
 +
 +This command create a new directory in the parent directory of the plugin called ''app'' (relative path: ''../app/''). In the app directory there is a directory called //plugins//, in which there is a directory called //newplugin//. This is the compiled plugin. You can copy this directory in your GroIMP plugin directory (or in ''/home/.grogra.de-platform/plugins'') and start GroIMP.
 +
 +In GroIMP the filter is available. When adding a node from file you can see the "text/example" format:
 +
 +{{:tutorials:tuto_import.png?400|}}
 +
 +=== Actual content ===
 +
 +While the filter exists and is recognized by GroIMP, it is not doing anything because the java file is "empty".
 +
 +Open the file ''ExampleFilter.java'' from the java directory and add content to the ''getObject()'' method:
 +<code java>
 +                @Override
 + public Object getObject() throws IOException {
 + BufferedReader reader = new BufferedReader(((ReaderSource) source).getReader ());
 +
 + Node n = new Node();
 + Node last = n;
 + String line;
 + while((line = reader.readLine()) != null) {
 +      String[] l =line.split(" ");
 +      float length = Float.valueOf( l[0]);
 +      float radius = Float.valueOf( l[1]);
 +      Cylinder c = new Cylinder(length, radius);
 +      last.addEdgeBitsTo(c, Graph.BRANCH_EDGE, null);
 +      last=c;
 + }
 +
 + return n;
 + }
 +</code>
 +
 +And add the dependencies:
 +  * Add the following imports in the file.
 +<code java>
 +import java.io.BufferedReader;
 +
 +import de.grogra.graph.Graph;
 +import de.grogra.graph.impl.Node;
 +import de.grogra.imp3d.objects.Cylinder;
 +import de.grogra.pf.io.ReaderSource;
 +</code>
 +
 +  * Add the module dependency in ''module.info''
 +<code java>
 + requires graph;
 + requires imp3d;
 +        requires imp;
 +        requires utilities;
 +</code>
 +
 +  * In the ''plugin.xml'' from the resource directory:
 +<code xml>
 +  <import plugin="de.grogra.imp3d"/>
 +</code>
 +
 +  * And the maven dependecy in the ''pom.xml'' file:
 +<code xml>
 +    <dependency>
 +      <groupId>de.grogra</groupId>
 +      <artifactId>imp3d</artifactId>
 +      <version>2.1.5</version>
 +    </dependency>
 +</code>
 +
 +Compile the project again and replace the old version by the newly created one. 
 +GroIMP is now able to load .example file of the format: each line define a cylinder, with two values: length radius.
 +
 +Let's create a file called ''test.example'' and fill it with:
 +<code>
 +1 0.2
 +0.6 0.1
 +2 0.5
 +</code>
 +
 +This should create a chain of three cylinders if loaded in GroIMP.
 +
 +Open GroIMP, create a new project, import the file and look at the result.
 +
 +==== New command ====
 +
 +In this section we will create a GroIMP command callable from a menu item that will create a random chain of Cylinders and adds it to the graph.
 +
 +=== Create the command ===
 +
 +In the java directory create a new file called ''Commands.java'' and fill it with:
 +<code java>
 +package de.grogra.template.tutorial;
 +
 +import de.grogra.graph.Graph;
 +import de.grogra.graph.impl.Node;
 +import de.grogra.imp3d.objects.Cylinder;
 +import de.grogra.pf.registry.Item;
 +import de.grogra.pf.ui.Context;
 +
 +public class Commands {
 +
 + public static void randomCylinders(Item item, Object info, Context ctx) {
 + Node n = new Node();
 + Node last = n;
 + for(int i=0;i<5;i++) {
 + float length =  (float) (0.5f + Math.random() * (2 - 0.5));
 + float radius = (float) (0.1f + Math.random() * (0.4 - 0.1));
 + Cylinder c = new Cylinder(length, radius);
 + last.addEdgeBitsTo(c, Graph.BRANCH_EDGE, null);
 + last = c;
 + }
 + IMP.addNode(null, n, ctx);
 + }
 +}
 +</code>
 +
 +To be callable from the GUI, GroIMP commands needs to be //public//, //static//, and as their return value is not used //void//.
 +The parameters //Item, Object, Context// are the default and most used ones.
 +
 +=== Create a menu item ===
 +
 +Now that the command exists in java, it needs to be referenced in the registry to be accessible from GroIMP GUI.
 +
 +Open the ''plugin.xml'' file from the resources and add (within the <registry> tags):
 +<code xml>
 +    <directory name="tutorial">
 +    <directory name="tutorial">
 + <command name="createRandomCylinders" run="de.grogra.template.tutorial.Commands.randomCylinders"/>
 +    </directory>
 +   </directory>
 +   
 +    <ref name="hooks">
 + <ref name="complete">
 + <ref name="project">
 + <insert target="/workbench/menu/src" resolveLinks="false">
 + <link source="/tutorial/tutorial" />
 + </insert>
 + </ref>
 + </ref>
 + </ref>
 +</code>
 +
 +The tag '' <directory name="tutorial"> '' creates a directory in the registry, which can be used latter by GroIMP or users. In this directory we create a ''<command />'' tag that point at the command implementation in java.
 +
 +Then, the hooks > complete > project defines what happens when a GroIMP project is open. In this case at ''/workbench/menu/src'' (i.e. the menu bar) we insert the directory previously created.
 +
 +=== Use from GroIMP ===
 +
 +Now that the command has been implemented and added to the menu bar, compile the plugin and replace the old one.
 +Open GroIMP and a new project. 
 +
 +{{:tutorials:tuto_menu.png?400|}}
 +
 +=== Add an option ===
 +
 +The previous command is creating a chain of five cylinders. Instead of using a fixed number we can add a GroIMP option to let the user define the number.
 +
 +Options are defined in the registry. In the ''plugin.xml'' file. We need to modify slightly the directory "tutorial created in the previous section:
 +<code xml>
 +   <directory name="tutorial"  optionCategory="true">
 +    <directory name="tutorial">
 + <command name="createRandomCylinders" run="de.grogra.template.tutorial.Commands.randomCylinders"/>
 +    </directory> 
 +      <command name="options">
 +            <option name="numberOfCylinders" type="java.lang.Integer" value="5"/>
 +      </command>
 +   </directory>
 +</code>
 +
 +The directory is now using the parameter //optionCategory// , which will make it visible in the panel //preferences// of GroIMP. And the tag ''<option />'' is defining a new option with a type and a default value.
 +
 +{{:tutorials:tuto_addoption.png?400|}}
 +
 +Now we change the java code that was creating the Cylinders to use the value of this option. In the file ''Commands.java'', change the method :
 +
 +<code java>
 +
 +import de.grogra.util.Utils;
 +
 +public class Commands {
 +
 +public static void randomCylinders(Item item, Object info, Context ctx) {
 +  Node n = new Node();
 +  Node last = n;
 +
 +  Item ite = Item.resolveItem(item.getRegistry(), "/tutorial/options");
 +  int nbOfCylinders = (int) Utils.get(ite, "numberOfCylinders", 5);
 +
 +  for(int i=0;i<nbOfCylinders;i++) {
 + float length =  (float) (0.5f + Math.random() * (2 - 0.5));
 + float radius = (float) (0.1f + Math.random() * (0.4 - 0.1));
 + Cylinder c = new Cylinder(length, radius);
 + last.addEdgeBitsTo(c, Graph.BRANCH_EDGE, null);
 + last = c;
 +  }
 +  IMP.addNode(null, n, ctx);
 +}
 +}
 </code> </code>
tutorials/create-groimp-plugin.1733439474.txt.gz · Last modified: 2024/12/05 23:57 by gaetan