Home » Modeling » Graphiti » Nesting Shapes etc...
Nesting Shapes etc... [message #989310] |
Wed, 05 December 2012 15:42 |
Tim E. Messages: 56 Registered: November 2012 |
Member |
|
|
Hi,
I'm trying to build an non-EMF-based editor with Graphiti.
I finished the Eclipse Help Tutorial and looked through some other code snippets, but unfortunately I can't find information about the following:
(If there is a tutorial or code or forum topic, please post the link)
I'm trying to build a kind of UML editor.
It's pretty similar to this one, shown in the Graphiti introduction:
At the moment, I'm trying to build the classes.
Therefore, I added CreateFeatures and AddFeatures for Classes and Attributes.
I took a while to figure out, how to add attributes to classes (could not find a tutorial for this one as well)
At the moment my code looks like this:
AddClassObjectFeature:
@Override
public PictogramElement add(IAddContext context) {
ClassObject addedClass = (ClassObject) context.getNewObject();
Diagram targetDiagram = (Diagram) context.getTargetContainer();
IPeCreateService peCreateService = Graphiti.getPeCreateService();
IGaService gaService = Graphiti.getGaService();
/***********/
/** CLASS **/
/***********/
ContainerShape classContainer = peCreateService.createContainerShape(
targetDiagram, true);
// check whether the context has a size (e.g. from a create feature)
// otherwise define a default size for the shape
final int width = context.getWidth() <= 0 ? 100 : context.getWidth();
final int height = context.getHeight() <= 0 ? 200 : context.getHeight();
// create and set graphics algorithm
Rectangle roundedRectangle = gaService.createRectangle(classContainer);
roundedRectangle.setForeground(manageColor(CLASSOBJECT_FOREGROUND));
roundedRectangle.setBackground(manageColor(CLASSOBJECT_BACKGROUND));
roundedRectangle.setLineWidth(1);
gaService.setLocationAndSize(roundedRectangle, context.getX(),
context.getY(), width, height);
// create link and wire it
link(classContainer, addedClass);
/**********/
/** LINE **/
/**********/
// create shape for line
Shape shape = peCreateService.createShape(classContainer, false);
// create and set graphics algorithm
Polyline polyline = gaService.createPolyline(shape, new int[] { 0,
LINE_HEIGHT, width, 20 });
polyline.setForeground(manageColor(CLASSOBJECT_FOREGROUND));
polyline.setLineWidth(2);
/**********************************/
/** CLASS NAME (shape with text) **/
/**********************************/
// create shape for text
Shape classNameShape = peCreateService.createShape(classContainer,
false);
// create and set text graphics algorithm
Text className = gaService.createText(classNameShape,
addedClass.getName());
className.setForeground(manageColor(CLASSOBJECT_TEXT_FOREGROUND));
className.setHorizontalAlignment(Orientation.ALIGNMENT_CENTER);
// vertical alignment has as default value "center"
className.setFont(gaService
.manageDefaultFont(getDiagram(), false, true));
gaService.setLocationAndSize(className, 0, 0, width,
DEFAULT_HEIGHT_TEXT);
// create link and wire it
link(classNameShape, addedClass);
/*****************/
/** ATTRIBUTES **/
/*****************/
// just for testing
Attribute attribute = new Attribute("TestA1");
ContainerShape attributeContainer = peCreateService
.createContainerShape(classContainer, true);
// create and set graphics algorithm
Rectangle attribRectangle = gaService
.createInvisibleRectangle(attributeContainer);
attribRectangle.setTransparency(0.0);
attribRectangle.setForeground(manageColor(CLASSOBJECT_FOREGROUND));
attribRectangle.setBackground(manageColor(CLASSOBJECT_BACKGROUND));
attribRectangle.setLineWidth(1);
gaService.setLocationAndSize(attribRectangle, 0, LINE_HEIGHT, width,
height);
// Create an add context that describes where to add the Attribute in
// the class
AddContext addAttribContext = new AddContext(new AreaContext(),
attribute);
addAttribContext.setWidth(width);
addAttribContext.setTargetContainer(attributeContainer);
// Trigger the Graphiti framework to find a feature that is capable of
// adding a Attribute
addGraphicalRepresentation(addAttribContext, attribute);
// call the layout feature
layoutPictogramElement(classContainer);
return classContainer;
}
AddAttributeFeature:
@Override
public PictogramElement add(IAddContext context) {
// Get information from context
Attribute attrib = (Attribute) context.getNewObject();
ContainerShape containerShape = context.getTargetContainer();
IPeService peCreateService = Graphiti.getPeService();
IGaService gaService = Graphiti.getGaService();
// create shape for text
Shape attribNameShape = peCreateService.createShape(containerShape,
false);
// create and set text graphics algorithm
Text attribName = gaService.createText(attribNameShape,
attrib.getName());
attribName.setForeground(manageColor(CLASSOBJECT_TEXT_FOREGROUND));
attribName.setHorizontalAlignment(Orientation.ALIGNMENT_LEFT);
attribName.setVerticalAlignment(Orientation.ALIGNMENT_TOP);
attribName.setFont(gaService.manageDefaultFont(getDiagram(), false,
true));
gaService.setLocationAndSize(attribName, 0, 0, context.getWidth(), 20);
// create link and wire it
link(attribNameShape, attrib);
return attribNameShape;
}
First of all, I'm absolutely not sure if this is the right way to do it.
(Of course, the attributes for classes won't be hard-coded later)
Second, I've encountered some problems:
1) The Rectangle used as GA for the Attribute-Container, is visible and can be moved and resized indepedent of the ClassContainer. This is not really the way I want it to work.
2) Do I really have to compute the exact coordinates for every Text-Shape representing an attribute? Is there anything like the e.g. the ToolbarLayout in GEF available in Graphiti?
3) What will happen, when I (later on) delete a single attribute from the container? How can I update the positions of the other ones at the best?
I guess by using a LayoutFeature?
Is there any tutorial showing the differences between the shapes and how to use them? Which GA are necessary to do different things...and stuff like this? To better understand the Shape structure?
Thanks in advance,
Tim
[Updated on: Thu, 06 December 2012 05:36] Report message to a moderator
|
|
| | |
Re: Nesting Shapes etc... [message #989432 is a reply to message #989430] |
Thu, 06 December 2012 08:27 |
Tim E. Messages: 56 Registered: November 2012 |
Member |
|
|
Hi Michael,
thanks for your help.
Did you have the time to look through the code I posted?
Is this, in general, the intended way to code nestes shapes?
Edit: The code of the quoted example of a UML ClassDiagram is not available by any chance?
To your answer:
Is there any further information about IdPattern?
I'm probably going to use Patterns, so I might as well have a look at IdPatterns..?!
Cheers,
Tim
[Updated on: Thu, 06 December 2012 08:28] Report message to a moderator
|
|
|
Re: Nesting Shapes etc... [message #989512 is a reply to message #989310] |
Thu, 06 December 2012 14:46 |
Tim E. Messages: 56 Registered: November 2012 |
Member |
|
|
Hi again,
so I had a look at the FileSystemExample and it is actually really helpful. Thanks.
But in the meantime some more questions raised:
1: Will the IdPattern be part of the next release?
2: I've got an implementation of a classdiagram class. At the moment with the following structure:
- container : rectangle
-- shape : polyline
-- shape : text (for classname)
-- container : rectangle (for attributes)
--- shapes : text (for each attribute)
At the moment I'm struggling to update everything correctly.
I'm trying to update the attribute container by deleting all shapes and creating new ones for every attribute.
Is there only one possible to "empty" a container? i.e. deleting all current shapes?
Namely:
Shape[] toDelete = oldAttributeCon.getChildren().toArray(
new Shape[oldAttributeCon.getChildren().size()]);
for (Shape child : toDelete) {
EcoreUtil.delete(child, true);
}
Meaning that I have to use EcoreUtil.delete to delete shapes?
Or is there any other possibility?
[Updated on: Thu, 06 December 2012 14:59] Report message to a moderator
|
|
| | | | | | | | | |
Re: Nesting Shapes etc... [message #990058 is a reply to message #990040] |
Mon, 10 December 2012 16:45 |
Tim E. Messages: 56 Registered: November 2012 |
Member |
|
|
Hi Michael,
first of all, thanks for your help, again.
The purpose of my extension is the following:
My Class representation implementation is the following:
- container : rectangle
-- shape : polyline
-- shape : text (for classname)
-- container : rectangle (for attributes)
--- shapes : text (for each attribute)
-- container : rectangle (for methods)
--- shapes : text (for each method)
Now the my idea was to implement my own Shape to make access easier.
I use methods like:
ContainerShape getFirstContainerShape()
ContainerShape setFirstContainerShape()
public Shape getNameShape()
public String getName()
public void setName(String name)
...etc...
This makes life a lot easier (at least in my opinion), so that I don't
have to navigate trough all the Container and children everytime, when
writing the different Features (like update, layout, add).
I just had a quick look at the Properties, but the documentation
is more like
* If the meaning of the ... isn't clear,
* there really should be more of a description here...
which makes it kind of difficult to understand how to use them properly
Cheers,
Tim
[Updated on: Mon, 10 December 2012 16:52] Report message to a moderator
|
|
|
Re: Nesting Shapes etc... [message #990281 is a reply to message #990058] |
Tue, 11 December 2012 17:20 |
Aljoscha Hark Messages: 24 Registered: March 2012 |
Junior Member |
|
|
Hello Tim,
I avoided the ContainerShapeImpl-Inheritance "issue" by creating a somehow "helper" class for each neccessary BO, which delegates to the right PE/GA.
To be concrete: class ClassObjectUtil could deliver methods to get to a specific PE or GA. These delegations would have only be maintained inside the *AddFeature and the *Util class.
E.g.: text GA of a class:
// ClassAddFeature:
Text nameText = Graphiti.getGaService().createText(pe);
// ClassUpdateFeature:
Text nameText = ClassUtil.getText(pe);
// ClassUtil.getText(PictogramElement pe)
return pe.getGraphicAlgorithm().getGAChildren().get(0);
<edit>
Quote:- container : rectangle
-- shape : polyline
-- shape : text (for classname)
-- container : rectangle (for attributes)
--- shapes : text (for each attribute)
-- container : rectangle (for methods)
--- shapes : text (for each method)
in this case "nameText" would be "((ContainerShape)pe).getChildren().get(1).getGA()" in the util class.
</edit>
Hope it helps,
Aljoscha
[Updated on: Tue, 11 December 2012 17:25] Report message to a moderator
|
|
| | | | | |
Re: Nesting Shapes etc... [message #990691 is a reply to message #990281] |
Thu, 13 December 2012 19:59 |
Tim E. Messages: 56 Registered: November 2012 |
Member |
|
|
Hi,
I finally found the time today, to improve my code.
I tried to implement more parts of ClassUtil idea.
But I ran into a strange problem, I don't understand.
The basic idea is, as Aljoscha described, a util class for navigating through the
(Container)-Shapes of a created PE.
This util class is used in the Layout- and UpdateFeature.
Unfortunately, updateNeeded is called on a object, that has not finished its creation.
To understand what I mean here some code:
Structure of ClassObject (my business object)
- container : rectangle
-- shape : polyline
-- shape : text (for classname)
-- container : rectangle (for attributes)
--- shapes : text (for each attribute)
ClassObjectUtil:
public ClassObjectUtil(ContainerShape classContainer) {
this.classContainer = classContainer;
// set all other shapes we know
for (Shape child : classContainer.getChildren()) {
if (child instanceof ContainerShape) {
attributeContainer = (ContainerShape) child;
} else if (child instanceof Shape) {
// could be name or line
GraphicsAlgorithm ga = child.getGraphicsAlgorithm();
if (ga instanceof Text) {
classNameShape = child;
} else if (ga instanceof Polyline) {
line = (Polyline) ga;
}
}
}
}
public String getClassName() {
return ((Text) classNameShape.getGraphicsAlgorithm()).getValue();
}
...
...
...
According to my AddFeature, every created ClassObject has an according structure.
But at some point updateNeeded is called on a ContainerShape with a ClassObject as businessObject that does not have "finished" its creation?! At least the Shape (GA: Text) for the ClassObject name is "null" and the attribute ContainerShape is also "null". In fact, there aren't any children.
So of course the program ends up with a NPE when the updateNeeded method calls getClassName(...) of the ClassObjectUtil class.
Just for the record: canUpdate is not called at all up to this point, but I'm not sure, if this should be the case.
Do I miss something? Did I do something wrong?
Thanks in advance,
Tim
PS: A possible work around is to check in updateNeeded if the passed PE has children and if not, to return falseReason(), but this seems odd to me.
[Updated on: Thu, 13 December 2012 20:07] Report message to a moderator
|
|
|
Goto Forum:
Current Time: Fri Apr 26 19:30:01 GMT 2024
Powered by FUDForum. Page generated in 0.04990 seconds
|