diff --git a/src/main/dig/Ampel_Einfach.dig b/src/main/dig/Ampel_Einfach.dig index e2e533dc4..5af070757 100644 --- a/src/main/dig/Ampel_Einfach.dig +++ b/src/main/dig/Ampel_Einfach.dig @@ -113,13 +113,6 @@ Clock - - - Frequency - 1 - - 5 - 0 diff --git a/src/main/dig/JK-Trigger.dig b/src/main/dig/JK-Trigger.dig index 38db34c7a..b0d55d527 100644 --- a/src/main/dig/JK-Trigger.dig +++ b/src/main/dig/JK-Trigger.dig @@ -13,20 +13,6 @@ 0 - - In - - - - Label - - - C - - - - 0 - And @@ -45,7 +31,7 @@ And - + 3 @@ -68,8 +54,11 @@ In - - K + + Label + + + J @@ -79,21 +68,6 @@ 1 - - 0 - - - In - - - - J - - - - 1 - - 0 @@ -101,7 +75,7 @@ Out - + Q @@ -112,7 +86,7 @@ Out - + ~Q @@ -139,6 +113,31 @@ 0 + + In + + + + Label + + + C + + + + 0 + + + In + + + + K + + + + 0 + diff --git a/src/main/dig/MS-JK.dig b/src/main/dig/MS-JK.dig index c4dda1442..487911458 100644 --- a/src/main/dig/MS-JK.dig +++ b/src/main/dig/MS-JK.dig @@ -53,21 +53,6 @@ 0 - - In - - - - K - - - - 1 - - - - 0 - In @@ -137,6 +122,20 @@ 0 + + In + + + + Label + + + K + + + + 0 + @@ -155,50 +154,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -207,6 +166,10 @@ + + + + @@ -271,6 +234,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -279,21 +294,13 @@ - - - - - - - - - - + + @@ -319,6 +326,14 @@ + + + + + + + + @@ -327,21 +342,5 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/dig/splitter.dig b/src/main/dig/splitter.dig index 3cd02c5ef..bf910a51c 100644 --- a/src/main/dig/splitter.dig +++ b/src/main/dig/splitter.dig @@ -1,3 +1,4 @@ + @@ -136,25 +137,25 @@ In - + 0 In - + 0 In - + 0 In - + 0 @@ -169,31 +170,31 @@ 1,1,1,1 - + 0 Out - + 0 Out - + 0 Out - + 0 Out - + 0 @@ -322,13 +323,13 @@ Not - + 0 Not - + 0 @@ -433,24 +434,24 @@ - + - - + + - + - - + + - + @@ -493,20 +494,20 @@ - + - - + + - - + + - - + + @@ -537,12 +538,12 @@ - + - - + + diff --git a/src/main/java/de/neemann/digital/core/basic/FanIn.java b/src/main/java/de/neemann/digital/core/basic/FanIn.java index cd4fb20f9..8f2ba30e9 100644 --- a/src/main/java/de/neemann/digital/core/basic/FanIn.java +++ b/src/main/java/de/neemann/digital/core/basic/FanIn.java @@ -43,8 +43,8 @@ public abstract class FanIn extends Node implements Element { addAttributes(); } - public FanInDescription(String name, PartFactory partFactory) { - super(name, partFactory); + public FanInDescription(String name, ElementFactory elementFactory) { + super(name, elementFactory); addAttributes(); } diff --git a/src/main/java/de/neemann/digital/core/element/PartFactory.java b/src/main/java/de/neemann/digital/core/element/ElementFactory.java similarity index 78% rename from src/main/java/de/neemann/digital/core/element/PartFactory.java rename to src/main/java/de/neemann/digital/core/element/ElementFactory.java index 0cade7746..6b88bbf55 100644 --- a/src/main/java/de/neemann/digital/core/element/PartFactory.java +++ b/src/main/java/de/neemann/digital/core/element/ElementFactory.java @@ -3,6 +3,6 @@ package de.neemann.digital.core.element; /** * @author hneemann */ -public interface PartFactory { +public interface ElementFactory { Element create(ElementAttributes attributes); } diff --git a/src/main/java/de/neemann/digital/core/element/ElementTypeDescription.java b/src/main/java/de/neemann/digital/core/element/ElementTypeDescription.java index 2bdfb1c5c..5b14eced2 100644 --- a/src/main/java/de/neemann/digital/core/element/ElementTypeDescription.java +++ b/src/main/java/de/neemann/digital/core/element/ElementTypeDescription.java @@ -4,7 +4,7 @@ import java.lang.reflect.Constructor; import java.util.ArrayList; /** - * One instance for a element, so there is only one PartDescription for an AND. + * One instance for an element, so there is only one ElementTypeDescription for an AND. * Regardless of how many of these elements are used in the circuit. * It has the possibility to create a concrete element by using the given factory * @@ -13,7 +13,7 @@ import java.util.ArrayList; public class ElementTypeDescription { private final String name; private String shortName; - private final PartFactory partFactory; + private final ElementFactory elementFactory; private final String[] inputNames; private final ArrayList attributeList; @@ -22,7 +22,7 @@ public class ElementTypeDescription { } public ElementTypeDescription(String name, Class clazz, String... inputNames) { - this(name, new PartFactory() { + this(name, new ElementFactory() { @Override public Element create(ElementAttributes attributes) { try { @@ -35,10 +35,10 @@ public class ElementTypeDescription { }, inputNames); } - public ElementTypeDescription(String name, PartFactory partFactory, String... inputNames) { + public ElementTypeDescription(String name, ElementFactory elementFactory, String... inputNames) { this.name = name; this.shortName = name; - this.partFactory = partFactory; + this.elementFactory = elementFactory; this.inputNames = inputNames; attributeList = new ArrayList<>(); } @@ -118,6 +118,6 @@ public class ElementTypeDescription { * @return the Part instance */ public Element createElement(ElementAttributes elementAttributes) { - return partFactory.create(elementAttributes); + return elementFactory.create(elementAttributes); } } diff --git a/src/main/java/de/neemann/digital/gui/LibrarySelector.java b/src/main/java/de/neemann/digital/gui/LibrarySelector.java index e99c2292e..a664af252 100644 --- a/src/main/java/de/neemann/digital/gui/LibrarySelector.java +++ b/src/main/java/de/neemann/digital/gui/LibrarySelector.java @@ -1,30 +1,62 @@ package de.neemann.digital.gui; +import de.neemann.digital.core.element.Element; +import de.neemann.digital.core.element.ElementAttributes; +import de.neemann.digital.core.element.ElementFactory; +import de.neemann.digital.core.element.ElementTypeDescription; import de.neemann.digital.gui.components.CircuitComponent; +import de.neemann.digital.gui.draw.elements.Circuit; import de.neemann.digital.gui.draw.elements.VisualElement; import de.neemann.digital.gui.draw.graphics.Vector; +import de.neemann.digital.gui.draw.library.CustomElement; import de.neemann.digital.gui.draw.library.ElementLibrary; +import de.neemann.digital.gui.draw.library.ElementNotFoundNotification; +import de.process.utils.gui.ErrorMessage; import de.process.utils.gui.ToolTipAction; import javax.swing.*; import java.awt.event.ActionEvent; +import java.io.File; /** * @author hneemann */ -public class LibrarySelector { +public class LibrarySelector implements ElementNotFoundNotification { private final ElementLibrary library; + private File lastFile; + private File filePath; + private JMenu customMenu; + private InsertHistory insertHistory; + private CircuitComponent circuitComponent; public LibrarySelector(ElementLibrary library) { this.library = library; + library.setElementNotFoundNotification(this); } public JMenu buildMenu(InsertHistory insertHistory, CircuitComponent circuitComponent) { + this.insertHistory = insertHistory; + this.circuitComponent = circuitComponent; JMenu parts = new JMenu("Elements"); + customMenu = new JMenu("Custom"); + parts.add(customMenu); + + ToolTipAction importAction = new ToolTipAction("Import") { + @Override + public void actionPerformed(ActionEvent e) { + JFileChooser fc = Main.getjFileChooser(lastFile); + if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { + importElement(fc.getSelectedFile()); + } + } + }.setToolTip("Imports a model as a useable Element!"); + customMenu.add(importAction.createJMenuItem()); + + JMenu subMenu = null; String lastPath = null; - for (ElementLibrary.PartContainer pc : library) { + for (ElementLibrary.ElementContainer pc : library) { String path = pc.getTreePath(); if (!path.equals(lastPath)) { subMenu = new JMenu(path); @@ -37,6 +69,19 @@ public class LibrarySelector { return parts; } + public void setLastFile(File lastFile) { + this.lastFile = lastFile; + } + + public void setFilePath(File filePath) { + this.filePath = filePath; + } + + @Override + public ElementTypeDescription notFound(String elementName) { + return importElement(new File(filePath, elementName)); + } + private class InsertAction extends ToolTipAction { private final String name; @@ -58,4 +103,22 @@ public class LibrarySelector { } } + private ElementTypeDescription importElement(File file) { + try { + Circuit circuit = Circuit.loadCircuit(file); + ElementTypeDescription description = new ElementTypeDescription(file.getName(), new ElementFactory() { + @Override + public Element create(ElementAttributes attributes) { + return new CustomElement(circuit, library); + } + }, circuit.getInputNames(library)); + library.addDescription(description); + customMenu.add(new InsertAction(description.getName(), insertHistory, circuitComponent)); + return description; + } catch (Exception e) { + new ErrorMessage("error importing model").addCause(e).show(); + } + return null; + } + } diff --git a/src/main/java/de/neemann/digital/gui/Main.java b/src/main/java/de/neemann/digital/gui/Main.java index cc64ae571..aa6974fbe 100644 --- a/src/main/java/de/neemann/digital/gui/Main.java +++ b/src/main/java/de/neemann/digital/gui/Main.java @@ -1,20 +1,12 @@ package de.neemann.digital.gui; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; -import com.thoughtworks.xstream.io.xml.StaxDriver; import de.neemann.digital.core.Model; import de.neemann.digital.core.NodeException; import de.neemann.digital.core.Observer; import de.neemann.digital.core.SpeedTest; -import de.neemann.digital.core.element.AttributeKey; -import de.neemann.digital.core.element.ElementAttributes; import de.neemann.digital.gui.components.CircuitComponent; import de.neemann.digital.gui.draw.elements.Circuit; import de.neemann.digital.gui.draw.elements.PinException; -import de.neemann.digital.gui.draw.elements.VisualElement; -import de.neemann.digital.gui.draw.elements.Wire; -import de.neemann.digital.gui.draw.graphics.Vector; import de.neemann.digital.gui.draw.library.ElementLibrary; import de.neemann.digital.gui.draw.model.ModelDescription; import de.neemann.digital.gui.draw.shapes.ShapeFactory; @@ -27,7 +19,8 @@ import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.awt.event.ActionEvent; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.util.prefs.Preferences; /** @@ -41,6 +34,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave { private final ElementLibrary library = ShapeFactory.getInstance().setLibrary(new ElementLibrary()); private final ToolTipAction doStep; private final JCheckBoxMenuItem traceEnable; + private final LibrarySelector librarySelector; private File filename; private Model model; private ModelDescription modelDescription; @@ -198,7 +192,8 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave { toolBar.addSeparator(); - bar.add(new LibrarySelector(library).buildMenu(new InsertHistory(toolBar), circuitComponent)); + librarySelector = new LibrarySelector(library); + bar.add(librarySelector.buildMenu(new InsertHistory(toolBar), circuitComponent)); getContentPane().add(toolBar, BorderLayout.NORTH); @@ -206,19 +201,6 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave { InfoDialog.getInstance().addToFrame(this, MESSAGE); } - private static XStream getxStream() { - XStream xStream = new XStream(new StaxDriver()); - xStream.alias("visualElement", VisualElement.class); - xStream.alias("wire", Wire.class); - xStream.alias("circuit", Circuit.class); - xStream.alias("vector", Vector.class); - xStream.alias("key", AttributeKey.class); - xStream.addImplicitCollection(ElementAttributes.class, "attributes"); - xStream.aliasAttribute(Vector.class, "x", "x"); - xStream.aliasAttribute(Vector.class, "y", "y"); - return xStream; - } - public static void main(String[] args) { SwingUtilities.invokeLater(() -> new Main().setVisible(true)); } @@ -277,13 +259,14 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave { } private void loadFile(File filename) { - XStream xStream = getxStream(); - try (InputStream in = new FileInputStream(filename)) { - Circuit circuit = (Circuit) xStream.fromXML(in); - circuitComponent.setCircuit(circuit); + try { + librarySelector.setFilePath(filename.getParentFile()); + Circuit circ = Circuit.loadCircuit(filename); + circuitComponent.setCircuit(circ); setFilename(filename); } catch (Exception e) { - new ErrorMessage("error loading file " + filename).addCause(e).show(); + circuitComponent.setCircuit(new Circuit()); + new ErrorMessage("error reading a file").addCause(e).show(this); } } @@ -291,12 +274,9 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave { if (!filename.getName().endsWith(".dig")) filename = new File(filename.getPath() + ".dig"); - XStream xStream = getxStream(); - try (Writer out = new OutputStreamWriter(new FileOutputStream(filename), "utf-8")) { - out.write("\n"); - xStream.marshal(circuitComponent.getCircuit(), new PrettyPrintWriter(out)); + try { + circuitComponent.getCircuit().save(filename); setFilename(filename); - circuitComponent.getCircuit().saved(); } catch (IOException e) { new ErrorMessage("error writing a file").addCause(e).show(); } @@ -304,6 +284,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave { private void setFilename(File filename) { this.filename = filename; + librarySelector.setLastFile(filename); if (filename != null) { prefs.put("name", filename.getPath()); setTitle(filename + " - Digital"); diff --git a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java index 24c116481..b21b559d3 100644 --- a/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java +++ b/src/main/java/de/neemann/digital/gui/components/CircuitComponent.java @@ -327,6 +327,7 @@ public class CircuitComponent extends JComponent implements Observer { private ArrayList elements; private Vector lastPos; private State state; + private Vector copyStartPosition; private boolean wasRealyDragged; @Override @@ -352,6 +353,7 @@ public class CircuitComponent extends JComponent implements Observer { state = State.MOVE; } else { elements = circuit.getElementsToCopy(Vector.min(corner1, corner2), Vector.max(corner1, corner2)); + copyStartPosition = raster(getPosVector(e)); state = State.COPY; } lastPos = getPosVector(e); @@ -360,14 +362,14 @@ public class CircuitComponent extends JComponent implements Observer { @Override public void mouseReleased(MouseEvent e) { - if (elements != null && state == State.COPY) { + if (elements != null && state == State.COPY && copyStartPosition != null && !copyStartPosition.equals(raster(getPosVector(e)))) { for (Moveable m : elements) { if (m instanceof Wire) circuit.add((Wire) m); if (m instanceof VisualElement) circuit.add((VisualElement) m); } - reset(); + copyStartPosition = null; } if (wasRealyDragged) reset(); diff --git a/src/main/java/de/neemann/digital/gui/draw/elements/Circuit.java b/src/main/java/de/neemann/digital/gui/draw/elements/Circuit.java index 791cf6980..ffc58023c 100644 --- a/src/main/java/de/neemann/digital/gui/draw/elements/Circuit.java +++ b/src/main/java/de/neemann/digital/gui/draw/elements/Circuit.java @@ -1,9 +1,21 @@ package de.neemann.digital.gui.draw.elements; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; +import com.thoughtworks.xstream.io.xml.StaxDriver; +import de.neemann.digital.core.ObservableValue; +import de.neemann.digital.core.Observer; +import de.neemann.digital.core.element.AttributeKey; +import de.neemann.digital.core.element.ElementAttributes; +import de.neemann.digital.core.element.ElementTypeDescription; +import de.neemann.digital.core.io.In; +import de.neemann.digital.core.io.Out; import de.neemann.digital.gui.draw.graphics.Graphic; import de.neemann.digital.gui.draw.graphics.Vector; +import de.neemann.digital.gui.draw.library.ElementLibrary; import de.neemann.digital.gui.draw.shapes.Drawable; +import java.io.*; import java.util.ArrayList; import java.util.Iterator; @@ -16,11 +28,44 @@ public class Circuit implements Drawable { private transient boolean dotsPresent = false; private transient boolean modified = false; + + private static XStream getxStream() { + XStream xStream = new XStream(new StaxDriver()); + xStream.alias("visualElement", VisualElement.class); + xStream.alias("wire", Wire.class); + xStream.alias("circuit", Circuit.class); + xStream.alias("vector", Vector.class); + xStream.alias("key", AttributeKey.class); + xStream.addImplicitCollection(ElementAttributes.class, "attributes"); + xStream.aliasAttribute(Vector.class, "x", "x"); + xStream.aliasAttribute(Vector.class, "y", "y"); + return xStream; + } + + public static Circuit loadCircuit(File filename) throws IOException { + XStream xStream = getxStream(); + try (InputStream in = new FileInputStream(filename)) { + return (Circuit) xStream.fromXML(in); + } + } + + public void save(File filename) throws IOException { + XStream xStream = Circuit.getxStream(); + try (Writer out = new OutputStreamWriter(new FileOutputStream(filename), "utf-8")) { + out.write("\n"); + xStream.marshal(this, new PrettyPrintWriter(out)); + modified = false; + } + } + + + public Circuit() { visualElements = new ArrayList<>(); wires = new ArrayList<>(); } + @Override public void drawTo(Graphic graphic) { if (!dotsPresent) { @@ -148,7 +193,44 @@ public class Circuit implements Drawable { return modified; } - public void saved() { - modified = false; + public String[] getInputNames(ElementLibrary library) throws PinException { + ArrayList pinList = new ArrayList<>(); + for (VisualElement ve : visualElements) { + ElementTypeDescription elementType = library.getElementType(ve.getElementName()); + if (elementType == In.DESCRIPTION) { + String name = ve.getElementAttributes().get(AttributeKey.Label); + if (name == null || name.length() == 0) + throw new PinException("pin without a name!"); + + pinList.add(name); + } + } + return pinList.toArray(new String[pinList.size()]); } + + public ObservableValue[] getOutputNames(ElementLibrary library) throws PinException { + ArrayList pinList = new ArrayList<>(); + for (VisualElement ve : visualElements) { + ElementTypeDescription elementType = library.getElementType(ve.getElementName()); + if (elementType == Out.DESCRIPTION) { + String name = ve.getElementAttributes().get(AttributeKey.Label); + if (name == null || name.length() == 0) + throw new PinException("pin without a name!"); + + pinList.add(new ObservableValue(name, 0) { + @Override + public long getValue() { + throw new RuntimeException("invallid call!"); + } + + @Override + public ObservableValue addObserver(Observer observer) { + throw new RuntimeException("invallid call!"); + } + }); + } + } + return pinList.toArray(new ObservableValue[pinList.size()]); + } + } diff --git a/src/main/java/de/neemann/digital/gui/draw/elements/Pins.java b/src/main/java/de/neemann/digital/gui/draw/elements/Pins.java index 935f71fab..2a7f503f9 100644 --- a/src/main/java/de/neemann/digital/gui/draw/elements/Pins.java +++ b/src/main/java/de/neemann/digital/gui/draw/elements/Pins.java @@ -35,7 +35,7 @@ public class Pins implements Iterable { return allPins.iterator(); } - public void setOutputs(ObservableValue[] outs) throws PinException { + public void bindOutputsToOutputPins(ObservableValue[] outs) throws PinException { for (ObservableValue o : outs) { Pin pin = outputs.get(o.getName()); if (pin == null) diff --git a/src/main/java/de/neemann/digital/gui/draw/library/CustomElement.java b/src/main/java/de/neemann/digital/gui/draw/library/CustomElement.java new file mode 100644 index 000000000..37062e00a --- /dev/null +++ b/src/main/java/de/neemann/digital/gui/draw/library/CustomElement.java @@ -0,0 +1,46 @@ +package de.neemann.digital.gui.draw.library; + +import de.neemann.digital.core.Model; +import de.neemann.digital.core.NodeException; +import de.neemann.digital.core.ObservableValue; +import de.neemann.digital.core.element.Element; +import de.neemann.digital.gui.draw.elements.Circuit; +import de.neemann.digital.gui.draw.elements.PinException; +import de.neemann.digital.gui.draw.model.ModelDescription; + +/** + * @author hneemann + */ +public class CustomElement implements Element { + + private Circuit circuit; + private ElementLibrary library; + + public CustomElement(Circuit circuit, ElementLibrary library) { + this.circuit = circuit; + this.library = library; + } + + public ModelDescription getModelDescription() throws PinException { + return new ModelDescription(circuit, library, true); + } + + @Override + public void setInputs(ObservableValue... inputs) throws NodeException { + throw new RuntimeException("invalid call!"); + } + + @Override + public ObservableValue[] getOutputs() { + try { + return circuit.getOutputNames(library); + } catch (PinException e) { + throw new RuntimeException(e); + } + } + + @Override + public void registerNodes(Model model) { + throw new RuntimeException("invalid call!"); + } +} diff --git a/src/main/java/de/neemann/digital/gui/draw/library/ElementLibrary.java b/src/main/java/de/neemann/digital/gui/draw/library/ElementLibrary.java index e42de83a2..2d70ce1a9 100644 --- a/src/main/java/de/neemann/digital/gui/draw/library/ElementLibrary.java +++ b/src/main/java/de/neemann/digital/gui/draw/library/ElementLibrary.java @@ -23,10 +23,11 @@ import java.util.Iterator; /** * @author hneemann */ -public class ElementLibrary implements Iterable { +public class ElementLibrary implements Iterable { private final HashMap map = new HashMap<>(); - private ArrayList list = new ArrayList<>(); + private ArrayList list = new ArrayList<>(); + private ElementNotFoundNotification elementNotFoundNotification; public ElementLibrary() { add(And.DESCRIPTION, "Logic"); @@ -58,32 +59,47 @@ public class ElementLibrary implements Iterable { } private void add(ElementTypeDescription description, String treePath) { + addDescription(description); + list.add(new ElementContainer(description.getName(), treePath)); + } + + public void addDescription(ElementTypeDescription description) { String name = description.getName(); if (map.containsKey(name)) throw new RuntimeException("duplicate element " + name); map.put(name, description); - - list.add(new PartContainer(name, treePath)); } public ElementTypeDescription getElementType(String elementName) { ElementTypeDescription pd = map.get(elementName); - if (pd == null) - throw new RuntimeException("element " + elementName + " not found"); + if (pd == null) { + if (elementNotFoundNotification != null) + pd = elementNotFoundNotification.notFound(elementName); + if (pd == null) + throw new RuntimeException("element " + elementName + " not found"); + } return pd; } + private ElementTypeDescription loadPart(String elementName) { + return null; + } + @Override - public Iterator iterator() { + public Iterator iterator() { return list.iterator(); } - public static class PartContainer { + public void setElementNotFoundNotification(ElementNotFoundNotification elementNotFoundNotification) { + this.elementNotFoundNotification = elementNotFoundNotification; + } + + public static class ElementContainer { private final String name; private final String treePath; - public PartContainer(String name, String treePath) { + public ElementContainer(String name, String treePath) { this.name = name; this.treePath = treePath; } diff --git a/src/main/java/de/neemann/digital/gui/draw/library/ElementNotFoundNotification.java b/src/main/java/de/neemann/digital/gui/draw/library/ElementNotFoundNotification.java new file mode 100644 index 000000000..d1b847ab7 --- /dev/null +++ b/src/main/java/de/neemann/digital/gui/draw/library/ElementNotFoundNotification.java @@ -0,0 +1,10 @@ +package de.neemann.digital.gui.draw.library; + +import de.neemann.digital.core.element.ElementTypeDescription; + +/** + * @author hneemann + */ +public interface ElementNotFoundNotification { + ElementTypeDescription notFound(String elementName); +} diff --git a/src/main/java/de/neemann/digital/gui/draw/model/ModelDescription.java b/src/main/java/de/neemann/digital/gui/draw/model/ModelDescription.java index 106021c8e..54e102769 100644 --- a/src/main/java/de/neemann/digital/gui/draw/model/ModelDescription.java +++ b/src/main/java/de/neemann/digital/gui/draw/model/ModelDescription.java @@ -2,9 +2,13 @@ package de.neemann.digital.gui.draw.model; import de.neemann.digital.core.*; import de.neemann.digital.core.Observer; +import de.neemann.digital.core.element.AttributeKey; import de.neemann.digital.core.element.Element; import de.neemann.digital.core.element.ElementTypeDescription; +import de.neemann.digital.core.io.In; +import de.neemann.digital.core.io.Out; import de.neemann.digital.gui.draw.elements.*; +import de.neemann.digital.gui.draw.library.CustomElement; import de.neemann.digital.gui.draw.library.ElementLibrary; import java.util.*; @@ -16,44 +20,119 @@ public class ModelDescription implements Iterable { private final NetList netList; private final ArrayList entries; + private final HashMap ioMap; private HashMap map; /** * Creates the ModelDescription. - * After the the NetList is complete, so all pins connected together are registered - * to the Net instances in the NetList. Evenry group of connected Pins is represented - * by a Net-instance in the NetList. + * In created the NetList is complete, so all pins connected together are registered + * to the Net instances in the NetList. Every group of connected Pins is represented + * by a Net instance in the NetList. * * @param circuit the circuit - * @param library the library + * @param library the library used to create the Element instances * @throws PinException */ public ModelDescription(Circuit circuit, ElementLibrary library) throws PinException { + this(circuit, library, false); + } + + public ModelDescription(Circuit circuit, ElementLibrary library, boolean readAsCustom) throws PinException { entries = new ArrayList<>(); netList = new NetList(circuit.getWires()); + if (readAsCustom) + ioMap = new HashMap<>(); + else + ioMap = null; + for (VisualElement vp : circuit.getElements()) { Pins pins = vp.getPins(); ElementTypeDescription elementType = library.getElementType(vp.getElementName()); Element element = elementType.createElement(vp.getElementAttributes()); - pins.setOutputs(element.getOutputs()); + pins.bindOutputsToOutputPins(element.getOutputs()); + + + // if handled as nested element, don't put pins in EntryList, but put pin in separate map to connect it with parent! + boolean isNotAIO = true; + if (readAsCustom) { + if (elementType == In.DESCRIPTION || elementType == Out.DESCRIPTION) { + String label = vp.getElementAttributes().get(AttributeKey.Label); + if (label == null || label.length() == 0) + throw new PinException("no pin name given!"); + if (pins.size() != 1) + throw new PinException(label + " is not a regular input or output!"); + + ioMap.put(label, pins.get(0)); + isNotAIO = false; + } + } + + if (isNotAIO) + entries.add(new ModelEntry(element, pins, vp, elementType.getInputNames(vp.getElementAttributes()))); - entries.add(new ModelEntry(element, pins, vp, elementType.getInputNames(vp.getElementAttributes()))); for (Pin p : pins) netList.add(p); + } + + + ArrayList cmdl = new ArrayList<>(); + Iterator it = entries.iterator(); + while (it.hasNext()) { + ModelEntry me = it.next(); + if (me.getElement() instanceof CustomElement) { + CustomElement ce = (CustomElement) me.getElement(); + ModelDescription child = ce.getModelDescription(); + cmdl.add(child); + + for (Pin p : me.getPins()) { + Net childNet = child.getNetOfIOandRemove(p.getName()); + Net thisNet = netList.getNetOfPin(p); + + // Disconnect the parents net from the pin + thisNet.removePin(p); + // and connect it to the nested inner net! + thisNet.addAll(childNet.getPins()); + // remove connecte net form child + child.remove(childNet); + } + it.remove(); + } + } + for (ModelDescription md : cmdl) { + entries.addAll(md.entries); + netList.add(md.netList); + } + } + + private void remove(Net childNet) { + netList.remove(childNet); + } + + private Net getNetOfIOandRemove(String name) throws PinException { + Pin pin = ioMap.get(name); + if (pin == null) + throw new PinException("pin " + name + " not found!"); + Net netOfPin = netList.getNetOfPin(pin); + if (netOfPin == null) + throw new PinException("net of pin " + name + " not found!"); + + netOfPin.removePin(pin); + + return netOfPin; } /** * Creates the model * + * @param bindWiresToValues * @return the model * @throws PinException * @throws NodeException - * @param connectWires */ - public Model createModel(boolean connectWires) throws PinException, NodeException { + public Model createModel(boolean bindWiresToValues) throws PinException, NodeException { for (Net n : netList) - n.interconnect(connectWires); + n.interconnect(bindWiresToValues); Model m = new Model(); diff --git a/src/main/java/de/neemann/digital/gui/draw/model/Net.java b/src/main/java/de/neemann/digital/gui/draw/model/Net.java index d72ad6fa7..88309badf 100644 --- a/src/main/java/de/neemann/digital/gui/draw/model/Net.java +++ b/src/main/java/de/neemann/digital/gui/draw/model/Net.java @@ -7,6 +7,7 @@ import de.neemann.digital.gui.draw.elements.Wire; import de.neemann.digital.gui.draw.graphics.Vector; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; /** @@ -58,7 +59,11 @@ public class Net { pins.add(pin); } - public void interconnect(boolean connectWires) throws PinException { + public void addAll(Collection p) { + pins.addAll(p); + } + + public void interconnect(boolean bindWiresToValues) throws PinException { ArrayList inputs = new ArrayList<>(); ArrayList outputs = new ArrayList<>(); for (Pin p : pins) { @@ -81,7 +86,7 @@ public class Net { for (Pin i : inputs) i.setValue(value); - if (connectWires) + if (bindWiresToValues) for (Wire w : wires) w.setValue(value); } @@ -97,4 +102,17 @@ public class Net { return true; return false; } + + public boolean containsPin(Pin p) { + return pins.contains(p); + } + + public ArrayList getPins() { + return pins; + } + + public void removePin(Pin p) throws PinException { + if (!pins.remove(p)) + throw new PinException("pin not present!", this); + } } diff --git a/src/main/java/de/neemann/digital/gui/draw/model/NetList.java b/src/main/java/de/neemann/digital/gui/draw/model/NetList.java index c81f5951f..8d711df4f 100644 --- a/src/main/java/de/neemann/digital/gui/draw/model/NetList.java +++ b/src/main/java/de/neemann/digital/gui/draw/model/NetList.java @@ -21,6 +21,10 @@ public class NetList implements Iterable { add(w); } + public void add(NetList netList) { + this.netList.addAll(netList.netList); + } + public void add(Pin pin) { for (Net net : netList) if (net.contains(pin.getPos())) @@ -58,4 +62,15 @@ public class NetList implements Iterable { public Iterator iterator() { return netList.iterator(); } + + public Net getNetOfPin(Pin p) { + for (Net n : netList) + if (n.containsPin(p)) + return n; + return null; + } + + public void remove(Net childNet) { + netList.remove(childNet); + } }