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);
+ }
}