diff --git a/src/main/dig/processor/ALU/ALU.svg b/src/main/dig/processor/ALU/ALU.svg
index 7b0282420..e644fb1d9 100644
--- a/src/main/dig/processor/ALU/ALU.svg
+++ b/src/main/dig/processor/ALU/ALU.svg
@@ -28,9 +28,9 @@
{
private final String key;
- private final VALUE def;
+ private final DefaultFactory defFactory;
private final String langKey;
private boolean groupEditAllowed = false;
private Key dependsOn;
private CheckEnabled checkEnabled;
+ private boolean isSecondary;
+ private boolean requiresRestart = false;
// Both values are always null in digital.
// Both are only used within a custom implemented component.
private String name;
private String description;
- private boolean isSecondary;
- private boolean requiresRestart = false;
/**
- * Creates a new Key
+ * Creates a new Key.
+ * Use this constructor only if the def value is not mutable!
*
* @param key the key
* @param def the default value
*/
public Key(String key, VALUE def) {
- this.key = key;
- langKey = "key_" + key.replace(" ", "");
+ this(key, () -> def);
if (def == null)
throw new NullPointerException();
- this.def = def;
+ }
+
+ /**
+ * Creates a new Key.
+ * Use this constructor if the def value is mutable!
+ *
+ * @param key the key
+ * @param defFactory the factory to create a default value
+ */
+ public Key(String key, DefaultFactory defFactory) {
+ this.key = key;
+ langKey = "key_" + key.replace(" ", "");
+ if (defFactory == null)
+ throw new NullPointerException();
+ this.defFactory = defFactory;
}
/**
@@ -68,14 +82,14 @@ public class Key {
* @return the default value of this key
*/
public VALUE getDefault() {
- return def;
+ return defFactory.createDefault();
}
/**
* @return The values class
*/
public Class getValueClass() {
- return def.getClass();
+ return getDefault().getClass();
}
@Override
@@ -490,4 +504,18 @@ public class Key {
*/
boolean isEnabled(T t);
}
+
+ /**
+ * Used to provide a default value if the value is mutable.
+ *
+ * @param the type of the value
+ */
+ public interface DefaultFactory {
+ /**
+ * Called to create a new default value.
+ *
+ * @return the default value
+ */
+ VALUE createDefault();
+ }
}
diff --git a/src/main/java/de/neemann/digital/core/element/Keys.java b/src/main/java/de/neemann/digital/core/element/Keys.java
index 178438072..cfb5029f1 100644
--- a/src/main/java/de/neemann/digital/core/element/Keys.java
+++ b/src/main/java/de/neemann/digital/core/element/Keys.java
@@ -278,7 +278,7 @@ public final class Keys {
* the data key for memory
*/
public static final Key DATA
- = new Key<>("Data", DataField.DEFAULT);
+ = new Key<>("Data", DataField::new);
/**
* flag for flipping selector pos in muxers, decoders and drivers
@@ -602,7 +602,7 @@ public final class Keys {
* contains the input inverter config
*/
public static final Key INVERTER_CONFIG
- = new Key<>("inverterConfig", new InverterConfig());
+ = new Key<>("inverterConfig", new InverterConfig.Builder().build());
/**
* Background Color of nested circuits
@@ -661,7 +661,7 @@ public final class Keys {
* The manager which contains all the roms data
*/
public static final Key ROMMANAGER
- = new Key<>("romContent", ROMManger.EMPTY).setSecondary();
+ = new Key<>("romContent", ROMManger::new).setSecondary();
/**
@@ -707,7 +707,7 @@ public final class Keys {
* Shape used to represent a visual element
*/
public static final Key CUSTOM_SHAPE
- = new Key<>("customShape", CustomShapeDescription.EMPTY)
+ = new Key<>("customShape", new CustomShapeDescription.Builder().build())
.setSecondary()
.setDependsOn(SHAPE_TYPE, st -> st.equals(CustomCircuitShapeType.CUSTOM));
diff --git a/src/main/java/de/neemann/digital/core/memory/DataField.java b/src/main/java/de/neemann/digital/core/memory/DataField.java
index 52cded480..1b3a382d8 100644
--- a/src/main/java/de/neemann/digital/core/memory/DataField.java
+++ b/src/main/java/de/neemann/digital/core/memory/DataField.java
@@ -17,15 +17,17 @@ import java.util.Arrays;
*/
public class DataField implements HGSArray {
- /***
- * Simple default data field
- */
- public static final DataField DEFAULT = new DataField(0);
-
private long[] data;
private final transient ArrayList listeners = new ArrayList<>();
+ /**
+ * Creates a new DataField of size 0
+ */
+ public DataField() {
+ this(0);
+ }
+
/**
* Creates a new DataField
*
@@ -174,6 +176,13 @@ public class DataField implements HGSArray {
return data.length;
}
+ /**
+ * @return true if the data field is empty
+ */
+ public boolean isEmpty() {
+ return trim() == 0;
+ }
+
/**
* Adds a listener to this DataField
*
@@ -247,4 +256,17 @@ public class DataField implements HGSArray {
public long[] getData() {
return data;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DataField dataField = (DataField) o;
+ return Arrays.equals(data, dataField.data);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(data);
+ }
}
diff --git a/src/main/java/de/neemann/digital/core/memory/EEPROM.java b/src/main/java/de/neemann/digital/core/memory/EEPROM.java
index 9b02cd47a..b21034f44 100644
--- a/src/main/java/de/neemann/digital/core/memory/EEPROM.java
+++ b/src/main/java/de/neemann/digital/core/memory/EEPROM.java
@@ -5,10 +5,7 @@
*/
package de.neemann.digital.core.memory;
-import de.neemann.digital.core.Node;
-import de.neemann.digital.core.NodeException;
-import de.neemann.digital.core.ObservableValue;
-import de.neemann.digital.core.ObservableValues;
+import de.neemann.digital.core.*;
import de.neemann.digital.core.element.Element;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
@@ -40,6 +37,7 @@ public class EEPROM extends Node implements Element, RAMInterface, ROMInterface
private final int bits;
private final int addrBits;
+ private final ElementAttributes attr;
private final int size;
private final String label;
private final ObservableValue dataOut;
@@ -65,6 +63,7 @@ public class EEPROM extends Node implements Element, RAMInterface, ROMInterface
*/
public EEPROM(ElementAttributes attr) {
super(true);
+ this.attr = attr;
bits = attr.get(Keys.BITS);
addrBits = attr.get(Keys.ADDR_BITS);
size = 1 << addrBits;
@@ -77,6 +76,14 @@ public class EEPROM extends Node implements Element, RAMInterface, ROMInterface
isProgramMemory = attr.get(Keys.IS_PROGRAM_MEMORY);
}
+ @Override
+ public void registerNodes(Model model) {
+ super.registerNodes(model);
+
+ if (memory.isEmpty())
+ model.addObserver(event -> attr.set(Keys.DATA, memory), ModelEvent.STOPPED);
+ }
+
@Override
public void setInputs(ObservableValues inputs) throws NodeException {
addrIn = inputs.get(0).checkBits(addrBits, this).addObserverToValue(this);
diff --git a/src/main/java/de/neemann/digital/core/memory/EEPROMDualPort.java b/src/main/java/de/neemann/digital/core/memory/EEPROMDualPort.java
index d1f11e4dc..caa2c157c 100644
--- a/src/main/java/de/neemann/digital/core/memory/EEPROMDualPort.java
+++ b/src/main/java/de/neemann/digital/core/memory/EEPROMDualPort.java
@@ -5,6 +5,8 @@
*/
package de.neemann.digital.core.memory;
+import de.neemann.digital.core.Model;
+import de.neemann.digital.core.ModelEvent;
import de.neemann.digital.core.element.ElementAttributes;
import de.neemann.digital.core.element.ElementTypeDescription;
import de.neemann.digital.core.element.Keys;
@@ -33,6 +35,9 @@ public class EEPROMDualPort extends RAMDualPort implements ROMInterface {
.addAttribute(Keys.LABEL)
.addAttribute(Keys.DATA);
+ private final ElementAttributes attr;
+ private DataField memory;
+
/**
* Creates a new instance
*
@@ -40,11 +45,21 @@ public class EEPROMDualPort extends RAMDualPort implements ROMInterface {
*/
public EEPROMDualPort(ElementAttributes attr) {
super(attr);
+ this.attr = attr;
}
@Override
protected DataField createDataField(ElementAttributes attr, int size) {
- return attr.get(Keys.DATA);
+ memory = attr.get(Keys.DATA);
+ return memory;
+ }
+
+ @Override
+ public void registerNodes(Model model) {
+ super.registerNodes(model);
+
+ if (memory.isEmpty())
+ model.addObserver(event -> attr.set(Keys.DATA, memory), ModelEvent.STOPPED);
}
}
diff --git a/src/main/java/de/neemann/digital/core/memory/rom/ROMManger.java b/src/main/java/de/neemann/digital/core/memory/rom/ROMManger.java
index 875826f2b..413e1acbe 100644
--- a/src/main/java/de/neemann/digital/core/memory/rom/ROMManger.java
+++ b/src/main/java/de/neemann/digital/core/memory/rom/ROMManger.java
@@ -10,15 +10,12 @@ import de.neemann.digital.core.Node;
import de.neemann.digital.core.memory.DataField;
import java.util.HashMap;
+import java.util.Objects;
/**
* The Manager to manage all necessary rom images
*/
public class ROMManger {
- /**
- * The empty instance
- */
- public static final ROMManger EMPTY = new ROMManger();
private final HashMap roms;
@@ -35,6 +32,8 @@ public class ROMManger {
* @param model the mode to use
*/
public void applyTo(Model model) {
+ if (roms == null)
+ return;
for (Node n : model.findNode(n -> n instanceof ROMInterface)) {
ROMInterface rom = (ROMInterface) n;
DataField data = roms.get(rom.getLabel());
@@ -65,19 +64,23 @@ public class ROMManger {
roms.put(label, data);
}
- /**
- * @return returns EMPTY it this ROMManager is empty, this otherwise
- */
- public ROMManger getMinimized() {
- if (roms.isEmpty())
- return EMPTY;
- return this;
- }
-
/**
* @return true if no ROM's are stored
*/
public boolean isEmpty() {
return roms.isEmpty();
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ROMManger romManger = (ROMManger) o;
+ return Objects.equals(roms, romManger.roms);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(roms);
+ }
}
diff --git a/src/main/java/de/neemann/digital/draw/model/InverterConfig.java b/src/main/java/de/neemann/digital/draw/model/InverterConfig.java
index 3df26a194..46286b991 100644
--- a/src/main/java/de/neemann/digital/draw/model/InverterConfig.java
+++ b/src/main/java/de/neemann/digital/draw/model/InverterConfig.java
@@ -15,29 +15,12 @@ import java.util.Objects;
/**
* Manages the input inverting of a component
*/
-public class InverterConfig implements HGSMap {
+public final class InverterConfig implements HGSMap {
private HashSet inputs;
- /**
- * Creates a new instance.
- * No input is inverted.
- */
- public InverterConfig() {
- inputs = null;
- }
-
- /**
- * Adds a signal to invert
- *
- * @param name the signale
- * @return this for chained calls
- */
- public InverterConfig add(String name) {
- if (inputs == null)
- inputs = new HashSet<>();
- inputs.add(name);
- return this;
+ private InverterConfig(HashSet inputs) {
+ this.inputs = inputs;
}
/**
@@ -129,4 +112,35 @@ public class InverterConfig implements HGSMap {
return inputs.contains(key);
}
+
+ /**
+ * Builder to create InverterConfig instances
+ */
+ public static class Builder {
+
+ private HashSet inputs;
+
+ /**
+ * Adds a signal to invert
+ *
+ * @param name the signale
+ * @return this for chained calls
+ */
+ public Builder add(String name) {
+ if (inputs == null)
+ inputs = new HashSet<>();
+ inputs.add(name);
+ return this;
+ }
+
+ /**
+ * Creats the instance
+ *
+ * @return the created instance
+ */
+ public InverterConfig build() {
+ return new InverterConfig(inputs);
+ }
+
+ }
}
diff --git a/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java b/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java
index 49564f1ee..be12a28fb 100644
--- a/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java
+++ b/src/main/java/de/neemann/digital/draw/shapes/ShapeFactory.java
@@ -212,7 +212,7 @@ public final class ShapeFactory {
return new LayoutShape(customDescr, elementAttributes);
case CUSTOM:
final CustomShapeDescription customShapeDescription = customDescr.getAttributes().get(Keys.CUSTOM_SHAPE);
- if (customShapeDescription != CustomShapeDescription.EMPTY)
+ if (!customShapeDescription.isEmpty())
return new CustomShape(customShapeDescription, elementAttributes.getLabel(),
pt.getInputDescription(elementAttributes),
pt.getOutputDescriptions(elementAttributes));
diff --git a/src/main/java/de/neemann/digital/draw/shapes/custom/CustomShapeDescription.java b/src/main/java/de/neemann/digital/draw/shapes/custom/CustomShapeDescription.java
index 63bffe51a..f2ad8b9c9 100644
--- a/src/main/java/de/neemann/digital/draw/shapes/custom/CustomShapeDescription.java
+++ b/src/main/java/de/neemann/digital/draw/shapes/custom/CustomShapeDescription.java
@@ -24,95 +24,19 @@ import java.util.Iterator;
/**
* Is intended to be stored in a file.
*/
-public class CustomShapeDescription implements Iterable {
- /**
- * The default empty shape instance
- */
- public static final CustomShapeDescription EMPTY = new CustomShapeDescription();
+public final class CustomShapeDescription implements Iterable {
- private HashMap pins;
- private ArrayList drawables;
- private TextHolder label;
+ private final HashMap pins;
+ private final ArrayList drawables;
+ private final TextHolder label;
/**
* Creates a new instance
*/
- public CustomShapeDescription() {
- pins = new HashMap<>();
- drawables = new ArrayList<>();
- }
-
- /**
- * Adds a pin to this shape description
- *
- * @param name the name of the pin
- * @param pos the pins position
- * @param showLabel if true the label of the pin is shown
- * @return this for chained calls
- */
- public CustomShapeDescription addPin(String name, Vector pos, boolean showLabel) {
- pins.put(name, new Pin(pos, showLabel));
- return this;
- }
-
-
- /**
- * Adds a polygon to the shape
- *
- * @param p1 starting point of the line
- * @param p2 ending point of the line
- * @param thickness the line thickness
- * @param color the color to use
- * @return this for chained calls
- */
- public CustomShapeDescription addLine(Vector p1, Vector p2, int thickness, Color color) {
- drawables.add(new LineHolder(p1, p2, thickness, color));
- return this;
- }
-
- /**
- * Adds a circle to the shape
- *
- * @param p1 upper left corner of the circles bounding box
- * @param p2 lower right corner of the circles bounding box
- * @param thickness the line thickness
- * @param color the color to use
- * @param filled true if filled
- * @return this for chained calls
- */
- public CustomShapeDescription addCircle(Vector p1, Vector p2, int thickness, Color color, boolean filled) {
- drawables.add(new CircleHolder(p1, p2, thickness, color, filled));
- return this;
- }
-
- /**
- * Adds a polygon to the shape
- *
- * @param poly the polygon to add
- * @param thickness the line thickness
- * @param color the color to use
- * @param filled true if filled
- * @return this for chained calls
- */
- public CustomShapeDescription addPolygon(Polygon poly, int thickness, Color color, boolean filled) {
- drawables.add(new PolygonHolder(poly, thickness, filled, color));
- return this;
- }
-
- /**
- * Adds a text to the shape
- *
- * @param p1 position
- * @param p2 second position to determin the base line orientation
- * @param text the text to draw
- * @param orientation the orientation of the text
- * @param size the font size
- * @param color the text color
- * @return this for chained calls
- */
- public CustomShapeDescription addText(Vector p1, Vector p2, String text, Orientation orientation, int size, Color color) {
- drawables.add(new TextHolder(p1, p2, text, orientation, size, color));
- return this;
+ private CustomShapeDescription(HashMap pins, ArrayList drawables, TextHolder label) {
+ this.pins = pins;
+ this.drawables = drawables;
+ this.label = label;
}
/**
@@ -155,19 +79,6 @@ public class CustomShapeDescription implements Iterable pins;
+ private final ArrayList drawables;
+ private TextHolder label;
+
+ /**
+ * Creates a new builder
+ */
+ public Builder() {
+ pins = new HashMap<>();
+ drawables = new ArrayList<>();
+ }
+
+ /**
+ * Sets the label positioning info.
+ *
+ * @param pos0 pos0
+ * @param pos1 pos1
+ * @param textOrientation textOrientation
+ * @param fontSize fontSize
+ * @param filled filled
+ * @return this for chained calls
+ */
+ public Builder setLabel(Vector pos0, Vector pos1, Orientation textOrientation, int fontSize, Color filled) {
+ label = new TextHolder(pos0, pos1, "", textOrientation, fontSize, filled);
+ return this;
+ }
+
+ /**
+ * Adds a pin to this shape description
+ *
+ * @param name the name of the pin
+ * @param pos the pins position
+ * @param showLabel if true the label of the pin is shown
+ * @return this for chained calls
+ */
+ public Builder addPin(String name, Vector pos, boolean showLabel) {
+ pins.put(name, new Pin(pos, showLabel));
+ return this;
+ }
+
+
+ /**
+ * Adds a polygon to the shape
+ *
+ * @param p1 starting point of the line
+ * @param p2 ending point of the line
+ * @param thickness the line thickness
+ * @param color the color to use
+ * @return this for chained calls
+ */
+ public Builder addLine(Vector p1, Vector p2, int thickness, Color color) {
+ drawables.add(new LineHolder(p1, p2, thickness, color));
+ return this;
+ }
+
+ /**
+ * Adds a circle to the shape
+ *
+ * @param p1 upper left corner of the circles bounding box
+ * @param p2 lower right corner of the circles bounding box
+ * @param thickness the line thickness
+ * @param color the color to use
+ * @param filled true if filled
+ * @return this for chained calls
+ */
+ public Builder addCircle(Vector p1, Vector p2, int thickness, Color color, boolean filled) {
+ drawables.add(new CircleHolder(p1, p2, thickness, color, filled));
+ return this;
+ }
+
+ /**
+ * Adds a polygon to the shape
+ *
+ * @param poly the polygon to add
+ * @param thickness the line thickness
+ * @param color the color to use
+ * @param filled true if filled
+ * @return this for chained calls
+ */
+ public Builder addPolygon(Polygon poly, int thickness, Color color, boolean filled) {
+ drawables.add(new PolygonHolder(poly, thickness, filled, color));
+ return this;
+ }
+
+ /**
+ * Adds a text to the shape
+ *
+ * @param p1 position
+ * @param p2 second position to determin the base line orientation
+ * @param text the text to draw
+ * @param orientation the orientation of the text
+ * @param size the font size
+ * @param color the text color
+ * @return this for chained calls
+ */
+ public Builder addText(Vector p1, Vector p2, String text, Orientation orientation, int size, Color color) {
+ drawables.add(new TextHolder(p1, p2, text, orientation, size, color));
+ return this;
+ }
+
+ /**
+ * @return the {@link CustomShapeDescription}
+ */
+ public CustomShapeDescription build() {
+ return new CustomShapeDescription(pins, drawables, label);
+ }
+
+ }
}
diff --git a/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java b/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java
index adb7d78c5..a07e3e82c 100644
--- a/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java
+++ b/src/main/java/de/neemann/digital/draw/shapes/custom/svg/SvgImporter.java
@@ -67,9 +67,10 @@ public class SvgImporter {
NodeList gList = svg.getElementsByTagName("svg").item(0).getChildNodes();
Context c = new Context();
try {
- CustomShapeDescription csd = new CustomShapeDescription();
- create(csd, gList, c);
+ CustomShapeDescription.Builder builder = new CustomShapeDescription.Builder();
+ create(builder, gList, c);
+ CustomShapeDescription csd = builder.build();
if (csd.getPinCount() > 0) {
float xMin = Float.MAX_VALUE;
float yMin = Float.MAX_VALUE;
@@ -86,7 +87,7 @@ public class SvgImporter {
}
}
- private void create(CustomShapeDescription csd, NodeList gList, Context c) throws SvgException {
+ private void create(CustomShapeDescription.Builder csd, NodeList gList, Context c) throws SvgException {
for (int i = 0; i < gList.getLength(); i++) {
final Node node = gList.item(i);
if (node instanceof Element) {
@@ -99,7 +100,7 @@ public class SvgImporter {
}
}
- private void create(CustomShapeDescription csd, Element element, Context parent) throws SvgException {
+ private void create(CustomShapeDescription.Builder csd, Element element, Context parent) throws SvgException {
Context c = new Context(parent, element);
switch (element.getNodeName()) {
case "a":
@@ -150,19 +151,19 @@ public class SvgImporter {
}
}
- private void drawTransformedPolygon(CustomShapeDescription csd, Context c, Polygon polygon) {
+ private void drawTransformedPolygon(CustomShapeDescription.Builder csd, Context c, Polygon polygon) {
if (polygon != null)
drawPolygon(csd, c, polygon.transform(c.getTransform()));
}
- private void drawPolygon(CustomShapeDescription csd, Context c, Polygon polygon) {
+ private void drawPolygon(CustomShapeDescription.Builder csd, Context c, Polygon polygon) {
if (c.getFilled() != null && polygon.isClosed())
csd.addPolygon(polygon, c.getThickness(), c.getFilled(), true);
if (c.getStroke() != null)
csd.addPolygon(polygon, c.getThickness(), c.getStroke(), false);
}
- private void drawRect(CustomShapeDescription csd, Element element, Context c) {
+ private void drawRect(CustomShapeDescription.Builder csd, Element element, Context c) {
VectorInterface size = new VectorFloat(c.getLength(element.getAttribute("width")), c.getLength(element.getAttribute("height")));
VectorInterface pos = new VectorFloat(c.getLength(element.getAttribute("x")), c.getLength(element.getAttribute("y")));
String rxStr = element.getAttribute("rx");
@@ -213,7 +214,7 @@ public class SvgImporter {
drawPolygon(csd, c, polygon);
}
- private void drawCircle(CustomShapeDescription csd, Element element, Context c) {
+ private void drawCircle(CustomShapeDescription.Builder csd, Element element, Context c) {
if (element.hasAttribute("id")) {
VectorInterface pos = c.v(c.getLength(element.getAttribute("cx")), c.getLength(element.getAttribute("cy")));
String id = element.getAttribute("id");
@@ -279,7 +280,7 @@ public class SvgImporter {
return new Vector(Math.round(pos.getXFloat() / SIZE) * SIZE, Math.round(pos.getYFloat() / SIZE) * SIZE);
}
- private void drawText(CustomShapeDescription csd, Context c, Element element) throws SvgException {
+ private void drawText(CustomShapeDescription.Builder csd, Context c, Element element) throws SvgException {
VectorFloat p = new VectorFloat(c.getLength(element.getAttribute("x")), c.getLength(element.getAttribute("y")));
VectorInterface pos0 = p.transform(c.getTransform());
VectorInterface pos1 = p.add(new VectorFloat(1, 0)).transform(c.getTransform());
@@ -290,7 +291,7 @@ public class SvgImporter {
drawTextElement(csd, c, element, pos0, pos1);
}
- private void drawTextElement(CustomShapeDescription csd, Context c, Element element, VectorInterface pos0, VectorInterface pos1) throws SvgException {
+ private void drawTextElement(CustomShapeDescription.Builder csd, Context c, Element element, VectorInterface pos0, VectorInterface pos1) throws SvgException {
NodeList nodes = element.getElementsByTagName("*");
if (nodes.getLength() == 0) {
String text = element.getTextContent();
diff --git a/src/main/java/de/neemann/digital/gui/components/CustomShapeEditor.java b/src/main/java/de/neemann/digital/gui/components/CustomShapeEditor.java
index 68ffa1464..0acf90e1b 100644
--- a/src/main/java/de/neemann/digital/gui/components/CustomShapeEditor.java
+++ b/src/main/java/de/neemann/digital/gui/components/CustomShapeEditor.java
@@ -52,7 +52,7 @@ public class CustomShapeEditor extends EditorFactory.LabelEditor names;
diff --git a/src/main/java/de/neemann/digital/testing/TestCaseElement.java b/src/main/java/de/neemann/digital/testing/TestCaseElement.java
index 52da4df05..564d3e2c5 100644
--- a/src/main/java/de/neemann/digital/testing/TestCaseElement.java
+++ b/src/main/java/de/neemann/digital/testing/TestCaseElement.java
@@ -18,7 +18,7 @@ public class TestCaseElement implements Element {
/**
* the used {@link ElementAttributes} key
*/
- public static final Key TESTDATA = new Key<>("Testdata", TestCaseDescription.DEFAULT);
+ public static final Key TESTDATA = new Key<>("Testdata", () -> new TestCaseDescription(""));
/**
* The TestCaseElement description