Skip to content

Commit

Permalink
Colour selection action now suitable for multiple nodes & also working
Browse files Browse the repository at this point in the history
for host and rule graphs
  • Loading branch information
rensink committed Nov 15, 2024
1 parent a553d81 commit 0be1bcd
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 63 deletions.
53 changes: 51 additions & 2 deletions src/main/java/nl/utwente/groove/grammar/aspect/AspectGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,9 @@ public AspectGraph relabel(TypeLabel oldLabel, TypeLabel newLabel) {
*/
public AspectGraph colour(TypeLabel label, Aspect colour) {
assert getRole() == TYPE;
// create a plain graph under relabelling
PlainGraph result = createPlainGraph();
AspectToPlainMap elementMap = new AspectToPlainMap();
// flag registering if anything changed due to relabelling
// flag registering if anything changed due to the colour change
boolean graphChanged = false;
// construct the plain graph for the aspect nodes,
// except for the colour aspects
Expand Down Expand Up @@ -360,6 +359,56 @@ public AspectGraph colour(TypeLabel label, Aspect colour) {
}
}

/**
* Returns an aspect graph obtained from this one by changing the colour aspect
* of one or more nodes.
* @param changedNodes the nodes to be changed (guaranteed to be nodes of this graph)
* @param colour the new colour for the node; may be {@code null}
* if the colour is to be reset to default
* @return a clone of this aspect graph with changed node colour, or this graph
* if {@code node} already had the required colour
*/
public AspectGraph colour(Collection<AspectNode> changedNodes, Aspect colour) {
boolean graphChanged = false;
// create a plain graph
PlainGraph result = createPlainGraph();
AspectToPlainMap elementMap = new AspectToPlainMap();
// construct the plain graph for the aspect nodes,
// except for the colour aspects of the changed node
for (AspectNode node : nodeSet()) {
boolean isChangedNode = changedNodes.contains(node);
graphChanged |= isChangedNode && !Objects.equals(node.get(COLOR), colour);
PlainNode image = result.addNode(node.getNumber());
elementMap.putNode(node, image);
node
.getNodeLabels()
.stream()
.filter(l -> !isChangedNode || !l.has(COLOR))
.forEach(l -> result.addEdge(image, l.toString(), image));
if (isChangedNode && colour != null) {
result.addEdge(image, colour.toString(), image);
}
}
if (graphChanged) {
// copy the edges over
for (AspectEdge edge : edgeSet()) {
AspectLabel edgeLabel = edge.label();
PlainNode sourceImage = elementMap.getNode(edge.source());
assert sourceImage != null;
PlainNode targetImage = elementMap.getNode(edge.target());
assert targetImage != null;
PlainEdge edgeImage
= result.addEdge(sourceImage, edgeLabel.toString(), targetImage);
elementMap.putEdge(edge, edgeImage);
}
GraphInfo.transferProperties(this, result, elementMap);
result.setFixed();
return newInstance(result);
} else {
return this;
}
}

@Override
public boolean addNode(AspectNode node) {
assert !node.hasId() || !this.sortMap.isSet() : String
Expand Down
94 changes: 35 additions & 59 deletions src/main/java/nl/utwente/groove/gui/action/SelectColorAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,34 @@

import java.awt.Color;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JColorChooser;
import javax.swing.JDialog;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;

import org.jgraph.event.GraphSelectionEvent;
import org.jgraph.event.GraphSelectionListener;

import nl.utwente.groove.grammar.aspect.Aspect;
import nl.utwente.groove.grammar.aspect.AspectGraph;
import nl.utwente.groove.grammar.aspect.AspectKind;
import nl.utwente.groove.grammar.aspect.AspectNode;
import nl.utwente.groove.grammar.model.ResourceKind;
import nl.utwente.groove.grammar.type.TypeLabel;
import nl.utwente.groove.grammar.type.TypeNode;
import nl.utwente.groove.graph.GraphRole;
import nl.utwente.groove.graph.Label;
import nl.utwente.groove.gui.Options;
import nl.utwente.groove.gui.Simulator;
import nl.utwente.groove.gui.jgraph.JCell;
import nl.utwente.groove.gui.jgraph.AspectJGraph;
import nl.utwente.groove.gui.jgraph.AspectJVertex;
import nl.utwente.groove.gui.jgraph.JGraph;
import nl.utwente.groove.gui.tree.LabelTree;
import nl.utwente.groove.gui.tree.TypeTree.TypeTreeNode;
import nl.utwente.groove.util.Exceptions;
import nl.utwente.groove.util.parse.FormatException;

/**
* Action for selecting a colour for a type node.
*/
public class SelectColorAction extends SimulatorAction
implements GraphSelectionListener, TreeSelectionListener {
public class SelectColorAction extends SimulatorAction implements GraphSelectionListener {
/** Constructs an instance of the action. */
public SelectColorAction(Simulator simulator) {
super(simulator, Options.SELECT_COLOR_ACTION_NAME, null);
Expand All @@ -43,43 +39,25 @@ public SelectColorAction(Simulator simulator) {
}

/** Checks if in a given JGraph a type label is selected. */
private void checkJGraph(JGraph<?> jGraph) {
this.label = null;
private void checkJGraph(AspectJGraph jGraph) {
this.graph = null;
this.nodes.clear();
Object[] selection = jGraph.getSelectionCells();
if (selection != null) {
choose: for (Object cell : selection) {
for (Label entry : ((JCell<?>) cell).getKeys()) {
if (entry instanceof TypeNode) {
this.label = ((TypeNode) entry).label();
break choose;
}
}
}
}
refresh();
}

/** Checks if in a given {@link LabelTree} a type label is selected. */
private void checkLabelTree(LabelTree<?> tree) {
this.label = null;
TreePath[] selection = tree.getSelectionPaths();
if (selection != null) {
for (TreePath path : selection) {
Object treeNode = path.getLastPathComponent();
if (treeNode instanceof TypeTreeNode n && n.getEntry().isForNode()) {
this.label = n.getEntry().getType().label();
break;
}
}
this.graph = jGraph.getGraph();
var selectionStream = Arrays.stream(selection);
// find the relevant nodes
selectionStream
.filter(c -> c instanceof AspectJVertex)
.map(v -> ((AspectJVertex) v).getNode())
.forEach(this.nodes::add);
}
refresh();
}

@Override
public void execute() {
TypeNode typeNode = getGrammarModel().getTypeGraph().getNode(this.label);
assert typeNode != null; // ensured by the label
Color initColour = typeNode.getDeclaredColor();
Color initColour = this.nodes.stream().findFirst().get().getColor();
if (initColour != null) {
this.chooser.setColor(initColour);
}
Expand All @@ -102,37 +80,35 @@ private void setColour(Color newColour) {
throw Exceptions.UNREACHABLE;
}
}
for (AspectGraph typeGraph : getGrammarStore().getGraphs(ResourceKind.TYPE).values()) {
AspectGraph newTypeGraph = typeGraph.colour(this.label, colourAspect);
if (newTypeGraph != typeGraph) {
try {
getSimulatorModel().doAddGraph(ResourceKind.TYPE, newTypeGraph, false);
} catch (IOException exc) {
showErrorDialog(exc, String
.format("Error while saving type graph '%s'", typeGraph.getName()));
}
var hostGraph = this.graph;
assert hostGraph != null;
var newHostGraph = hostGraph.colour(this.nodes, colourAspect);
if (newHostGraph != hostGraph) {
try {
getSimulatorModel()
.doAddGraph(ResourceKind.toResource(this.graph.getRole()), newHostGraph, false);
} catch (IOException exc) {
showErrorDialog(exc, String
.format("Error while saving host graph '%s'", hostGraph.getName()));
}
}
}

@Override
public void valueChanged(TreeSelectionEvent e) {
checkLabelTree((LabelTree<?>) e.getSource());
}

/** Sets {@link #label} based on the {@link JGraph} selection. */
/** Sets {@link #nodes} based on the {@link JGraph} selection. */
@Override
public void valueChanged(GraphSelectionEvent e) {
checkJGraph((JGraph<?>) e.getSource());
checkJGraph((AspectJGraph) e.getSource());
}

@Override
public void refresh() {
super.setEnabled(this.label != null);
super.setEnabled(!this.nodes.isEmpty());
}

/** The label for which a colour is chosen; may be {@code null}. */
private TypeLabel label;
/** The graph to be changed. */
private AspectGraph graph;
/** The selected nodes to be changed */
private Set<AspectNode> nodes = new HashSet<>();

private final JColorChooser chooser;
}
7 changes: 7 additions & 0 deletions src/main/java/nl/utwente/groove/gui/jgraph/AspectJGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,17 @@ public AspectJGraph(Simulator simulator, DisplayKind kind, boolean editing) {
@Override
protected void installListeners() {
super.installListeners();
addGraphSelectionListener(getActions().getSelectColorAction());
addOptionListener(SHOW_ASPECTS_OPTION);
addOptionListener(SHOW_VALUE_NODES_OPTION);
}

@Override
public void removeListeners() {
super.removeListeners();
removeGraphSelectionListener(getActions().getSelectColorAction());
}

@Override
public void setModel(GraphModel model) {
GraphModel oldModel = getModel();
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/nl/utwente/groove/gui/jgraph/JGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ protected void installListeners() {
addMouseListener(getMouseListener());
addKeyListener(getCancelEditListener());
getSelectionModel().addGraphSelectionListener(getGraphSelectionListener());
addGraphSelectionListener(getActions().getSelectColorAction());
addOptionListener(SHOW_INTERNAL_NODE_IDS_OPTION);
addOptionListener(SHOW_USER_NODE_IDS_OPTION);
addOptionListener(SHOW_ANCHORS_OPTION);
Expand All @@ -167,7 +166,6 @@ public void removeListeners() {
removeMouseListener(getMouseListener());
removeKeyListener(getCancelEditListener());
getSelectionModel().removeGraphSelectionListener(getGraphSelectionListener());
removeGraphSelectionListener(getActions().getSelectColorAction());
getActions().removeRefreshable(getExportAction());
for (Pair<JMenuItem,RefreshListener> record : this.optionListeners) {
record.one().removeItemListener(record.two());
Expand Down

0 comments on commit 0be1bcd

Please sign in to comment.