Graph Api / Diagram API questions

I have some questions regarding the Graph/Diagram APIs

  • What are the differences between the Graph and Diagram API - is the Diagram Api new, and the Graph API is deprecated? Or are they completely different APIs with different purposes?

  • What is the preferred way to register a Hotspot Painter within the Graph API's configuration map for the GenericNodeRealizers?
    As I understand it, I need to wrap a custom com.intellij.openapi.graph.view.GenericNodeRealizer.HotSpotPainter instance to allow yFiles to use - ie,otherwise you get an exception like below

    [  68822]  ERROR - llij.ide.plugins.PluginManager - Can't unwrap interface: interface a.j.md$m_

    java.lang.AssertionError: Can't unwrap interface: interface a.j.md$m_

    at com.intellij.openapi.graph.impl.GraphBase.b(GraphBase.java:243)

    at com.intellij.openapi.graph.impl.GraphBase.a(GraphBase.java:211)


    I understand there are wrapping mechanisms for this, ie for NodeCellRenderer (GraphManager#createNodeCellRendererPainter), but is there one for a hotspot painter?...

    Currently I am instantiating the obfusicated interface to avoid this issue - but I understand this will break in the future


        configMap.put(GenericNodeRealizer.HotSpotPainter.class, new a.j.md.m_() {
            @Override
            public void a(a.j.ld ld1, Graphics2D graphics2d) {
                // ...
            }
        });

Cheers,
Alan

12 comments
Comment actions Permalink

Hi Alan,
1. Diagram API is our small Diagramming Framework based on Graph API which is based on yFiles. Diagram API is much, much simplier than Graph API. Also, it provides some useful generic features like Undo/Redo, Toolbar, color management, node highliting, etc. You can look at a simple example here https://github.com/bulenkov/IntelliJIdeaDiagramDemo

2. Graph API doesn't support Hotspot Painters at the moment. So, the way you register it is fine.

Konstantin

0
Comment actions Permalink

Perfect, thank you Konstantin.

- Shall I create a YouTrack issue to allow for Hotspot painters to be added to the OpenAPI? I can not send a PR for this myself, as it is closed source unfortunately :(

- Additionally, I wonder if this information could be added to a new page entitled 'Diagram / Graph Api' - for future developers to easily access

The page would contain the information you have provided -

Diagram API

Diagram API is our small Diagramming Framework based on Graph API which is based on yFiles. Diagram API is much, much simplier than Graph API. Also, it provides some useful generic features like Undo/Redo, Toolbar, color management, node highliting, etc

Example Plugin - http://confluence.jetbrains.com/display/IDEADEV/Diagram+Framework

Graph API

Data Model -

A data model can be provided to a given Graph. This data model provides access to the Nodes/Edges in a given data source, and provides methods for manipulating this information.

See com.intellij.openapi.graph.builder.GraphDataModel

Presentation Model

Provides definitions associated with the presentation, such as setting the layout, EdgeRealizers and NodeRealizers, tooltip information etc.

        see also
           - com.intellij.openapi.graph.builder.GraphPresentationModel
           - com.intellij.openapi.graph.builder.components.BasicGraphPresentationModel

        Realizers (Presentation Model)

The concept of Realizers are used to take the Nodges/Edges from a given Graph's datamodel to be visually represented and drawn. There are different interfaces provided for various Node/Edge realizers which can be implemented - such as com.intellij.openapi.graph.view.ImageNodeRealizer; However generic implementations of these Realizers are also provided via GenericNodeRealizer and GenericEdgeRealizer - which allow for a specific piece of functionality/behaviour to be replaced explicitly, and if not overriden will default to a known behaviour.

A common use case is to replace the renderer associated with a NodeRealizer, and as such there is a util method provided for this; This which can be provided under the Presentation Model's implementation of getNodeRealizer

GraphViewUtil.createNodeRealizer("ConfigurationName",  com.intellij.openapi.graph.view.NodeCellRenderer)

        Disposing
          *Not sure about the specifics of this* - Most plugins appear to explicitly register with themselves with the Disposer class...

        Useful Classes

com.intellij.openapi.graph.GraphManager - Allows for the creation of common instances related to graphs, such as GraphViews, generic realizers etc.

com.intellij.openapi.graph.builder.GraphBuilderFactory



Additionally, perhaps a small summary of which API you would suggest new developers to make use of?

0
Comment actions Permalink

Hi Konstantin

With regards to -

2. Graph API doesn't support Hotspot Painters at the moment. So, the way you register it is fine.

Unfortunately as I feared such a decision to use the obfusicated method names does not work on all IJ versions, as my previous 13.0.2 code does not compile for the newer 13.1 release.
This is not something I can send a PR for either, since this code is closed-source... Shall I raise a youtrack issue for this support to be added?
0
Comment actions Permalink

That's weird, because we haven't changed the library http://screencast.com/t/8llalxafsKws

0
Comment actions Permalink

Thank you for your response. To clarify;
My probem is due to a.j.md.m_ no longer existing within IJ 13.0.2 - instead it is now found called a.j.md.r_ within IJ 13.1

Concretely, I currently override the default configuration map with -

    configMap.put(GenericNodeRealizer.HotSpotPainter.class, new a.j.md.m_() {
        @Override
        public void a(a.j.ld ld1, Graphics2D graphics2d) {
            // ...
        }
    });

Because otherwise if I attemp to register an implementation of GenericNodeRealizer.HotSpotPainter directly -

    configMap.put(GenericNodeRealizer.HotSpotPainter.class, new GenericNodeRealizer.HotSpotPainter() {
        @Override
        public void paintHotSpots(NodeRealizer nodeRealizer, Graphics2D graphics2d) {
            // ...
        }
    });

I will instead get exceptions saying `Can't unwrap interface: interface a.j.md$m_` - I believe this is because you don't currently provide a method to convert an implementation of IJ's HotSpotPainter to yFile's implementation within the GraphManager class?

Unfortunately the code is too obfuscated for me to see how to appropriately use GraphBase.wrap/unwrap - and if these are expected to be used or not. If worse comes to worse, I imagine I can use reflection and grab the curent class mapping defined in GraphManager's I2Y_CLASSES, and create the yFiles painter object myself at runtime

I would of course love to know if there's a better alternative, which I'm sure there is! :)

0
Comment actions Permalink

Hi Alan, did you ultimately get something working? I'd like to build a diagramming and drawing tool in IJ but am worried no clear source would make it impossible. Any thoughts?

0
Comment actions Permalink

Yip, everything went fine - other than adding hotspot painters, which were obfusicated on every IJ build and non-deterministic.
I was working on a graphical visualisation of Apache Camel routes, were I added some screenshots here

My source code was in Scala, and i'm happy to share it with you on Github if you desire :)

0
Comment actions Permalink

That looks great, Alan - I'd love to see some code if you don't mind!


0
Comment actions Permalink

Fantastic! The only thing that worries me about using that interface is that it is based upon non-open source stuff, yfiles or whatever it's called. As we all know, the source code *is* the documentation when building a plug-in. Did you find it to be a problem not seeing into the proprietary source code?

Of course, it also bothers me that community edition people won't be able to use it. Is it possible to build a plug-in that simply disables that feature for community edition? probably but I wonder how the source code will avoid referencing types to that module. oh well. I will look into that if I go down this path.

I will add your notes to my plugin cheat sheet:

https://theantlrguy.atlassian.net/wiki/display/~admin/Intellij+plugin+development+notes

please do post the source so I can have that as well!
thanks,
Terence

0
Comment actions Permalink

Yeah - not having access to raw-source code was indeed one of the more painful things I had to endure whilst writing my plugin. Everything is a wrapper around yFiles however, so be sure to check out that documentation first if you're hoping to learn about specific terminology used in the API

Restricting the graphing capabilities to ultimate users only was also a negiative point I faced when investigating the IJ graph APIs. To try and alleviate this pain I provided an extension point within my plugin.xml file, and provided a unified interface for creating graphs. This meant I could easily swap in/out graphing implementations in future releases. For instance I registered both an implementation of JUNG graphing library, and IJ's Graphing API implementation. For CE users I would have provided a separate plugin.xml file with JUNG registered as the implementation.

On reflection; I think it would have been nice to use D3 for graphing, and then embed it with JavaFX. Allowing me to provide similiar tooling on a public website, which would be cool.

I have just made my Github repo public now, and is available here. Everything should be under the plugin directory.

Lemme know what you decide to progress with :)

0
Comment actions Permalink

fantastic! I'm beginning to think that using https://github.com/jgraph/jgraphx is a much better idea as it is open source and also written by people trying to make money, although they make money on the JavaScript version.
Ter

0
Comment actions Permalink
Is it possible to build a plug-in that simply disables that feature for community edition?


Yes, you can do this with optional dependencies in your plugin.xml - quite a few plugins do this with the copyright plugin, for example. See https://github.com/JetBrains/intellij-plugins/blob/master/Dart/resources/META-INF/plugin.xml#L8-10 for an example. The auxiliary xml file will only be parsed and its extensions registered if the dependency is present.

0

Please sign in to leave a comment.