From 81eac8aedd8d222eff888ed6c7173a02a09f917b Mon Sep 17 00:00:00 2001 From: hneemann Date: Fri, 16 Jun 2017 18:04:37 +0200 Subject: [PATCH] If an error occurs, the name of the affected file is shown. --- distribution/ReleaseNotes.txt | 1 + .../digital/core/ExceptionWithOrigin.java | 56 +++++ .../neemann/digital/core/NodeException.java | 20 +- .../digital/draw/elements/PinException.java | 3 +- .../digital/draw/model/ModelCreator.java | 223 +++++++++--------- .../java/de/neemann/gui/ErrorMessage.java | 12 + src/main/resources/lang/lang_de.xml | 1 + src/main/resources/lang/lang_en.xml | 1 + 8 files changed, 202 insertions(+), 115 deletions(-) create mode 100644 src/main/java/de/neemann/digital/core/ExceptionWithOrigin.java diff --git a/distribution/ReleaseNotes.txt b/distribution/ReleaseNotes.txt index 0b0a6e81b..1c2eb0846 100644 --- a/distribution/ReleaseNotes.txt +++ b/distribution/ReleaseNotes.txt @@ -2,6 +2,7 @@ Release Notes planned as v0.13 - In case of oscillations almost all effected components are shown. +- If an error occurs, the name of the affected file is shown. v0.12.1, released on 05. Jun 2016 - added a fuse to simulate a PROM or PAL. diff --git a/src/main/java/de/neemann/digital/core/ExceptionWithOrigin.java b/src/main/java/de/neemann/digital/core/ExceptionWithOrigin.java new file mode 100644 index 000000000..c69296fbb --- /dev/null +++ b/src/main/java/de/neemann/digital/core/ExceptionWithOrigin.java @@ -0,0 +1,56 @@ +package de.neemann.digital.core; + +import java.io.File; + +/** + * A exception which has a file as an origin + * Created by hneemann on 16.06.17. + */ +public class ExceptionWithOrigin extends Exception { + private File origin; + + /** + * Creates a new exception + * + * @param message message + */ + public ExceptionWithOrigin(String message) { + super(message); + } + + /** + * Creates a new exception + * + * @param message message + * @param cause the cause + */ + public ExceptionWithOrigin(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates a new exception + * + * @param cause the cause + */ + public ExceptionWithOrigin(Throwable cause) { + super(cause); + } + + /** + * @return the origin of the error + */ + public File getOrigin() { + return origin; + } + + /** + * Sets the origin of an error + * + * @param origin the file which causes the exception + */ + public void setOrigin(File origin) { + if (getOrigin() == null) + this.origin = origin; + } +} diff --git a/src/main/java/de/neemann/digital/core/NodeException.java b/src/main/java/de/neemann/digital/core/NodeException.java index 7d2ab0dc1..67c49471f 100644 --- a/src/main/java/de/neemann/digital/core/NodeException.java +++ b/src/main/java/de/neemann/digital/core/NodeException.java @@ -8,7 +8,6 @@ import java.io.File; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; /** * This exception is thrown if there was a problem creating or running the model. @@ -17,7 +16,7 @@ import java.util.HashSet; * * @author hneemann */ -public class NodeException extends Exception { +public class NodeException extends ExceptionWithOrigin { private final ArrayList nodes; private final ImmutableList values; private final int input; @@ -88,11 +87,7 @@ public class NodeException extends Exception { } if (nodes != null && nodes.size() > 0) { - HashSet origins = new HashSet<>(); for (Node node : nodes) { - if (node != null && node.getOrigin() != null && node.getOrigin().length() > 0) - origins.add(node.getOrigin()); - if (node != null) try { // pick the nodes description if available final Field field = node.getClass().getField("DESCRIPTION"); @@ -111,8 +106,6 @@ public class NodeException extends Exception { // ignore an error accessing the ElementTypeDescription } } - for (File o : origins) - items.addItem(o.getName()); } return items.toString(); @@ -152,6 +145,17 @@ public class NodeException extends Exception { sb.append(")"); return sb.toString(); } + } + @Override + public File getOrigin() { + File o = super.getOrigin(); + if (o != null) + return o; + + for (Node n : nodes) + if (n.getOrigin() != null) + return n.getOrigin(); + return null; } } diff --git a/src/main/java/de/neemann/digital/draw/elements/PinException.java b/src/main/java/de/neemann/digital/draw/elements/PinException.java index 8e1738cda..e39104a1e 100644 --- a/src/main/java/de/neemann/digital/draw/elements/PinException.java +++ b/src/main/java/de/neemann/digital/draw/elements/PinException.java @@ -1,5 +1,6 @@ package de.neemann.digital.draw.elements; +import de.neemann.digital.core.ExceptionWithOrigin; import de.neemann.digital.draw.model.Net; /** @@ -7,7 +8,7 @@ import de.neemann.digital.draw.model.Net; * * @author hneemann */ -public class PinException extends Exception { +public class PinException extends ExceptionWithOrigin { private VisualElement element; private Net net; diff --git a/src/main/java/de/neemann/digital/draw/model/ModelCreator.java b/src/main/java/de/neemann/digital/draw/model/ModelCreator.java index d9e74c6ef..26b1efd93 100644 --- a/src/main/java/de/neemann/digital/draw/model/ModelCreator.java +++ b/src/main/java/de/neemann/digital/draw/model/ModelCreator.java @@ -32,6 +32,7 @@ public class ModelCreator implements Iterable { private final NetList netList; private final ArrayList entries; private final HashMap ioMap; + private final File origin; /** * Creates the ModelDescription. @@ -69,7 +70,7 @@ public class ModelCreator implements Iterable { * @param circuit the circuit to use * @param library the library to use * @param isNestedCircuit if true the model is created for use as nested element - * @param fileName only used for better messages in exceptions + * @param origin only used for better messages in exceptions * @param netList the NetList of the model. If known it is not necessary to create it. * @param subName name of the circuit, used to name unique elements * @param depth recursion depth, used to detect a circuit which contains itself @@ -77,7 +78,8 @@ public class ModelCreator implements Iterable { * @throws NodeException NodeException * @throws ElementNotFoundException ElementNotFoundException */ - public ModelCreator(Circuit circuit, ElementLibrary library, boolean isNestedCircuit, File fileName, NetList netList, String subName, int depth) throws PinException, NodeException, ElementNotFoundException { + public ModelCreator(Circuit circuit, ElementLibrary library, boolean isNestedCircuit, File origin, NetList netList, String subName, int depth) throws PinException, NodeException, ElementNotFoundException { + this.origin = origin; this.circuit = circuit; this.netList = netList; entries = new ArrayList<>(); @@ -86,107 +88,112 @@ public class ModelCreator implements Iterable { else ioMap = null; - for (VisualElement ve : circuit.getElements()) { - Pins pins = ve.getPins(); - ElementTypeDescription elementType = library.getElementType(ve.getElementName()); - ElementAttributes attr = ve.getElementAttributes(); - if (attr.getCleanLabel().contains("*")) { - attr = new ElementAttributes(attr); - attr.set(Keys.LABEL, attr.getCleanLabel().replace("*", subName)); - } - Element element = elementType.createElement(attr); - ve.setElement(element); - pins.bindOutputsToOutputPins(element.getOutputs()); - - // sets the nodes origin to create better error messages - if (element instanceof Node) - ((Node) element).setOrigin(fileName); - - // if handled as nested element, don't put pins in EntryList, but put the pins in a - // separate map to connect it with the parent! - boolean isNotAIO = true; - if (isNestedCircuit) { - if (elementType == In.DESCRIPTION || elementType == Out.DESCRIPTION || elementType == Clock.DESCRIPTION) { - String label = ve.getElementAttributes().getLabel(); - if (label == null || label.length() == 0) - throw new PinException(Lang.get("err_pinWithoutName", fileName)); - if (pins.size() != 1) - throw new PinException(Lang.get("err_N_isNotInputOrOutput", label, fileName)); - if (ioMap.containsKey(label)) - throw new PinException(Lang.get("err_duplicatePinLabel", label, fileName)); - - ioMap.put(label, pins.get(0)); - isNotAIO = false; + try { + for (VisualElement ve : circuit.getElements()) { + Pins pins = ve.getPins(); + ElementTypeDescription elementType = library.getElementType(ve.getElementName()); + ElementAttributes attr = ve.getElementAttributes(); + if (attr.getCleanLabel().contains("*")) { + attr = new ElementAttributes(attr); + attr.set(Keys.LABEL, attr.getCleanLabel().replace("*", subName)); } - } + Element element = elementType.createElement(attr); + ve.setElement(element); + pins.bindOutputsToOutputPins(element.getOutputs()); - if (isNotAIO) - entries.add(new ModelEntry(element, pins, ve, elementType.getInputDescription(ve.getElementAttributes()), isNestedCircuit)); + // sets the nodes origin to create better error messages + if (element instanceof Node) + ((Node) element).setOrigin(origin); - for (Pin p : pins) - netList.add(p); - } + // if handled as nested element, don't put pins in EntryList, but put the pins in a + // separate map to connect it with the parent! + boolean isNotAIO = true; + if (isNestedCircuit) { + if (elementType == In.DESCRIPTION || elementType == Out.DESCRIPTION || elementType == Clock.DESCRIPTION) { + String label = ve.getElementAttributes().getLabel(); + if (label == null || label.length() == 0) + throw new PinException(Lang.get("err_pinWithoutName", origin)); + if (pins.size() != 1) + throw new PinException(Lang.get("err_N_isNotInputOrOutput", label, origin)); + if (ioMap.containsKey(label)) + throw new PinException(Lang.get("err_duplicatePinLabel", label, origin)); - // connect all custom elements to the parents net - ArrayList cmdl = new ArrayList<>(); - Iterator it = entries.iterator(); - while (it.hasNext()) { - ModelEntry me = it.next(); - if (me.getElement() instanceof CustomElement) { // at first look for custom elements - CustomElement ce = (CustomElement) me.getElement(); - ModelCreator child = ce.getModelDescription(combineNames(subName, me.getVisualElement().getElementAttributes().getCleanLabel()), depth + 1); - cmdl.add(child); - - HashMap netMatch = new HashMap<>(); - - for (Pin p : me.getPins()) { // connect the custom elements to the parents net - Net childNet = child.getNetOfIOandRemove(p.getName()); - - Net otherParentNet = netMatch.get(childNet); - if (otherParentNet != null) { - // direct connection! - // two nets in the parent are connected directly by the nested circuit - // merge the nets in the parent! - - // remove the childs inner pin which is already added to the other net - Pin insertedPin = child.getPinOfIO(p.getName()); - otherParentNet.removePin(insertedPin); - - Net parentNet = netList.getNetOfPin(p); - if (parentNet != null) { - // Disconnect the parents net from the pin - parentNet.removePin(p); - - // connect the two parent nets if they are not already the same - if (otherParentNet != parentNet) { - otherParentNet.addNet(parentNet); - netList.remove(parentNet); - } - } - } else { - Net parentNet = netList.getNetOfPin(p); - if (parentNet != null) { - // Disconnect the parents net from the pin - parentNet.removePin(p); - // and connect it to the nested inner net! - parentNet.addAll(childNet.getPins()); - - // store net connection - netMatch.put(childNet, parentNet); - } + ioMap.put(label, pins.get(0)); + isNotAIO = false; } } - // remove connected nets form child - for (Net childNet : netMatch.keySet()) - child.remove(childNet); + if (isNotAIO) + entries.add(new ModelEntry(element, pins, ve, elementType.getInputDescription(ve.getElementAttributes()), isNestedCircuit)); - it.remove(); + for (Pin p : pins) + netList.add(p); } - } - for (ModelCreator md : cmdl) { // put the elements of the custom element to the parent - entries.addAll(md.entries); - netList.add(md.netList); + + // connect all custom elements to the parents net + ArrayList cmdl = new ArrayList<>(); + Iterator it = entries.iterator(); + while (it.hasNext()) { + ModelEntry me = it.next(); + if (me.getElement() instanceof CustomElement) { // at first look for custom elements + CustomElement ce = (CustomElement) me.getElement(); + ModelCreator child = ce.getModelDescription(combineNames(subName, me.getVisualElement().getElementAttributes().getCleanLabel()), depth + 1); + cmdl.add(child); + + HashMap netMatch = new HashMap<>(); + + for (Pin p : me.getPins()) { // connect the custom elements to the parents net + Net childNet = child.getNetOfIOandRemove(p.getName()); + + Net otherParentNet = netMatch.get(childNet); + if (otherParentNet != null) { + // direct connection! + // two nets in the parent are connected directly by the nested circuit + // merge the nets in the parent! + + // remove the childs inner pin which is already added to the other net + Pin insertedPin = child.getPinOfIO(p.getName()); + otherParentNet.removePin(insertedPin); + + Net parentNet = netList.getNetOfPin(p); + if (parentNet != null) { + // Disconnect the parents net from the pin + parentNet.removePin(p); + + // connect the two parent nets if they are not already the same + if (otherParentNet != parentNet) { + otherParentNet.addNet(parentNet); + netList.remove(parentNet); + } + } + } else { + Net parentNet = netList.getNetOfPin(p); + if (parentNet != null) { + // Disconnect the parents net from the pin + parentNet.removePin(p); + // and connect it to the nested inner net! + parentNet.addAll(childNet.getPins()); + + // store net connection + netMatch.put(childNet, parentNet); + } + } + } + + // remove connected nets form child + for (Net childNet : netMatch.keySet()) + child.remove(childNet); + + it.remove(); + } + } + for (ModelCreator md : cmdl) { // put the elements of the custom element to the parent + entries.addAll(md.entries); + netList.add(md.netList); + } + } catch (PinException | NodeException e) { + e.setOrigin(origin); + throw e; } } @@ -232,24 +239,28 @@ public class ModelCreator implements Iterable { * @throws NodeException NodeException */ public Model createModel(boolean attachWires) throws PinException, NodeException { + try { + Model m = new Model(); - Model m = new Model(); + for (Net n : netList) + n.interconnect(m, attachWires); - for (Net n : netList) - n.interconnect(m, attachWires); + for (ModelEntry e : entries) + e.applyInputs(); - for (ModelEntry e : entries) - e.applyInputs(); + for (ModelEntry e : entries) + e.getElement().registerNodes(m); - for (ModelEntry e : entries) - e.getElement().registerNodes(m); + for (ModelEntry e : entries) { + e.getElement().init(m); + e.getVisualElement().getShape().registerModel(this, m, e); + } - for (ModelEntry e : entries) { - e.getElement().init(m); - e.getVisualElement().getShape().registerModel(this, m, e); + return m; + } catch (PinException | NodeException e) { + e.setOrigin(origin); + throw e; } - - return m; } /** diff --git a/src/main/java/de/neemann/gui/ErrorMessage.java b/src/main/java/de/neemann/gui/ErrorMessage.java index b396c2816..108aa8251 100644 --- a/src/main/java/de/neemann/gui/ErrorMessage.java +++ b/src/main/java/de/neemann/gui/ErrorMessage.java @@ -1,9 +1,11 @@ package de.neemann.gui; +import de.neemann.digital.core.ExceptionWithOrigin; import de.neemann.digital.lang.Lang; import javax.swing.*; import java.awt.*; +import java.io.File; /** * Used to show error messages. @@ -44,6 +46,16 @@ public class ErrorMessage implements Runnable { if (message.length() > 0) message.append('\n'); addExceptionMessage(e); + + if (e instanceof ExceptionWithOrigin) { + File o = ((ExceptionWithOrigin) e).getOrigin(); + if (o!=null) { + if (message.length() > 0) + message.append('\n'); + message.append(Lang.get("msg_errInFile_N", o.getName())); + } + } + return this; } diff --git a/src/main/resources/lang/lang_de.xml b/src/main/resources/lang/lang_de.xml index 8a8362590..d4c283aef 100644 --- a/src/main/resources/lang/lang_de.xml +++ b/src/main/resources/lang/lang_de.xml @@ -914,6 +914,7 @@ Die Icons stammen aus dem Tango Desktop Project. Zu invertierende Eingänge keine Die Namen der Pins konnten nicht ermittelt werden. + Aufgetreten in Datei {0}! Ok diff --git a/src/main/resources/lang/lang_en.xml b/src/main/resources/lang/lang_en.xml index 98e74a5ef..7c211b1b5 100644 --- a/src/main/resources/lang/lang_en.xml +++ b/src/main/resources/lang/lang_en.xml @@ -901,6 +901,7 @@ The icons are taken from the Tango Desktop Project. Inputs to invert none Could not determine the names of the pins. + Occurred in file {0}! Ok