Home » Modeling » GMF (Graphical Modeling Framework) » [GMF tooling] Figure with affixed children and internal children
[GMF tooling] Figure with affixed children and internal children [message #1012850] |
Fri, 22 February 2013 10:28 |
Cedric Moonen Messages: 274 Registered: August 2009 |
Senior Member |
|
|
Hello,
I am trying to have an element with both affixed children (e.g. something similar as ports on a component) and internal children too.
In my graphical model (*.gmfgraph) my figure has a child Rectangle with an XYLayout on it and I defined a child access to that rectangle.
In the node definition for this element, I selected this child access for the "Content Pane" property.
Additionally, in my affixed child node definition, I specify the "Affixed Parent Side" to be NSEW.
If I generate the code, I can indeed add my affixed children which are displayed properly and I can also add children inside my figure, but unfortunately, they are stretched to fill the entire figure automatically (as if there was a fill layout).
After looking at the generated code, I realized that the content pane is not returned properly. In order to fix this, I added this method in the XXXEditPart (the edit part for the element with both affixed and internal children):
@Override
protected IFigure getContentPaneFor(IGraphicalEditPart editPart) {
if (editPart instanceof IBorderItemEditPart) {
return getBorderedFigure().getBorderItemContainer();
} else {
return getContentPane();
}
}
So I override the getContentPane of AbstractBorderedShapeEditPart which was simply never calling getContentPane but was calling getMainFigure instead.
This solves the problem, but is this a bug or am I doing something wrong here ?
|
|
| | | |
Re: [GMF tooling] Figure with affixed children and internal children [message #1015068 is a reply to message #1015044] |
Wed, 27 February 2013 11:05 |
Cedric Moonen Messages: 274 Registered: August 2009 |
Senior Member |
|
|
Hi Thomas,
Actually, I'm not really aware of a solution neither, since I am a bit experimenting (I didn't found any good documentation anywhere about GMF tooling, except for a couple of basic tutorials).
If you don't use affixed children for a specific figure, all the children will automatically added inside the figure you specified. You don't need to create a compartment for that.
I thought that it would be similar when some of the children have to be affixed and the others not, but apparently it is not the case. So I tried to force directing the content pane to the rectangle figure which should contain the nested children but it didn't work. I'm attaching an example so that you can have a better idea of what I'm talking about.
In the example, I have components that can have two types of children: ports and ContainedElements. The ports should be positioned outside the components (at the border) and ContainedElements should be positioned inside the components (using a XY layout). By default, if I specify NONE for the Affixed Parent Side of the Port Node in the gmfgraph file, it works fine and the ports and the contained elements can be added to a Component (and they are positioned where I drop them).
Now if I try to specify NSEW for the Affixed Parent Side of the Port Node, then when I try to add a ContainedElement in a Component, it is stretched all over the component (and thus I can't even add new ContainedElement in the component).
In the zip file I added the EMF project and the GMF project (without the sources), so that you don't have to spend too much time recreating the projects. You simply have to generate the EMF code (+ the edit plug-in) and the diagram code.
Hope this helps.
Cédric
|
|
| | | | |
Re: [GMF tooling] Figure with affixed children and internal children [message #1015362 is a reply to message #1015334] |
Thu, 28 February 2013 11:01 |
Thomas Beyer Messages: 55 Registered: February 2013 |
Member |
|
|
Hi Cedric,
I could not use your last attached files, since the ecore-stuff was missing again.
However, I slightly modified the gmfgraph, gmfmap and gmfgen file of your components example.
Find the attached zip. Make sure to put the files back in their proper projects again, so that the references amongst them can be resolved correctly.
Simply regenerate model, edit and diagram code.
I did exactly what I wrote in my former post. Also I disabled the ListLayout of the Compartment-Figure in the gmfgen-model to allow a free positioning an sizing of the ContainedElements.
As you can see in the attached screenshot, this is what comes out and hopefully what you desired
The yellow rectangle is your Component. The purple rectangles are the ContainedElements and the blue one is the Port.
Just to be clear, as I believe there were confusions about the affixed children and compartments.
Affixed children and Compartments (resp. Containments) are two different things and totally independent of each other. You can combine both approaches in one element though, in your example the Component.
-> the affixed child does not need a compartment, since it aligns itself to the node, it is attached to.
-> If you want to put a node inside another node, the containernode (in your case the Component) needs a compartment (which is somewhat the container), that controls its children (in your case the ContainedElements).
So as a result, you have a node, that can have both affixed children (Port) and contained children (ContainedElement).
HTH
Thomas
|
|
|
Re: [GMF tooling] Figure with affixed children and internal children [message #1015380 is a reply to message #1015362] |
Thu, 28 February 2013 12:36 |
Cedric Moonen Messages: 274 Registered: August 2009 |
Senior Member |
|
|
Quote:I could not use your last attached files, since the ecore-stuff was missing again.
Sorry, I thought I would not attach it again since it didn't change...
Quote:However, I slightly modified the gmfgraph, gmfmap and gmfgen file of your components example.
Find the attached zip. Make sure to put the files back in their proper projects again, so that the references amongst them can be resolved correctly.
Simply regenerate model, edit and diagram code.
I already tried something very similar as you did but without success. Anyway, I regenerated the code and indeed, this doesn't work properly: the contained elements can be added to the component (and resized and all, so that works fine), but I can't add any port to my component: this is simply not accepted. When I hover over the rectangle I have a tooltip saying "ComponentCompartment" so, it is logical that I can't add ports to it (the compartment is probably stretched all over the component figure, making it impossible to add ports to the component).
Quote:As you can see in the attached screenshot, this is what comes out and hopefully what you desired
This is indeed what I would like to have. Strange that you don't have the problem of adding ports to the component... I'm using GMF tooling 3.0.2.201301191623.
Quote:Just to be clear, as I believe there were confusions about the affixed children and compartments.
Affixed children and Compartments (resp. Containments) are two different things and totally independent of each other. You can combine both approaches in one element though, in your example the Component.
-> the affixed child does not need a compartment, since it aligns itself to the node, it is attached to.
-> If you want to put a node inside another node, the containernode (in your case the Component) needs a compartment (which is somewhat the container), that controls its children (in your case the ContainedElements).
So as a result, you have a node, that can have both affixed children (Port) and contained children (ContainedElement).
I understood the difference between affixed children and compartments. The only thing that confused me is that if you don't have affixed children, you can perfectly have children inside a figure without having to define compartments (so, if I remove the ports or make them non affixed, I don't need to create a container in order to have the children inside the component figure).
Maybe this is not desired by GMF and you should always have a compartment if you want to nest children inside your figure ? This would in fact be something that works but was not supposed to work in this way ?
Additionally, I find it strange that the layout that you specified on your compartment in the gmfgraph is not taken into account: you have to go into the gmfgen file and disable the list layout. Why can't the layout that you specified in the gmfgraph taken into account (you can have a layout on the component rectangle figure and one on the compartment figure in your gmfgraph).
Anyway, thanks for your answers.
Cédric
|
|
|
Re: [GMF tooling] Figure with affixed children and internal children [message #1015541 is a reply to message #1015380] |
Fri, 01 March 2013 08:18 |
Thomas Beyer Messages: 55 Registered: February 2013 |
Member |
|
|
Hi Cedric,
Quote:I already tried something very similar as you did but without success. Anyway, I regenerated the code and indeed, this doesn't work properly: the contained elements can be added to the component (and resized and all, so that works fine), but I can't add any port to my component: this is simply not accepted. When I hover over the rectangle I have a tooltip saying "ComponentCompartment" so, it is logical that I can't add ports to it (the compartment is probably stretched all over the component figure, making it impossible to add ports to the component).
The overlapping really is the case.
You can add as many ports as you like though.
To test this, you could make your compartment collapsible (gmfgen-model-attribibute).
If you collapse the compartment, the "parent"rectangle is adressed and you can add ports via the popuphandles or the palette.
Quote:I understood the difference between affixed children and compartments. The only thing that confused me is that if you don't have affixed children, you can perfectly have children inside a figure without having to define compartments (so, if I remove the ports or make them non affixed, I don't need to create a container in order to have the children inside the component figure).
Maybe this is not desired by GMF and you should always have a compartment if you want to nest children inside your figure ? This would in fact be something that works but was not supposed to work in this way ?
Yes, GMF requires compartments to allow the placement of figures inside figures. It is always possible to find and implement different solutions. In order to fully leverage from the GMF-concepts, use compartments.
Quote:Additionally, I find it strange that the layout that you specified on your compartment in the gmfgraph is not taken into account: you have to go into the gmfgen file and disable the list layout. Why can't the layout that you specified in the gmfgraph taken into account (you can have a layout on the component rectangle figure and one on the compartment figure in your gmfgraph).
The layouts that you define in your gmfgraph-model are only used to create (complex) figures and not propagated to be used within compartments.
At the moment, GMF supports ListCompartments (ListLayout) and ShapeCompartments (XYLayout). However, you are absolutely free to implement your own LayoutManager.
For example to modify a ShapeCompartment (as it is for your componentcompartment) your could take at look at
ShapeCompartmentEditPart's
/**
* Creates a scrollpane (with auto scrollbars) in which the children are
* drawn. The factory hint property is used to set this compartments label.
*/
protected IFigure createFigure() {
ShapeCompartmentFigure scf = new ShapeCompartmentFigure(getCompartmentName(), getMapMode());
scf.getContentPane().setLayoutManager(getLayoutManager());
scf.getContentPane().addLayoutListener(LayoutAnimator.getDefault());
return scf;
}
for modifications.
Regards
Thomas
|
|
| |
Re: [GMF tooling] Figure with affixed children and internal children [message #1015604 is a reply to message #1012850] |
Fri, 01 March 2013 11:03 |
Cedric Moonen Messages: 274 Registered: August 2009 |
Senior Member |
|
|
I tried your solution with the compartment and in fact it does work fine if you have only 1 port. As soon as you try to add a second port, an exception is thrown and the port is positioned at the origin of the diagram (because the exception is thrown while trying to locate the port on the border).
Here is the full stack trace:
org.eclipse.swt.SWTException: Failed to execute runnable (java.lang.IllegalArgumentException: Invalid side argument: 0. Should be the value from PositionConstants: WEST, EAST, NORTH or SOUTH)
at org.eclipse.swt.SWT.error(SWT.java:4361)
at org.eclipse.swt.SWT.error(SWT.java:4276)
at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:138)
at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4144)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3761)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$9.run(PartRenderingEngine.java:1053)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:942)
at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:86)
at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:588)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:543)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:353)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:180)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:629)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:584)
at org.eclipse.equinox.launcher.Main.run(Main.java:1438)
at org.eclipse.equinox.launcher.Main.main(Main.java:1414)
Caused by: java.lang.IllegalArgumentException: Invalid side argument: 0. Should be the value from PositionConstants: WEST, EAST, NORTH or SOUTH
at org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator.calculateNextNonConflictingPosition(BorderItemLocator.java:447)
at org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator.locateOnBorder(BorderItemLocator.java:394)
at org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator.relocate(BorderItemLocator.java:550)
at org.eclipse.draw2d.DelegatingLayout.layout(DelegatingLayout.java:75)
at org.eclipse.draw2d.Figure$LayoutNotifier.layout(Figure.java:1976)
at org.eclipse.draw2d.Figure.layout(Figure.java:1093)
at org.eclipse.draw2d.Figure.validate(Figure.java:1896)
at org.eclipse.gmf.runtime.diagram.ui.internal.figures.BorderItemContainerFigure.validate(BorderItemContainerFigure.java:340)
at org.eclipse.draw2d.Figure.validate(Figure.java:1898)
at org.eclipse.gmf.runtime.diagram.ui.figures.BorderedNodeFigure.validate(BorderedNodeFigure.java:262)
at org.eclipse.draw2d.Figure.validate(Figure.java:1898)
at org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemsAwareFreeFormLayer.validate(BorderItemsAwareFreeFormLayer.java:183)
at org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart$1.validate(DiagramEditPart.java:157)
at org.eclipse.draw2d.Figure.validate(Figure.java:1898)
at org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemsAwareFreeFormLayer.validate(BorderItemsAwareFreeFormLayer.java:183)
at org.eclipse.draw2d.Figure.validate(Figure.java:1898)
at org.eclipse.draw2d.Figure.validate(Figure.java:1898)
at org.eclipse.draw2d.Figure.validate(Figure.java:1898)
at org.eclipse.draw2d.FreeformViewport$FreeformViewportLayout.calculatePreferredSize(FreeformViewport.java:25)
at org.eclipse.draw2d.AbstractLayout.getPreferredSize(AbstractLayout.java:110)
at org.eclipse.draw2d.AbstractHintLayout.getPreferredSize(AbstractHintLayout.java:90)
at org.eclipse.draw2d.Figure.getPreferredSize(Figure.java:807)
at org.eclipse.draw2d.ScrollPaneSolver.solve(ScrollPaneSolver.java:82)
at org.eclipse.draw2d.FigureCanvas.layoutViewport(FigureCanvas.java:325)
at org.eclipse.draw2d.FigureCanvas.access$4(FigureCanvas.java:323)
at org.eclipse.draw2d.FigureCanvas$3.notifyValidating(FigureCanvas.java:292)
at org.eclipse.draw2d.UpdateManager.fireValidating(UpdateManager.java:143)
at org.eclipse.draw2d.DeferredUpdateManager.performValidation(DeferredUpdateManager.java:214)
at org.eclipse.gmf.runtime.diagram.ui.parts.DiagramGraphicalViewer$ToggleUpdateManager.performValidation(DiagramGraphicalViewer.java:116)
at org.eclipse.draw2d.DeferredUpdateManager.performUpdate(DeferredUpdateManager.java:190)
at org.eclipse.gmf.runtime.diagram.ui.parts.DiagramGraphicalViewer$ToggleUpdateManager.performUpdate(DiagramGraphicalViewer.java:106)
at org.eclipse.draw2d.DeferredUpdateManager$UpdateRequest.run(DeferredUpdateManager.java:44)
at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:135)
... 24 more
Just to be sure, I attached the model project and the diagram project so that you can easily reproduce the problem (I removed the generated source files).
EDIT: if I remove the compartment (so having the ContainedElements as affixed children too and completely removing the compartment figure, node and mapping), this works fine: I can add more than 1 child.
Thanks,
Cédric
[Updated on: Fri, 01 March 2013 11:16] Report message to a moderator
|
|
|
Re: [GMF tooling] Figure with affixed children and internal children [message #1015917 is a reply to message #1015604] |
Mon, 04 March 2013 09:27 |
Thomas Beyer Messages: 55 Registered: February 2013 |
Member |
|
|
Hi Cedric,
the error is thrown, because you have to explicitely use a direction of type NORTH, EAST, WEST, SOUTH or NONE for the Affixed Parent Side attribute of the Port Figure within your gmfgraph model. Other attributes than those will throw the error.
(I modified the model after providing it in my former reply without mentioning that. Sry about that).
Regarding your other question:
Quote:So, I would like to make the compartment concept "invisible" to the end user (so the compartment is not collapsible). Furthermore, the user should still be able to add ports to the component even if the compartment is expanded over the full component.
Would something like this be possible in GMF ?
Sure, it is.
1. disable the collapsible-attribute of the compartment (and regenerate).
2. modify your generated ComponentComponentCompartmentEditPart and delegate the creationrequest of the Port to its parent, that is capable of creating the Port.
@Override
public Command getCommand(Request request) {
if (request instanceof CreateViewAndElementRequest) {
CreateViewAndElementRequest cver = (CreateViewAndElementRequest) request;
CreateElementRequestAdapter adapter = cver
.getViewAndElementDescriptor()
.getCreateElementRequestAdapter();
CreateElementRequest cer = (CreateElementRequest) adapter
.getAdapter(CreateElementRequest.class);
if (cer.getElementType() == ComponentsElementTypes.Port_3001)
return getParent().getCommand(request);
}
return super.getCommand(request);
}
Regards
Thomas
|
|
|
Re: [GMF tooling] Figure with affixed children and internal children [message #1016952 is a reply to message #1015917] |
Fri, 08 March 2013 10:26 |
Cedric Moonen Messages: 274 Registered: August 2009 |
Senior Member |
|
|
Thomas,
Thanks for your answer (sorry for the late answer but I have been busy on something else).
This indeed fixes the problem. However, I don't particularly like the idea that I have to modify the generated code and furthermore the visual ID is subject to change when you modify the gmfmap or the gmfgraph model, producing compilation errors (once the project becomes bigger, this also becomes a maintenance hell).
So, instead of modifying the generated code, I was thinking of using dynamic templates so that I modify the code generation templates (as explained here) using aspects. I simply have to add a method, so this is something that can easily be done via aspects.
However, the tricky part is that I don't want to hardcode the affixed children or the visual ID (again, for maintenance reasons). So, I modified a bit the code that you supplied in this way:
@Override
public Command getCommand(Request request) {
if (request instanceof CreateViewAndElementRequest) {
CreateViewAndElementRequest cver = (CreateViewAndElementRequest) request;
CreateElementRequestAdapter adapter = cver
.getViewAndElementDescriptor()
.getCreateElementRequestAdapter();
CreateElementRequest cer = (CreateElementRequest) adapter
.getAdapter(CreateElementRequest.class);
if (cer.getElementType() == ComponentsElementTypes.ContainedElement_3001)
return super.getCommand(request);
else
return getParent().getCommand(request);
}
return super.getCommand(request);
}
(note: the visual ID of the contained element is not valid, so this code won't compile, this was just to show you). So, the difference is that I check whether the element to be created is of type of the contained elements of the compartment. If this is false, I simply delegate the call to the parent edit part.
So, why does it make a difference ? In fact it is much easier to generate this code than the code that you showed me since here I have a direct access to the contained children of the compartment in the GMFGen model.
So, my aspect for the CompartmentEditPart looks like this:
«IMPORT 'http://www.eclipse.org/gmf/2009/GenModel'»
«AROUND additions FOR gmfgen::GenCompartment-»
«IF self.editPartClassName = 'ContainerEditPart' -»
«EXPAND xpt::Common::generatedMemberComment»
public org.eclipse.gef.commands.Command getCommand(org.eclipse.gef.Request request) {
if (request instanceof org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest) {
org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest cver = (org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewAndElementRequest) request;
org.eclipse.gmf.runtime.diagram.core.edithelpers.CreateElementRequestAdapter adapter = cver
.getViewAndElementDescriptor()
.getCreateElementRequestAdapter();
org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest cer = (org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest) adapter
.getAdapter(org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest.class);
if («FOREACH self.containedNodes AS containedNode SEPARATOR(' || ')»cer.getElementType() == components.diagram.providers.ComponentsElementTypes.«containedNode.getClassNamePrefix()»_«containedNode.visualID»«ENDFOREACH») {
return super.getCommand(request);
} else {
return getParent().getCommand(request);
}
}
return super.getCommand(request);
}
«ENDIF -»
«ENDAROUND»
|
|
| | |
Re: [GMF tooling] Figure with affixed children and internal children [message #1017191 is a reply to message #1017010] |
Sun, 10 March 2013 21:42 |
Thomas Beyer Messages: 55 Registered: February 2013 |
Member |
|
|
Hi Cedric,
Quote:BTW, which technique are you using when you have to modify for instance the NodeEditPart but only for a specific edit part ? For instance in this case I modified the CompartmentEditPart but I would like to restrict it only to the Component compartments. What I did is have an IF condition based on the edit part name but this doesn't feel very robust. I was just wondering what the best technique would be here...
I am not sure, whether there is an appropriate answer to what is THE BEST solution, but querying for the editpart's class-name is definitely a working one.
I usually check the gmfgen.ecore to see, what attributes I can use to test for.
I prefer to query for the domain-element though, since my genmodels usually have more than one instance of the same compartmenteditpart's class which would result in tests for name equivalence of ComponentCompartmentEditPart, ComponentCompartment2EditPart, etc.
In my cases this reduces the error-proneness and complexity of the templates, but doesn't take of that fact, that GMF generates a lot of redundant boilerplate code for these multiple classes, which noticeably increases the memory footprint of the entire packaged application.
Maybe there will be more code abstracted/shifted to the base runtime-classes in the future.
I will also support your bugzilla.
Regards
Thomas
|
|
|
Goto Forum:
Current Time: Thu Jan 23 00:51:37 GMT 2025
Powered by FUDForum. Page generated in 0.04856 seconds
|