tesis-dynaware / graph-editor

Eclipse Public License 1.0
132 stars 42 forks source link

Add attributes to the Model #4

Closed eckig closed 9 years ago

eckig commented 9 years ago

Maybe that is not really an issue but my lack of understanding using the EMF API.

What I am trying to do is add new attributes to the Model, for example to a GNode. I made a subclass of it and added it to the graph. This works but the EMF model does not really incorporate this subclass, best example is trying to copy and paste this node. The EMF copy method creates a new GNode because it does not know my custom node.

What am I missing here? Any hints are appreciated :-)

(I digged deep into the code and currently my best guess would be that I would have to create my own EMF model classes with my own EPackage and EClass?)

rmfisher commented 9 years ago

Yeah this is a good question, and important for us to document better how to do it. It's on my to-do list.

I have never tried to sub-class GNode or other model classes. I'm not sure if such an approach is possible.

The way it typically works is that you have a separate EMF 'domain model' that the graph diagram is illustrating. Let's say you create an EMF model with a 'Car' class and in the graph editor the nodes are representing cars. Maybe in your software you are using these 'car' objects in contexts that have nothing to do with graphs or diagrams, they are part of your core business logic. You would not do

public class Car extends GNode 

because it's not an "is a" relationship. At least that's the kind of use-case we have ourselves.

So what you have are 2 EMF models, one for the core business logic (e.g. your own "car.ecore" file, with a Car class with attributes like name, manufacturer, etc) and one for the visual representations of those objects in a graph diagram (the EMF model provided by us, with a GNode class with layout attributes like x, y, width, height, etc).

What you do want is to edit both EMF models in the same EditingDomain. So for example in the "addNode" button handler you do the following:

  1. Create a new GNode instance with some initial values
  2. Use SetCommand.create(...) to create a command to add the GNode to a GModel instance
  3. Create a new Car instance with some initial values
  4. Use SetCommand.create(...) to create a command to add the Car to e.g. a CarModel instance
  5. Add both commands to a CompoundCommand, and execute that

Then when you press undo, both the car and the node will be removed, and everything will remain in sync. This requires that both the GModel object and the CarModel object are attached to the same editing domain. You do this via:

editingDomain.getResourceSet().getResources().add(...);

Hooks are provided for other operations like adding and removing connections, pasting nodes, deleting nodes, etc. For example:

void setOnConnectionCreated(CommandAppender<GConnection> appender);

This is how we intend to keep our "domain model" in sync with the graph model. We have not fully implemented it yet, but this is how I expect it to work.

I hope this makes things a bit clearer. Like I said, we will be trying to improve the documentation on this soon.

eckig commented 9 years ago

Thanks for taking the time to clarify this.

However it would be nice to make the hooks more general / functional

void setOnConnectionCreated(Consumer<GConnection> consumer);
void setOnNodeCreated(Consumer<GConnection> consumer);

etc.

You may even retrofit your CommandAppender to BiConsumer<T, CompoundCommand>.

eckig commented 9 years ago

Another question on how to link the graph model with the domain model:

The GNode has an ID attribute to identify it, but are we supposed to identify GConnectors? I have the following problem: I get notified when a new connection has been created, but I have no way to transport this connection into my domain model because I can not identify the GConnectors of the new connection..

rmfisher commented 9 years ago

Fair enough. I added ID attributes to the other model elements. The change is pushed to GitHub. The Maven Central artifacts will be updated in the next release.

eckig commented 9 years ago

Thanks!

rmfisher commented 9 years ago

By the way I just replaced CommandAppender with BiConsumer. You may need to update your project if you made any explicit references to CommandAppender. If you just passed a lambda expression you probably won't need to change anything.

eckig commented 9 years ago

Thanks for the heads-up. But as you have guessed, we are using lambdas, so it does not break :-)