Skip to content

Commit d9eb7b3

Browse files
committed
klighd, klighd.piccolo & friends: added 'FOREGROUND_NODE' & 'BACKGROUND_FIGURE' to 'KlighdProperties', refactored handling of nodes and node figures to solve #151
* added corresponding convenience methods to 'DiagramSyntheses' * added distinguished layers for regular nodes and foreground nodes in 'KChildAreaNode' * refined 'fullPaint()' procedures for 'KChildAreaNode' and 'KNodeNode' * refined figure filtering in 'KlighdFigureNode' * added required state to 'KlighdPaintContext' * added corresponding tests to 'klighd.piccolo.test' powered by the svg generator * minor refinement in 'SemanticSVGGraphics2D' (generated white space)
1 parent cf32626 commit d9eb7b3

File tree

16 files changed

+1405
-70
lines changed

16 files changed

+1405
-70
lines changed

plugins/de.cau.cs.kieler.klighd.piccolo.freehep/src/de/cau/cs/kieler/klighd/piccolo/freehep/SemanticSVGGraphics2D.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1566,7 +1566,7 @@ protected static String getPathContent(PathIterator path) {
15661566
StringBuffer result = new StringBuffer();
15671567

15681568
double[] coords = new double[6];
1569-
result.append("d=\"");
1569+
result.append(" d=\"");
15701570
while (!path.isDone()) {
15711571
int segType = path.currentSegment(coords);
15721572

@@ -1628,7 +1628,7 @@ protected static String getPathContent(PathIterator path) {
16281628
protected String getPath(PathIterator path) {
16291629
StringBuffer result = new StringBuffer();
16301630

1631-
result.append("<path ");
1631+
result.append("<path");
16321632
result.append(attributes(true));
16331633
result.append(getPathContent(path));
16341634
result.append("/>");

plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/KlighdNode.java

+14
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,8 @@ public KlighdFigureNode(final T rendering) {
554554

555555
private T rendering;
556556

557+
private boolean isBackgroundFigure;
558+
557559
/**
558560
* Configures the {@link KRendering} element being represented by this {@link KlighdFigureNode}.
559561
*
@@ -567,6 +569,8 @@ public void setRendering(final T rendering) {
567569
return;
568570
}
569571

572+
this.isBackgroundFigure = rendering.getProperty(KlighdProperties.BACKGROUND_FIGURE);
573+
570574
setVisibilityOn(
571575
rendering.getProperty(KlighdProperties.OUTLINE_INVISIBLE).booleanValue(),
572576
rendering.getProperty(KlighdProperties.EXPORTED_IMAGE_INVISIBLE).booleanValue(),
@@ -678,6 +682,16 @@ protected boolean pickAfterChildren(final PPickPath pickPath) {
678682
}
679683
}
680684

685+
/**
686+
* {@inheritDoc}
687+
*/
688+
@Override
689+
public boolean isNotVisibleOn(KlighdPaintContext kpc) {
690+
return kpc.isBackgroundFiguresOnly() && !this.isBackgroundFigure
691+
|| kpc.isNonBackgroundFiguresOnly() && this.isBackgroundFigure
692+
|| super.isNotVisibleOn(kpc);
693+
}
694+
681695
/**
682696
* {@inheritDoc}<br>
683697
* <br>

plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/AbstractKGERenderingController.java

+9
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ enum ElementMovement {
156156
/** whether to synchronize the rendering with the model. */
157157
private boolean syncRendering = false;
158158

159+
/** A flag for capturing whether some figure description parts are tagged as background figures. */
160+
protected boolean backgroundFiguresPresent = false;
161+
159162
/**
160163
* A flag indicating the availability of {@link KStyle KStyles} with valid modifier ids in
161164
* {@link #currentRendering}.
@@ -324,6 +327,9 @@ void updateRendering() {
324327
// this call updates the 'currentRendering' field
325328
getCurrentRendering();
326329

330+
// reset the flag before re-evaluating the current figure description
331+
backgroundFiguresPresent = false;
332+
327333
// reset that flag as potentially available styles with a modifier might be removed now
328334
modifiableStylesPresent = false;
329335

@@ -1172,6 +1178,9 @@ protected PNodeController<?> createRendering(final KRendering rendering,
11721178
final boolean isRenderingRef =
11731179
rendering.eClass() == KRenderingPackage.eINSTANCE.getKRenderingRef();
11741180

1181+
this.backgroundFiguresPresent = this.backgroundFiguresPresent
1182+
|| rendering.getProperty(KlighdProperties.BACKGROUND_FIGURE);
1183+
11751184
final List<KStyle> renderingStyles = rendering.getStyles();
11761185

11771186
processModifiableStyles(renderingStyles);

plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/controller/KNodeRenderingController.java

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ protected PNodeController<?> internalUpdateRendering() {
7272
handleAreaAndPointPlacementRendering(createDefaultRendering(), repNode);
7373
}
7474

75+
repNode.setHasBackgroundFigures(this.backgroundFiguresPresent);
76+
7577
// make sure the child area is attached to something
7678
if (childAreaNode.getParent() == null) {
7779
// if the childArea is not part of the above created PNode rendering tree

plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KChildAreaNode.java

+81-11
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@
1616
*/
1717
package de.cau.cs.kieler.klighd.piccolo.internal.nodes;
1818

19+
import org.eclipse.emf.common.notify.Notification;
20+
import org.eclipse.emf.common.notify.impl.AdapterImpl;
21+
import org.eclipse.emf.common.util.BasicEMap;
22+
23+
import de.cau.cs.kieler.klighd.kgraph.KGraphPackage;
1924
import de.cau.cs.kieler.klighd.krendering.KChildArea;
2025
import de.cau.cs.kieler.klighd.piccolo.IKlighdNode;
2126
import de.cau.cs.kieler.klighd.piccolo.internal.util.KlighdPaintContext;
27+
import de.cau.cs.kieler.klighd.util.KlighdProperties;
2228
import edu.umd.cs.piccolo.PLayer;
2329
import edu.umd.cs.piccolo.PNode;
2430
import edu.umd.cs.piccolo.util.PBounds;
@@ -41,14 +47,17 @@ public class KChildAreaNode extends KlighdDisposingLayer implements IKlighdNode.
4147

4248
private final KNodeAbstractNode parentNodeNode;
4349

44-
private final boolean edgesFirst;
50+
private boolean edgesFirst;
4551

4652
/** the node layer. */
47-
private PLayer nodeLayer;
53+
private PLayer belowEdgesNodeLayer;
4854

4955
/** the edge layer. */
5056
private PLayer edgeLayer;
5157

58+
/** 2nd node layer containing nodes being drawn on top of edges. */
59+
private PLayer aboveEdgesNodeLayer;
60+
5261
/** the {@link KChildArea} represented by this {@link KChildAreaNode}, may be <code>null</code>. */
5362
private KChildArea childArea;
5463

@@ -69,6 +78,37 @@ public KChildAreaNode(final KNodeAbstractNode parentNodeNode, final boolean edge
6978
this.setPickable(false);
7079
this.parentNodeNode = parentNodeNode;
7180
this.edgesFirst = edgesFirst;
81+
82+
if (!edgesFirst && parentNodeNode instanceof KNodeTopNode) {
83+
// special handling for the KNodeTopNode since the root KNode and the KNodeTopNode are
84+
// kept for the entire diagram life time and the update strategy transfers settings on
85+
// the root node after this constructor call;
86+
// hence, 'edgesFirst' will always be false except KlighdProperties.EDGES_FIRST is set
87+
// on the viewContext;
88+
// thus, if no activation is done on the view context we need to listen for changes on
89+
// the properties of the root node being performed by the update strategy, so...
90+
91+
parentNodeNode.getViewModelElement().eAdapters().add(new AdapterImpl() {
92+
93+
@Override
94+
public void notifyChanged(Notification msg) {
95+
if (msg.getFeature() == KGraphPackage.eINSTANCE.getEMapPropertyHolder_Properties()) {
96+
final Object newValue = msg.getNewValue();
97+
if (msg.getEventType() == Notification.REMOVE_MANY && newValue == null) {
98+
KChildAreaNode.this.edgesFirst =
99+
KlighdProperties.EDGES_FIRST.getDefault().booleanValue();
100+
101+
} else if (msg.getEventType() == Notification.ADD
102+
&& newValue instanceof BasicEMap.Entry<?, ?>
103+
&& KlighdProperties.EDGES_FIRST
104+
.equals(((BasicEMap.Entry<?, ?>) newValue).getKey())) {
105+
KChildAreaNode.this.edgesFirst =
106+
(Boolean) ((BasicEMap.Entry<?, ?>) newValue).getValue();
107+
}
108+
}
109+
}
110+
});
111+
}
72112
}
73113

74114
/**
@@ -103,8 +143,8 @@ public PLayer getEdgeLayer() {
103143
*
104144
* @return a dedicated layer accommodating all attached {@link KNodeNode KNodeNodes}.
105145
*/
106-
public PLayer getNodeLayer() {
107-
return this.nodeLayer;
146+
public PLayer getDefaultNodeLayer() {
147+
return this.belowEdgesNodeLayer;
108148
}
109149

110150
/**
@@ -124,12 +164,22 @@ public void setClip(final boolean clip) {
124164
* the node representation
125165
*/
126166
public void addNode(final KNodeNode node) {
127-
if (nodeLayer == null) {
128-
nodeLayer = new KlighdDisposingLayer();
129-
addChild(edgesFirst ? getChildrenCount() : 0, nodeLayer);
167+
if (edgesFirst || node.isTaggedAsForeground()) {
168+
if (aboveEdgesNodeLayer == null) {
169+
aboveEdgesNodeLayer = new KlighdDisposingLayer();
170+
addChild(getChildrenCount(), aboveEdgesNodeLayer);
171+
}
172+
aboveEdgesNodeLayer.addChild(node);
173+
node.setParentNode(parentNodeNode, true);
174+
175+
} else {
176+
if (belowEdgesNodeLayer == null) {
177+
belowEdgesNodeLayer = new KlighdDisposingLayer();
178+
addChild(0, belowEdgesNodeLayer);
179+
}
180+
belowEdgesNodeLayer.addChild(node);
181+
node.setParentNode(parentNodeNode, false);
130182
}
131-
nodeLayer.addChild(node);
132-
node.setParentNode(parentNodeNode);
133183
}
134184

135185
/**
@@ -141,7 +191,7 @@ public void addNode(final KNodeNode node) {
141191
public void addEdge(final KEdgeNode edge) {
142192
if (edgeLayer == null) {
143193
edgeLayer = new KlighdDisposingLayer();
144-
addChild(edgesFirst ? 0 : getChildrenCount(), edgeLayer);
194+
addChild(belowEdgesNodeLayer == null ? 0 : 1, edgeLayer);
145195
}
146196
edgeLayer.addChild(edge);
147197
}
@@ -264,6 +314,26 @@ public void fullPaint(final PPaintContext paintContext) {
264314
super.validateFullBounds();
265315
super.validateFullPaint();
266316

267-
super.fullPaint(paintContext);
317+
if (this.aboveEdgesNodeLayer == null || this.aboveEdgesNodeLayer.getChildrenCount() == 0) {
318+
// no nodes to be drawn above edges, so draw as usual
319+
super.fullPaint(paintContext);
320+
321+
} else if (getVisible() && fullIntersects(paintContext.getLocalClip())) {
322+
final KlighdPaintContext kpc = (KlighdPaintContext) paintContext;
323+
324+
// assigning selected nodes explicitly to the 'aboveEdgesNodeLayer' or 'belowEdgesNodeLayer'
325+
// is not supported as of now, and therefore a mixture of nodes to be drawn underneath the edge layer
326+
// and nodes to be drawn on top of the edge layer should not occur at the time of writing this.
327+
328+
kpc.pushFigureFilterBackgroundOnly();
329+
paintContext.pushTransform(getTransformReference(false));
330+
this.aboveEdgesNodeLayer.fullPaint(paintContext);
331+
paintContext.popTransform(getTransformReference(false));
332+
kpc.popFigureFilter();
333+
334+
kpc.pushFigureFilterNonBackgroundOnly();
335+
super.fullPaint(paintContext);
336+
kpc.popFigureFilter();
337+
}
268338
}
269339
}

plugins/de.cau.cs.kieler.klighd.piccolo/src/de/cau/cs/kieler/klighd/piccolo/internal/nodes/KNodeNode.java

+72-5
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ public class KNodeNode extends KNodeAbstractNode implements
7575
*/
7676
private final PCamera childAreaCamera;
7777

78+
/** Flag indicating that this node is tagged to be drawn on top of the edge layer within the parent child area. */
79+
private final boolean isTaggedAsForeground;
80+
81+
/** Flag indicating that this node is considered be drawn on top of the edge layer within the parent child area by its containing child area. */
82+
private boolean isDrawnAsForeground = false;
83+
84+
/** Flag indicating whether this node's figure contains background parts to be drawn before drawing all the edges within the parent child area. */
85+
private boolean hasBackgroundFigures = false;
86+
7887
/** this flag indicates whether this node is currently observed by the {@link KlighdMainCamera}. */
7988
private boolean isRootLayer = false;
8089

@@ -114,6 +123,8 @@ public class KNodeNode extends KNodeAbstractNode implements
114123
public KNodeNode(final KNode node, final boolean edgesFirst) {
115124
super(node, edgesFirst);
116125

126+
this.isTaggedAsForeground = node.getProperty(KlighdProperties.FOREGROUND_NODE).booleanValue();
127+
117128
this.visibilityHelper = KGraphElementNode.evaluateVisibilityDefinitions(node, null);
118129

119130
this.childAreaCamera = new PCamera() {
@@ -395,8 +406,9 @@ public KNodeAbstractNode getParentKNodeNode() {
395406
* @param parentINode
396407
* the {@link AbstractKNodeNode} being the new parent in terms of the structural nodes
397408
*/
398-
public void setParentNode(final KNodeAbstractNode parentINode) {
409+
public void setParentNode(final KNodeAbstractNode parentINode, final boolean addedAsForeground) {
399410
this.parent = parentINode;
411+
this.isDrawnAsForeground = addedAsForeground;
400412
}
401413

402414
/**
@@ -408,6 +420,27 @@ public void removeFromParent() {
408420
this.parent = null;
409421
}
410422

423+
/**
424+
* Getter.
425+
*
426+
* @return the value of getProperty({@link KlighdProperties#FOREGROUND_NODE}) for the
427+
* corresponding {@link KNode}.
428+
*/
429+
public boolean isTaggedAsForeground() {
430+
return this.isTaggedAsForeground;
431+
}
432+
433+
/**
434+
* Setter.
435+
*
436+
* @param hasBackgroundFigures
437+
* value denoting whether the attached node figure contains parts being tagged as
438+
* background figure parts.
439+
*/
440+
public void setHasBackgroundFigures(final boolean hasBackgroundFigures) {
441+
this.hasBackgroundFigures = hasBackgroundFigures;
442+
}
443+
411444
/**
412445
* {@inheritDoc}
413446
*/
@@ -645,8 +678,17 @@ protected void notifyCameras(PBounds parentBounds) {
645678
*/
646679
@Override
647680
public void fullPaint(final PPaintContext paintContext) {
648-
final boolean isRootLayer = this.isRootLayer;
649681
final KlighdPaintContext kpc = (KlighdPaintContext) paintContext;
682+
683+
final boolean backgroundFiguresOnly = kpc.isBackgroundFiguresOnly();
684+
if (backgroundFiguresOnly && !(this.isDrawnAsForeground && this.hasBackgroundFigures)) {
685+
// if parent child area preforms the background figure drawings and this
686+
// node is not to be drawn in foreground or doesn't have background figure parts
687+
// exit early!
688+
return;
689+
}
690+
691+
final boolean isRootLayer = this.isRootLayer;
650692
if (!isRootLayer && this.visibilityHelper != null
651693
&& this.visibilityHelper.isNotVisibleOn(kpc)) {
652694
return;
@@ -671,20 +713,31 @@ public void fullPaint(final PPaintContext paintContext) {
671713
paintContext.pushTransform(transform);
672714
paintContext.pushTransparency(getTransparency());
673715

716+
final boolean pushAllFilter = !this.isDrawnAsForeground && kpc.isNonBackgroundFiguresOnly();
717+
if (pushAllFilter) {
718+
// in case this node is to be drawn as a regular (non-foreground) node but has figure parts tagged as background figures
719+
// and we're in non-background drawing mode override the configured non-background figure filter with the all filter,
720+
// and revert the override below, of course!
721+
kpc.pushFigureFilterAll();
722+
}
723+
674724
this.hasBeenDrawn = true;
675725

676726
final boolean applyScale = this.nodeScale != null;
677727
if (applyScale) {
678728
kpc.pushNodeScale(this.nodeScale.doubleValue());
679729
}
680730

681-
if (!getOccluded()) {
731+
if (!getOccluded() && !backgroundFiguresOnly) {
732+
// contributes the opening group tag during SVG exports if semantic data are attached,
733+
// don't do that during the background figure drawing
682734
paint(paintContext);
683735
}
684736

685737
final int count = getChildrenCount();
738+
final List<?> children = getChildrenReference();
686739
for (int i = 0; i < count; i++) {
687-
final PNode each = (PNode) getChildrenReference().get(i);
740+
final PNode each = (PNode) children.get(i);
688741

689742
if (isRootLayer) {
690743
if (isRootAndDrawnViaMainCamera) {
@@ -705,17 +758,31 @@ public void fullPaint(final PPaintContext paintContext) {
705758
// Hence, it must be that of the outline diagram or any further one.
706759
continue;
707760
}
761+
762+
} else if (backgroundFiguresOnly) {
763+
if (i != 0 || each == this.childArea) {
764+
// do not draw anything except the node's figure if just background drawing is requested
765+
break;
766+
}
708767
}
709768

710769
each.fullPaint(paintContext);
711770
}
712771

713-
paintAfterChildren(paintContext);
772+
if (!backgroundFiguresOnly) {
773+
// contributes the closing group tag during SVG exports if semantic data are attached,
774+
// don't do that during the background figure drawing
775+
paintAfterChildren(paintContext);
776+
}
714777

715778
if (applyScale) {
716779
kpc.popNodeScale();
717780
}
718781

782+
if (pushAllFilter) {
783+
kpc.popFigureFilter();
784+
}
785+
719786
paintContext.popTransparency(getTransparency());
720787
paintContext.popTransform(transform);
721788
}

0 commit comments

Comments
 (0)