mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-26 14:31:02 -04:00
refactoring of library system to allow separate component tree view
This commit is contained in:
parent
84b16602de
commit
6dc25b04ea
@ -122,7 +122,7 @@ Single-Cycle CPU.</string>
|
||||
<boolean>true</boolean>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="1220" y="40"/>
|
||||
<pos x="1180" y="40"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Branch.dig</elementName>
|
||||
@ -188,6 +188,10 @@ Single-Cycle CPU.</string>
|
||||
<visualElement>
|
||||
<elementName>Driver</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>rotation</string>
|
||||
<rotation rotation="1"/>
|
||||
</entry>
|
||||
<entry>
|
||||
<string>Bits</string>
|
||||
<int>16</int>
|
||||
@ -197,12 +201,12 @@ Single-Cycle CPU.</string>
|
||||
<boolean>true</boolean>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="520" y="120"/>
|
||||
<pos x="520" y="40"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>PC.dig</elementName>
|
||||
<elementAttributes/>
|
||||
<pos x="360" y="120"/>
|
||||
<pos x="400" y="120"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Clock</elementName>
|
||||
@ -477,16 +481,12 @@ Single-Cycle CPU.</string>
|
||||
<visualElement>
|
||||
<elementName>Tunnel</elementName>
|
||||
<elementAttributes>
|
||||
<entry>
|
||||
<string>rotation</string>
|
||||
<rotation rotation="3"/>
|
||||
</entry>
|
||||
<entry>
|
||||
<string>NetName</string>
|
||||
<string>stPC</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="520" y="160"/>
|
||||
<pos x="560" y="40"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Tunnel</elementName>
|
||||
@ -528,7 +528,7 @@ Single-Cycle CPU.</string>
|
||||
<string>abs</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="340" y="160"/>
|
||||
<pos x="380" y="160"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Tunnel</elementName>
|
||||
@ -576,7 +576,7 @@ Single-Cycle CPU.</string>
|
||||
<string>ALU2D</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="1260" y="40"/>
|
||||
<pos x="1220" y="40"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Tunnel</elementName>
|
||||
@ -662,7 +662,7 @@ Single-Cycle CPU.</string>
|
||||
<string>C</string>
|
||||
</entry>
|
||||
</elementAttributes>
|
||||
<pos x="340" y="140"/>
|
||||
<pos x="380" y="140"/>
|
||||
</visualElement>
|
||||
<visualElement>
|
||||
<elementName>Tunnel</elementName>
|
||||
@ -766,7 +766,7 @@ Single-Cycle CPU.</string>
|
||||
</visualElements>
|
||||
<wires>
|
||||
<wire>
|
||||
<p1 x="340" y="320"/>
|
||||
<p1 x="380" y="320"/>
|
||||
<p2 x="940" y="320"/>
|
||||
</wire>
|
||||
<wire>
|
||||
@ -782,16 +782,20 @@ Single-Cycle CPU.</string>
|
||||
<p2 x="1360" y="320"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="600" y="0"/>
|
||||
<p1 x="520" y="0"/>
|
||||
<p2 x="640" y="0"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="640" y="0"/>
|
||||
<p2 x="800" y="0"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1220" y="0"/>
|
||||
<p2 x="1440" y="0"/>
|
||||
<p1 x="800" y="0"/>
|
||||
<p2 x="1180" y="0"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="800" y="0"/>
|
||||
<p2 x="1220" y="0"/>
|
||||
<p1 x="1180" y="0"/>
|
||||
<p2 x="1440" y="0"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="740" y="480"/>
|
||||
@ -813,10 +817,6 @@ Single-Cycle CPU.</string>
|
||||
<p1 x="900" y="160"/>
|
||||
<p2 x="1080" y="160"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="160"/>
|
||||
<p2 x="360" y="160"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1160" y="160"/>
|
||||
<p2 x="1240" y="160"/>
|
||||
@ -829,6 +829,10 @@ Single-Cycle CPU.</string>
|
||||
<p1 x="540" y="160"/>
|
||||
<p2 x="660" y="160"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="160"/>
|
||||
<p2 x="400" y="160"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="640" y="420"/>
|
||||
<p2 x="660" y="420"/>
|
||||
@ -854,7 +858,7 @@ Single-Cycle CPU.</string>
|
||||
<p2 x="1240" y="360"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="320" y="360"/>
|
||||
<p1 x="340" y="360"/>
|
||||
<p2 x="360" y="360"/>
|
||||
</wire>
|
||||
<wire>
|
||||
@ -882,16 +886,20 @@ Single-Cycle CPU.</string>
|
||||
<p2 x="840" y="40"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1240" y="40"/>
|
||||
<p2 x="1260" y="40"/>
|
||||
<p1 x="1200" y="40"/>
|
||||
<p2 x="1220" y="40"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="880" y="460"/>
|
||||
<p2 x="900" y="460"/>
|
||||
<p1 x="540" y="40"/>
|
||||
<p2 x="560" y="40"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="820" y="460"/>
|
||||
<p2 x="840" y="460"/>
|
||||
<p1 x="380" y="140"/>
|
||||
<p2 x="400" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="500" y="140"/>
|
||||
<p2 x="520" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="880" y="140"/>
|
||||
@ -901,30 +909,30 @@ Single-Cycle CPU.</string>
|
||||
<p1 x="760" y="140"/>
|
||||
<p2 x="800" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="140"/>
|
||||
<p2 x="360" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="640" y="140"/>
|
||||
<p2 x="660" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="460" y="140"/>
|
||||
<p2 x="480" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1160" y="140"/>
|
||||
<p2 x="1220" y="140"/>
|
||||
<p2 x="1180" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1280" y="140"/>
|
||||
<p2 x="1360" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1220" y="140"/>
|
||||
<p1 x="1180" y="140"/>
|
||||
<p2 x="1280" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="880" y="460"/>
|
||||
<p2 x="900" y="460"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="820" y="460"/>
|
||||
<p2 x="840" y="460"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1000" y="300"/>
|
||||
<p2 x="1060" y="300"/>
|
||||
@ -933,6 +941,10 @@ Single-Cycle CPU.</string>
|
||||
<p1 x="1140" y="300"/>
|
||||
<p2 x="1160" y="300"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="240"/>
|
||||
<p2 x="520" y="240"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1340" y="400"/>
|
||||
<p2 x="1360" y="400"/>
|
||||
@ -954,12 +966,28 @@ Single-Cycle CPU.</string>
|
||||
<p2 x="360" y="400"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="80"/>
|
||||
<p2 x="1220" y="80"/>
|
||||
<p1 x="380" y="80"/>
|
||||
<p2 x="1180" y="80"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="320" y="240"/>
|
||||
<p2 x="480" y="240"/>
|
||||
<p1 x="380" y="180"/>
|
||||
<p2 x="400" y="180"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1420" y="180"/>
|
||||
<p2 x="1440" y="180"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1160" y="180"/>
|
||||
<p2 x="1220" y="180"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1060" y="180"/>
|
||||
<p2 x="1080" y="180"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="560" y="180"/>
|
||||
<p2 x="660" y="180"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1340" y="340"/>
|
||||
@ -978,24 +1006,20 @@ Single-Cycle CPU.</string>
|
||||
<p2 x="840" y="500"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1420" y="180"/>
|
||||
<p2 x="1440" y="180"/>
|
||||
<p1 x="500" y="120"/>
|
||||
<p2 x="520" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="180"/>
|
||||
<p2 x="360" y="180"/>
|
||||
<p1 x="380" y="120"/>
|
||||
<p2 x="400" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1160" y="180"/>
|
||||
<p2 x="1220" y="180"/>
|
||||
<p1 x="760" y="120"/>
|
||||
<p2 x="840" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1060" y="180"/>
|
||||
<p2 x="1080" y="180"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="560" y="180"/>
|
||||
<p2 x="660" y="180"/>
|
||||
<p1 x="640" y="120"/>
|
||||
<p2 x="660" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="500" y="440"/>
|
||||
@ -1013,26 +1037,6 @@ Single-Cycle CPU.</string>
|
||||
<p1 x="1000" y="280"/>
|
||||
<p2 x="1020" y="280"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="540" y="120"/>
|
||||
<p2 x="600" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="760" y="120"/>
|
||||
<p2 x="840" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="460" y="120"/>
|
||||
<p2 x="500" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="120"/>
|
||||
<p2 x="360" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="600" y="120"/>
|
||||
<p2 x="660" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1340" y="380"/>
|
||||
<p2 x="1360" y="380"/>
|
||||
@ -1066,8 +1070,8 @@ Single-Cycle CPU.</string>
|
||||
<p2 x="1280" y="320"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="320" y="240"/>
|
||||
<p2 x="320" y="360"/>
|
||||
<p1 x="640" y="0"/>
|
||||
<p2 x="640" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="580" y="380"/>
|
||||
@ -1081,25 +1085,21 @@ Single-Cycle CPU.</string>
|
||||
<p1 x="900" y="160"/>
|
||||
<p2 x="900" y="460"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1220" y="60"/>
|
||||
<p2 x="1220" y="80"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1220" y="0"/>
|
||||
<p2 x="1220" y="20"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1220" y="180"/>
|
||||
<p2 x="1220" y="340"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1220" y="80"/>
|
||||
<p2 x="1220" y="140"/>
|
||||
<p1 x="520" y="140"/>
|
||||
<p2 x="520" y="240"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="520" y="140"/>
|
||||
<p2 x="520" y="160"/>
|
||||
<p1 x="520" y="60"/>
|
||||
<p2 x="520" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="520" y="0"/>
|
||||
<p2 x="520" y="20"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="520" y="600"/>
|
||||
@ -1118,21 +1118,13 @@ Single-Cycle CPU.</string>
|
||||
<p2 x="400" y="620"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="180"/>
|
||||
<p2 x="340" y="320"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="80"/>
|
||||
<p2 x="340" y="120"/>
|
||||
<p1 x="340" y="240"/>
|
||||
<p2 x="340" y="360"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="340" y="600"/>
|
||||
<p2 x="340" y="620"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="600" y="0"/>
|
||||
<p2 x="600" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="600" y="600"/>
|
||||
<p2 x="600" y="620"/>
|
||||
@ -1141,6 +1133,18 @@ Single-Cycle CPU.</string>
|
||||
<p1 x="1240" y="160"/>
|
||||
<p2 x="1240" y="360"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1180" y="60"/>
|
||||
<p2 x="1180" y="80"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1180" y="0"/>
|
||||
<p2 x="1180" y="20"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="1180" y="80"/>
|
||||
<p2 x="1180" y="140"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="540" y="160"/>
|
||||
<p2 x="540" y="380"/>
|
||||
@ -1165,10 +1169,6 @@ Single-Cycle CPU.</string>
|
||||
<p1 x="1440" y="180"/>
|
||||
<p2 x="1440" y="360"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="480" y="140"/>
|
||||
<p2 x="480" y="240"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="480" y="600"/>
|
||||
<p2 x="480" y="620"/>
|
||||
@ -1233,6 +1233,14 @@ Single-Cycle CPU.</string>
|
||||
<p1 x="440" y="600"/>
|
||||
<p2 x="440" y="620"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="180"/>
|
||||
<p2 x="380" y="320"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="80"/>
|
||||
<p2 x="380" y="120"/>
|
||||
</wire>
|
||||
<wire>
|
||||
<p1 x="380" y="600"/>
|
||||
<p2 x="380" y="620"/>
|
||||
|
@ -0,0 +1,20 @@
|
||||
package de.neemann.digital.draw.library;
|
||||
|
||||
import de.neemann.digital.core.element.ElementTypeDescription;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Used for lazy loading of the circuits
|
||||
* Created by hneemann on 25.03.17.
|
||||
*/
|
||||
public interface DescriptionCreator {
|
||||
/**
|
||||
* Is called if the description is needed in the circuit.
|
||||
* Is not called to create the menus
|
||||
*
|
||||
* @return the description
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
ElementTypeDescription createDescription() throws IOException;
|
||||
}
|
@ -3,7 +3,7 @@ package de.neemann.digital.draw.library;
|
||||
import de.neemann.digital.core.arithmetic.*;
|
||||
import de.neemann.digital.core.arithmetic.Comparator;
|
||||
import de.neemann.digital.core.basic.*;
|
||||
import de.neemann.digital.core.element.ElementTypeDescription;
|
||||
import de.neemann.digital.core.element.*;
|
||||
import de.neemann.digital.core.flipflops.FlipflopD;
|
||||
import de.neemann.digital.core.flipflops.FlipflopJK;
|
||||
import de.neemann.digital.core.flipflops.FlipflopRS;
|
||||
@ -19,13 +19,18 @@ import de.neemann.digital.core.switching.PFET;
|
||||
import de.neemann.digital.core.switching.Relay;
|
||||
import de.neemann.digital.core.switching.Switch;
|
||||
import de.neemann.digital.core.wiring.*;
|
||||
import de.neemann.digital.draw.elements.Circuit;
|
||||
import de.neemann.digital.draw.elements.PinException;
|
||||
import de.neemann.digital.draw.elements.Tunnel;
|
||||
import de.neemann.digital.draw.shapes.ShapeFactory;
|
||||
import de.neemann.digital.gui.components.data.DummyElement;
|
||||
import de.neemann.digital.gui.components.graphics.GraphicCard;
|
||||
import de.neemann.digital.gui.components.terminal.Keyboard;
|
||||
import de.neemann.digital.gui.components.terminal.Terminal;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.digital.testing.TestCaseElement;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -35,110 +40,146 @@ import java.util.*;
|
||||
* @author hneemann
|
||||
*/
|
||||
public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ElementLibrary.class);
|
||||
|
||||
private final HashMap<String, ElementTypeDescription> map = new HashMap<>();
|
||||
private ArrayList<ElementContainer> list = new ArrayList<>();
|
||||
private ElementNotFoundNotification elementNotFoundNotification;
|
||||
private final HashMap<String, LibraryNode> map = new HashMap<>();
|
||||
private final ArrayList<LibraryListener> listeners = new ArrayList<>();
|
||||
private final LibraryNode root;
|
||||
private ShapeFactory shapeFactory;
|
||||
private LibraryNode customNode;
|
||||
private File rootLibraryPath;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public ElementLibrary() {
|
||||
String menu = Lang.get("lib_Logic");
|
||||
add(And.DESCRIPTION, menu);
|
||||
add(NAnd.DESCRIPTION, menu);
|
||||
add(Or.DESCRIPTION, menu);
|
||||
add(NOr.DESCRIPTION, menu);
|
||||
add(XOr.DESCRIPTION, menu);
|
||||
add(XNOr.DESCRIPTION, menu);
|
||||
add(Not.DESCRIPTION, menu);
|
||||
add(LookUpTable.DESCRIPTION, menu);
|
||||
add(Delay.DESCRIPTION, menu);
|
||||
root = new LibraryNode("root");
|
||||
|
||||
menu = Lang.get("lib_io");
|
||||
add(Out.DESCRIPTION, menu);
|
||||
add(Out.LEDDESCRIPTION, menu);
|
||||
add(In.DESCRIPTION, menu);
|
||||
add(Clock.DESCRIPTION, menu);
|
||||
add(Button.DESCRIPTION, menu);
|
||||
add(Probe.DESCRIPTION, menu);
|
||||
add(Out.SEVENDESCRIPTION, menu);
|
||||
add(Out.SEVENHEXDESCRIPTION, menu);
|
||||
add(DummyElement.DATADESCRIPTION, menu);
|
||||
add(DummyElement.TEXTDESCRIPTION, menu);
|
||||
add(Keyboard.DESCRIPTION, menu);
|
||||
add(Terminal.DESCRIPTION, menu);
|
||||
LibraryNode node = new LibraryNode(Lang.get("lib_Logic"));
|
||||
node.add(And.DESCRIPTION);
|
||||
node.add(NAnd.DESCRIPTION);
|
||||
node.add(Or.DESCRIPTION);
|
||||
node.add(NOr.DESCRIPTION);
|
||||
node.add(XOr.DESCRIPTION);
|
||||
node.add(XNOr.DESCRIPTION);
|
||||
node.add(Not.DESCRIPTION);
|
||||
node.add(LookUpTable.DESCRIPTION);
|
||||
node.add(Delay.DESCRIPTION);
|
||||
root.add(node);
|
||||
|
||||
menu = Lang.get("lib_wires");
|
||||
add(Const.DESCRIPTION, menu);
|
||||
add(Ground.DESCRIPTION, menu);
|
||||
add(VDD.DESCRIPTION, menu);
|
||||
add(Tunnel.DESCRIPTION, menu);
|
||||
add(Splitter.DESCRIPTION, menu);
|
||||
add(PullUp.DESCRIPTION, menu);
|
||||
add(PullDown.DESCRIPTION, menu);
|
||||
add(Driver.DESCRIPTION, menu);
|
||||
add(DriverInvSel.DESCRIPTION, menu);
|
||||
node = new LibraryNode(Lang.get("lib_io"));
|
||||
node.add(Out.DESCRIPTION);
|
||||
node.add(Out.LEDDESCRIPTION);
|
||||
node.add(In.DESCRIPTION);
|
||||
node.add(Clock.DESCRIPTION);
|
||||
node.add(Button.DESCRIPTION);
|
||||
node.add(Probe.DESCRIPTION);
|
||||
node.add(Out.SEVENDESCRIPTION);
|
||||
node.add(Out.SEVENHEXDESCRIPTION);
|
||||
node.add(DummyElement.DATADESCRIPTION);
|
||||
node.add(DummyElement.TEXTDESCRIPTION);
|
||||
node.add(Keyboard.DESCRIPTION);
|
||||
node.add(Terminal.DESCRIPTION);
|
||||
root.add(node);
|
||||
|
||||
menu = Lang.get("lib_mux");
|
||||
add(Multiplexer.DESCRIPTION, menu);
|
||||
add(Demultiplexer.DESCRIPTION, menu);
|
||||
add(Decoder.DESCRIPTION, menu);
|
||||
node = new LibraryNode(Lang.get("lib_wires"));
|
||||
node.add(Const.DESCRIPTION);
|
||||
node.add(Ground.DESCRIPTION);
|
||||
node.add(VDD.DESCRIPTION);
|
||||
node.add(Tunnel.DESCRIPTION);
|
||||
node.add(Splitter.DESCRIPTION);
|
||||
node.add(PullUp.DESCRIPTION);
|
||||
node.add(PullDown.DESCRIPTION);
|
||||
node.add(Driver.DESCRIPTION);
|
||||
node.add(DriverInvSel.DESCRIPTION);
|
||||
root.add(node);
|
||||
|
||||
menu = Lang.get("lib_flipFlops");
|
||||
add(FlipflopRS.DESCRIPTION, menu);
|
||||
add(FlipflopJK.DESCRIPTION, menu);
|
||||
add(FlipflopD.DESCRIPTION, menu);
|
||||
add(FlipflopT.DESCRIPTION, menu);
|
||||
node = new LibraryNode(Lang.get("lib_mux"));
|
||||
node.add(Multiplexer.DESCRIPTION);
|
||||
node.add(Demultiplexer.DESCRIPTION);
|
||||
node.add(Decoder.DESCRIPTION);
|
||||
root.add(node);
|
||||
|
||||
menu = Lang.get("lib_memory");
|
||||
add(Register.DESCRIPTION, menu);
|
||||
add(ROM.DESCRIPTION, menu);
|
||||
add(RAMDualPort.DESCRIPTION, menu);
|
||||
add(RAMSinglePort.DESCRIPTION, menu);
|
||||
add(RAMSinglePortSel.DESCRIPTION, menu);
|
||||
add(GraphicCard.DESCRIPTION, menu);
|
||||
add(Counter.DESCRIPTION, menu);
|
||||
node = new LibraryNode(Lang.get("lib_flipFlops"));
|
||||
node.add(FlipflopRS.DESCRIPTION);
|
||||
node.add(FlipflopJK.DESCRIPTION);
|
||||
node.add(FlipflopD.DESCRIPTION);
|
||||
node.add(FlipflopT.DESCRIPTION);
|
||||
root.add(node);
|
||||
|
||||
menu = Lang.get("lib_arithmetic");
|
||||
add(Add.DESCRIPTION, menu);
|
||||
add(Sub.DESCRIPTION, menu);
|
||||
add(Mul.DESCRIPTION, menu);
|
||||
add(Comparator.DESCRIPTION, menu);
|
||||
add(Neg.DESCRIPTION, menu);
|
||||
add(BitCount.DESCRIPTION, menu);
|
||||
node = new LibraryNode(Lang.get("lib_memory"));
|
||||
node.add(Register.DESCRIPTION);
|
||||
node.add(ROM.DESCRIPTION);
|
||||
node.add(RAMDualPort.DESCRIPTION);
|
||||
node.add(RAMSinglePort.DESCRIPTION);
|
||||
node.add(RAMSinglePortSel.DESCRIPTION);
|
||||
node.add(GraphicCard.DESCRIPTION);
|
||||
node.add(Counter.DESCRIPTION);
|
||||
root.add(node);
|
||||
|
||||
menu = Lang.get("lib_cplx");
|
||||
node = new LibraryNode(Lang.get("lib_arithmetic"));
|
||||
node.add(Add.DESCRIPTION);
|
||||
node.add(Sub.DESCRIPTION);
|
||||
node.add(Mul.DESCRIPTION);
|
||||
node.add(Comparator.DESCRIPTION);
|
||||
node.add(Neg.DESCRIPTION);
|
||||
node.add(BitCount.DESCRIPTION);
|
||||
root.add(node);
|
||||
|
||||
node = new LibraryNode(Lang.get("lib_cplx"));
|
||||
// add(Diode.DESCRIPTION, menu); // see class DiodeTest for further information
|
||||
add(DiodeForeward.DESCRIPTION, menu);
|
||||
add(DiodeBackward.DESCRIPTION, menu);
|
||||
add(Switch.DESCRIPTION, menu);
|
||||
add(Relay.DESCRIPTION, menu);
|
||||
add(NFET.DESCRIPTION, menu);
|
||||
add(PFET.DESCRIPTION, menu);
|
||||
add(Reset.DESCRIPTION, menu);
|
||||
add(Break.DESCRIPTION, menu);
|
||||
node.add(DiodeForeward.DESCRIPTION);
|
||||
node.add(DiodeBackward.DESCRIPTION);
|
||||
node.add(Switch.DESCRIPTION);
|
||||
node.add(Relay.DESCRIPTION);
|
||||
node.add(NFET.DESCRIPTION);
|
||||
node.add(PFET.DESCRIPTION);
|
||||
node.add(Reset.DESCRIPTION);
|
||||
node.add(Break.DESCRIPTION);
|
||||
root.add(node);
|
||||
|
||||
menu = Lang.get("lib_test");
|
||||
add(TestCaseElement.TESTCASEDESCRIPTION, menu);
|
||||
}
|
||||
node = new LibraryNode(Lang.get("lib_test"));
|
||||
node.add(TestCaseElement.TESTCASEDESCRIPTION);
|
||||
root.add(node);
|
||||
|
||||
private void add(ElementTypeDescription description, String treePath) {
|
||||
String name = description.getName();
|
||||
map.put(name, description);
|
||||
list.add(new ElementContainer(description, treePath));
|
||||
populateNodeMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a description to the library
|
||||
* Sets the shape factory used to import sub circuits
|
||||
*
|
||||
* @param description the description
|
||||
* @param file the file which was loaded
|
||||
* @param shapeFactory the shape factory
|
||||
*/
|
||||
public void addDescription(ElementTypeDescription description, File file) {
|
||||
map.put(file.getName(), description);
|
||||
public void setShapeFactory(ShapeFactory shapeFactory) {
|
||||
this.shapeFactory = shapeFactory;
|
||||
}
|
||||
|
||||
private void populateNodeMap() {
|
||||
map.clear();
|
||||
root.traverse(libraryNode -> {
|
||||
if (libraryNode.isLeaf()) {
|
||||
map.put(libraryNode.getName(), libraryNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the root library path
|
||||
*
|
||||
* @param rootLibraryPath the path
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void setFilePath(File rootLibraryPath) throws IOException {
|
||||
if (rootLibraryPath == null) {
|
||||
if (this.rootLibraryPath != null) {
|
||||
this.rootLibraryPath = null;
|
||||
rescanFolder();
|
||||
}
|
||||
} else if (!rootLibraryPath.equals(this.rootLibraryPath)) {
|
||||
this.rootLibraryPath = rootLibraryPath;
|
||||
rescanFolder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ElementTypeDescription} by a given name.
|
||||
@ -149,60 +190,123 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
|
||||
* @throws ElementNotFoundException ElementNotFoundException
|
||||
*/
|
||||
public ElementTypeDescription getElementType(String elementName) throws ElementNotFoundException {
|
||||
ElementTypeDescription description = map.get(elementName);
|
||||
if (description != null)
|
||||
return description;
|
||||
try {
|
||||
LibraryNode description = map.get(elementName);
|
||||
if (description != null)
|
||||
return description.getDescription();
|
||||
|
||||
elementName = elementName.replace("\\", "/"); // effects only some old files!
|
||||
|
||||
File file = new File(elementName);
|
||||
|
||||
description = map.get(file.getName());
|
||||
if (description != null)
|
||||
return description;
|
||||
|
||||
if (elementNotFoundNotification != null)
|
||||
try {
|
||||
description = elementNotFoundNotification.elementNotFound(file);
|
||||
} catch (IOException e) {
|
||||
throw new ElementNotFoundException(Lang.get("msg_errorImportingModel", elementName), e);
|
||||
// effects only some old files!
|
||||
elementName = elementName.replace("\\", "/");
|
||||
if (elementName.contains("/")) {
|
||||
elementName = new File(elementName).getName();
|
||||
}
|
||||
|
||||
if (description != null)
|
||||
return description;
|
||||
description = map.get(elementName);
|
||||
if (description != null)
|
||||
return description.getDescription();
|
||||
|
||||
if (rootLibraryPath == null)
|
||||
throw new RuntimeException("no root path set");
|
||||
|
||||
rescanFolder();
|
||||
|
||||
description = map.get(elementName);
|
||||
if (description != null)
|
||||
return description.getDescription();
|
||||
} catch (IOException e) {
|
||||
throw new ElementNotFoundException(Lang.get("msg_errorImportingModel"), e);
|
||||
}
|
||||
|
||||
throw new ElementNotFoundException(Lang.get("err_element_N_notFound", elementName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ElementContainer> iterator() {
|
||||
HashSet<String> baseElements = new HashSet<>();
|
||||
for (ElementContainer ec : list) {
|
||||
baseElements.add(ec.getDescription().getName());
|
||||
}
|
||||
ArrayList<ElementContainer> custom = new ArrayList<>();
|
||||
for (Map.Entry<String, ElementTypeDescription> entry : map.entrySet()) {
|
||||
if (!baseElements.contains(entry.getValue().getName())) {
|
||||
custom.add(new ElementContainer(entry.getValue(), Lang.get("menu_custom")));
|
||||
}
|
||||
}
|
||||
private void rescanFolder() {
|
||||
LOGGER.debug("rescan folder");
|
||||
if (customNode == null) {
|
||||
customNode = new LibraryNode(Lang.get("menu_custom"));
|
||||
root.add(customNode);
|
||||
} else customNode.removeAll();
|
||||
|
||||
if (custom.isEmpty())
|
||||
return list.iterator();
|
||||
else {
|
||||
Collections.sort(custom, (c1, c2) -> c1.getDescription().getTranslatedName().compareToIgnoreCase(c2.getDescription().getTranslatedName()));
|
||||
custom.addAll(list);
|
||||
return custom.iterator();
|
||||
if (rootLibraryPath != null)
|
||||
scanFolder(rootLibraryPath, customNode);
|
||||
|
||||
populateNodeMap();
|
||||
|
||||
fireLibraryChanged();
|
||||
}
|
||||
|
||||
private void fireLibraryChanged() {
|
||||
for (LibraryListener l : listeners)
|
||||
l.libraryChanged();
|
||||
}
|
||||
|
||||
private void scanFolder(File path, LibraryNode node) {
|
||||
File[] list = path.listFiles();
|
||||
if (list != null) {
|
||||
ArrayList<File> orderedList = new ArrayList<>(Arrays.asList(list));
|
||||
orderedList.sort((f1, f2) -> f1.getName().compareToIgnoreCase(f2.getName()));
|
||||
for (File f : orderedList) {
|
||||
if (f.isDirectory()) {
|
||||
LibraryNode n = new LibraryNode(f.getName());
|
||||
scanFolder(f, n);
|
||||
if (!n.isEmpty())
|
||||
node.add(n);
|
||||
}
|
||||
}
|
||||
for (File f : orderedList) {
|
||||
final String name = f.getName();
|
||||
if (f.isFile() && name.endsWith(".dig"))
|
||||
node.add(importElement(f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setes the {@link ElementNotFoundNotification} which can be calle if a element is not present.
|
||||
* Adds a listener to this library
|
||||
*
|
||||
* @param elementNotFoundNotification elementNotFoundNotification
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public void setElementNotFoundNotification(ElementNotFoundNotification elementNotFoundNotification) {
|
||||
this.elementNotFoundNotification = elementNotFoundNotification;
|
||||
public void addListener(LibraryListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from this library
|
||||
*
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeListener(LibraryListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<ElementContainer> iterator() {
|
||||
ArrayList<ElementContainer> nodes = new ArrayList<>();
|
||||
for (LibraryNode n : getRoot())
|
||||
addToList(nodes, n, "");
|
||||
return nodes.iterator();
|
||||
}
|
||||
|
||||
private void addToList(ArrayList<ElementContainer> nodes, LibraryNode node, String path) {
|
||||
if (node.isLeaf()) {
|
||||
if (node.isDescriptionLoaded()) {
|
||||
try {
|
||||
nodes.add(new ElementContainer(node.getDescription(), path));
|
||||
} catch (IOException e) {
|
||||
// can not happen because description is present!
|
||||
}
|
||||
}
|
||||
} else
|
||||
for (LibraryNode n : node)
|
||||
addToList(nodes, n, concat(path, node.getName()));
|
||||
}
|
||||
|
||||
private String concat(String path, String name) {
|
||||
if (path.length() == 0)
|
||||
return name;
|
||||
return path + " - " + name;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,6 +318,120 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
|
||||
map.remove(name.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all entries
|
||||
*
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public void updateEntries() throws IOException {
|
||||
rescanFolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the root element
|
||||
*/
|
||||
public LibraryNode getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
private LibraryNode importElement(File file) {
|
||||
return new LibraryNode(file.getName(), () -> {
|
||||
try {
|
||||
LOGGER.debug("load element " + file);
|
||||
Circuit circuit = Circuit.loadCircuit(file, shapeFactory);
|
||||
ElementTypeDescriptionCustom description =
|
||||
new ElementTypeDescriptionCustom(file,
|
||||
attributes -> new CustomElement(circuit, ElementLibrary.this, file),
|
||||
circuit.getAttributes(), circuit.getInputNames());
|
||||
description.setShortName(createShortName(file));
|
||||
|
||||
String descriptionText = circuit.getAttributes().get(Keys.DESCRIPTION);
|
||||
if (descriptionText != null && descriptionText.length() > 0) {
|
||||
description.setDescription(descriptionText);
|
||||
}
|
||||
return description;
|
||||
} catch (PinException e) {
|
||||
throw new IOException(Lang.get("msg_errorImportingModel"), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String createShortName(File file) {
|
||||
return createShortName(file.getName());
|
||||
}
|
||||
|
||||
private String createShortName(String name) {
|
||||
if (name.endsWith(".dig")) return name.substring(0, name.length() - 4);
|
||||
|
||||
String transName = Lang.getNull("elem_" + name);
|
||||
if (transName == null)
|
||||
return name;
|
||||
else
|
||||
return transName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The description of a nested element.
|
||||
* This is a complete circuit which is used as a element.
|
||||
*/
|
||||
public static class ElementTypeDescriptionCustom extends ElementTypeDescription {
|
||||
private final File file;
|
||||
private final ElementAttributes attributes;
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Creates a new element
|
||||
*
|
||||
* @param file the file which is loaded
|
||||
* @param elementFactory a element factory which is used to create concrete elements if needed
|
||||
* @param attributes the attributes of the element
|
||||
* @param inputNames the names of the input signals
|
||||
*/
|
||||
public ElementTypeDescriptionCustom(File file, ElementFactory elementFactory, ElementAttributes attributes, PinDescription... inputNames) {
|
||||
super(file.getName(), elementFactory, inputNames);
|
||||
this.file = file;
|
||||
this.attributes = attributes;
|
||||
setShortName(file.getName());
|
||||
addAttribute(Keys.ROTATE);
|
||||
addAttribute(Keys.LABEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename
|
||||
* the retuned file is opened if the user wants to modify the element
|
||||
*
|
||||
* @return the filename
|
||||
*/
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the elements attributes
|
||||
*/
|
||||
public ElementAttributes getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom description for this field
|
||||
*
|
||||
* @param description the description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(ElementAttributes elementAttributes) {
|
||||
if (description != null)
|
||||
return description;
|
||||
else
|
||||
return super.getDescription(elementAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used to store a elements name and its position in the elements menu.
|
||||
*/
|
||||
@ -227,7 +445,7 @@ public class ElementLibrary implements Iterable<ElementLibrary.ElementContainer>
|
||||
* @param typeDescription the elements typeDescription
|
||||
* @param treePath the elements menu path
|
||||
*/
|
||||
public ElementContainer(ElementTypeDescription typeDescription, String treePath) {
|
||||
ElementContainer(ElementTypeDescription typeDescription, String treePath) {
|
||||
this.name = typeDescription;
|
||||
this.treePath = treePath;
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package de.neemann.digital.draw.library;
|
||||
|
||||
/**
|
||||
* Listener to notify library uses if the library changes
|
||||
* Created by hneemann on 25.03.17.
|
||||
*/
|
||||
public interface LibraryListener {
|
||||
|
||||
/**
|
||||
* called if library changes
|
||||
*/
|
||||
void libraryChanged();
|
||||
}
|
159
src/main/java/de/neemann/digital/draw/library/LibraryNode.java
Normal file
159
src/main/java/de/neemann/digital/draw/library/LibraryNode.java
Normal file
@ -0,0 +1,159 @@
|
||||
package de.neemann.digital.draw.library;
|
||||
|
||||
import de.neemann.digital.core.element.ElementTypeDescription;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* A node in the components library
|
||||
* Created by hneemann on 25.03.17.
|
||||
*/
|
||||
public class LibraryNode implements Iterable<LibraryNode> {
|
||||
|
||||
private final ArrayList<LibraryNode> children;
|
||||
private final String translatedName;
|
||||
private final String name;
|
||||
private final DescriptionCreator creator;
|
||||
private ElementTypeDescription description;
|
||||
|
||||
/**
|
||||
* Creates a new node with the given name.
|
||||
* The node can have children
|
||||
*
|
||||
* @param name name of the node
|
||||
*/
|
||||
LibraryNode(String name) {
|
||||
this.name = name;
|
||||
this.translatedName = name;
|
||||
this.children = new ArrayList<>();
|
||||
this.description = null;
|
||||
this.creator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new leaf
|
||||
*
|
||||
* @param description the description
|
||||
*/
|
||||
private LibraryNode(ElementTypeDescription description) {
|
||||
this.children = null;
|
||||
this.description = description;
|
||||
this.name = description.getName();
|
||||
this.translatedName = description.getTranslatedName();
|
||||
this.creator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new leaf
|
||||
*
|
||||
* @param name the name of the leaf
|
||||
* @param creator used to create the {@link ElementTypeDescription} if necessary
|
||||
*/
|
||||
LibraryNode(String name, DescriptionCreator creator) {
|
||||
this.children = null;
|
||||
this.name = name;
|
||||
this.translatedName = name;
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a node.
|
||||
* Throws an exception if this node is a leaf
|
||||
*
|
||||
* @param node
|
||||
*/
|
||||
void add(LibraryNode node) {
|
||||
children.add(node);
|
||||
}
|
||||
|
||||
void add(ElementTypeDescription node) {
|
||||
add(new LibraryNode(node));
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse the tree
|
||||
*
|
||||
* @param v a visitor
|
||||
* @param <V> the type of the visitor
|
||||
* @return the visitor
|
||||
*/
|
||||
public <V extends Visitor> V traverse(V v) {
|
||||
v.visit(this);
|
||||
if (children != null) {
|
||||
for (LibraryNode tn : children)
|
||||
tn.traverse(v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return trie if this is a leaf
|
||||
*/
|
||||
public boolean isLeaf() {
|
||||
return description != null || creator != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the description is already loaded
|
||||
*/
|
||||
public boolean isDescriptionLoaded() {
|
||||
return description != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description of the element
|
||||
*
|
||||
* @return the description
|
||||
* @throws IOException IOException
|
||||
*/
|
||||
public ElementTypeDescription getDescription() throws IOException {
|
||||
if (description == null)
|
||||
description = creator.createDescription();
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the translated name of the element
|
||||
*/
|
||||
public String getTranslatedName() {
|
||||
return translatedName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name od id of this element
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<LibraryNode> iterator() {
|
||||
return children.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* all children are removed
|
||||
*/
|
||||
public void removeAll() {
|
||||
children.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this node is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
if (isLeaf())
|
||||
return false;
|
||||
|
||||
return children.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the description if present, null otherwise
|
||||
*/
|
||||
public ElementTypeDescription getDescriptionOrNull() {
|
||||
return description;
|
||||
}
|
||||
}
|
15
src/main/java/de/neemann/digital/draw/library/Visitor.java
Normal file
15
src/main/java/de/neemann/digital/draw/library/Visitor.java
Normal file
@ -0,0 +1,15 @@
|
||||
package de.neemann.digital.draw.library;
|
||||
|
||||
/**
|
||||
* Visits all elements of the elements tree
|
||||
* Created by hneemann on 25.03.17.
|
||||
*/
|
||||
public interface Visitor {
|
||||
|
||||
/**
|
||||
* Called on every node
|
||||
*
|
||||
* @param libraryNode the node
|
||||
*/
|
||||
void visit(LibraryNode libraryNode);
|
||||
}
|
@ -23,7 +23,6 @@ import de.neemann.digital.draw.shapes.ieee.IEEEAndShape;
|
||||
import de.neemann.digital.draw.shapes.ieee.IEEENotShape;
|
||||
import de.neemann.digital.draw.shapes.ieee.IEEEOrShape;
|
||||
import de.neemann.digital.draw.shapes.ieee.IEEEXOrShape;
|
||||
import de.neemann.digital.gui.LibrarySelector;
|
||||
import de.neemann.digital.gui.components.data.DummyElement;
|
||||
import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.digital.testing.TestCaseElement;
|
||||
@ -57,6 +56,7 @@ public final class ShapeFactory {
|
||||
*/
|
||||
public ShapeFactory(ElementLibrary library, boolean ieee) {
|
||||
this.library = library;
|
||||
library.setShapeFactory(this);
|
||||
if (ieee) {
|
||||
map.put(And.DESCRIPTION.getName(), (attributes, inputs, outputs) -> new IEEEAndShape(inputs, outputs, false));
|
||||
map.put(NAnd.DESCRIPTION.getName(), (attributes, inputs, outputs) -> new IEEEAndShape(inputs, outputs, true));
|
||||
@ -136,8 +136,8 @@ public final class ShapeFactory {
|
||||
throw new NodeException(Lang.get("err_noShapeFoundFor_N", elementName));
|
||||
else {
|
||||
ElementTypeDescription pt = library.getElementType(elementName);
|
||||
if (pt instanceof LibrarySelector.ElementTypeDescriptionCustom) {
|
||||
LibrarySelector.ElementTypeDescriptionCustom customDescr = (LibrarySelector.ElementTypeDescriptionCustom) pt;
|
||||
if (pt instanceof ElementLibrary.ElementTypeDescriptionCustom) {
|
||||
ElementLibrary.ElementTypeDescriptionCustom customDescr = (ElementLibrary.ElementTypeDescriptionCustom) pt;
|
||||
return new GenericShape(
|
||||
pt.getShortName(),
|
||||
pt.getInputDescription(elementAttributes),
|
||||
|
@ -3,6 +3,7 @@ package de.neemann.digital.gui;
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* The InsertHistory puts the most frequently used elements to the toolbar of the main window.
|
||||
@ -41,15 +42,20 @@ public class InsertHistory {
|
||||
bar.add(wrapper);
|
||||
if (wrappers.size() > MAX_ICONS) {
|
||||
int oldest = findOldestIndex();
|
||||
wrapper = wrappers.get(oldest);
|
||||
bar.remove(wrapper.componentPosition);
|
||||
for (int i = oldest; i < wrappers.size(); i++)
|
||||
wrappers.get(i).componentPosition--;
|
||||
removeWrapperFromBar(wrappers.get(oldest));
|
||||
wrappers.remove(oldest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeWrapperFromBar(WrapperAction wrapper) {
|
||||
final int position = wrapper.componentPosition;
|
||||
bar.remove(position);
|
||||
for (WrapperAction w : wrappers)
|
||||
if (w.componentPosition > position)
|
||||
w.componentPosition--;
|
||||
}
|
||||
|
||||
private int findOldestIndex() {
|
||||
int found = -1;
|
||||
int oldestTime = mainTime;
|
||||
@ -70,8 +76,24 @@ public class InsertHistory {
|
||||
return false;
|
||||
}
|
||||
|
||||
private final class WrapperAction extends AbstractAction {
|
||||
/**
|
||||
* remove custom components
|
||||
*/
|
||||
public void removeCustom() {
|
||||
Iterator<WrapperAction> it = wrappers.iterator();
|
||||
while (it.hasNext()) {
|
||||
WrapperAction w = it.next();
|
||||
if (w.action instanceof LibrarySelector.InsertAction) {
|
||||
if (((LibrarySelector.InsertAction) w.action).isCustom()) {
|
||||
removeWrapperFromBar(w);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
bar.revalidate();
|
||||
}
|
||||
|
||||
private final class WrapperAction extends AbstractAction {
|
||||
private final AbstractAction action;
|
||||
private int componentPosition;
|
||||
private int time;
|
||||
|
@ -1,13 +1,10 @@
|
||||
package de.neemann.digital.gui;
|
||||
|
||||
import de.neemann.digital.core.element.*;
|
||||
import de.neemann.digital.draw.elements.Circuit;
|
||||
import de.neemann.digital.draw.elements.PinException;
|
||||
import de.neemann.digital.draw.elements.VisualElement;
|
||||
import de.neemann.digital.draw.graphics.Vector;
|
||||
import de.neemann.digital.draw.library.CustomElement;
|
||||
import de.neemann.digital.draw.library.ElementLibrary;
|
||||
import de.neemann.digital.draw.library.ElementNotFoundNotification;
|
||||
import de.neemann.digital.draw.library.LibraryListener;
|
||||
import de.neemann.digital.draw.library.LibraryNode;
|
||||
import de.neemann.digital.draw.shapes.ShapeFactory;
|
||||
import de.neemann.digital.gui.components.CircuitComponent;
|
||||
import de.neemann.digital.gui.state.State;
|
||||
@ -15,16 +12,10 @@ import de.neemann.digital.lang.Lang;
|
||||
import de.neemann.gui.ErrorMessage;
|
||||
import de.neemann.gui.StringUtils;
|
||||
import de.neemann.gui.ToolTipAction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* The LibrarySelector is responsible for building the menu used to select items for adding them to the circuit.
|
||||
@ -32,22 +23,17 @@ import java.util.HashMap;
|
||||
*
|
||||
* @author hneemann
|
||||
*/
|
||||
public class LibrarySelector implements ElementNotFoundNotification {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LibrarySelector.class);
|
||||
|
||||
public class LibrarySelector implements LibraryListener {
|
||||
private final ElementLibrary library;
|
||||
private final ShapeFactory shapeFactory;
|
||||
private final State elementState;
|
||||
private File filePath;
|
||||
private JMenu customMenu;
|
||||
private JMenu componentsMenu;
|
||||
private InsertHistory insertHistory;
|
||||
private CircuitComponent circuitComponent;
|
||||
private ArrayList<ImportedItem> importedElements;
|
||||
private HashMap<String, File> treeFileMap;
|
||||
|
||||
/**
|
||||
* Creates a new library selector.
|
||||
* the elementState is used to seht the window to the elemetEdit mode if a new element is added to the circuit.
|
||||
* the elementState is used to set the window to the elementEdit mode if a new element is added to the circuit.
|
||||
*
|
||||
* @param library the library to select elements from
|
||||
* @param shapeFactory The shape factory
|
||||
@ -55,10 +41,9 @@ public class LibrarySelector implements ElementNotFoundNotification {
|
||||
*/
|
||||
public LibrarySelector(ElementLibrary library, ShapeFactory shapeFactory, State elementState) {
|
||||
this.library = library;
|
||||
library.addListener(this);
|
||||
this.shapeFactory = shapeFactory;
|
||||
this.elementState = elementState;
|
||||
library.setElementNotFoundNotification(this);
|
||||
importedElements = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,64 +58,47 @@ public class LibrarySelector implements ElementNotFoundNotification {
|
||||
public JMenu buildMenu(InsertHistory insertHistory, CircuitComponent circuitComponent) {
|
||||
this.insertHistory = insertHistory;
|
||||
this.circuitComponent = circuitComponent;
|
||||
JMenu parts = new JMenu(Lang.get("menu_elements"));
|
||||
componentsMenu = new JMenu(Lang.get("menu_elements"));
|
||||
libraryChanged();
|
||||
|
||||
customMenu = new JMenu(Lang.get("menu_custom"));
|
||||
parts.add(customMenu);
|
||||
|
||||
customMenu.add(new ToolTipAction(Lang.get("menu_import")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JFileChooser fc = new JFileChooser(filePath);
|
||||
fc.setFileFilter(new FileNameExtensionFilter("Circuit", "dig"));
|
||||
if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
|
||||
try {
|
||||
Imported imp = importElement(fc.getSelectedFile());
|
||||
if (imp != null) {
|
||||
VisualElement visualElement = new VisualElement(imp.description.getName()).setPos(new Vector(10, 10)).setShapeFactory(shapeFactory);
|
||||
elementState.enter();
|
||||
circuitComponent.setPartToInsert(visualElement);
|
||||
insertHistory.add(imp.insertAction);
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
new ErrorMessage(Lang.get("msg_errorImportingModel")).addCause(e1).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}.setToolTip(Lang.get("menu_import_tt")).createJMenuItem());
|
||||
|
||||
customMenu.add(new ToolTipAction(Lang.get("menu_refresh")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
removeCustomElements();
|
||||
}
|
||||
}.setToolTip(Lang.get("menu_refresh_tt")).createJMenuItem());
|
||||
|
||||
|
||||
JMenu subMenu = null;
|
||||
String lastPath = null;
|
||||
for (ElementLibrary.ElementContainer elementContainer : library) {
|
||||
String path = elementContainer.getTreePath();
|
||||
if (!path.equals(lastPath)) {
|
||||
subMenu = new JMenu(path);
|
||||
parts.add(subMenu);
|
||||
lastPath = path;
|
||||
}
|
||||
subMenu.add(new InsertAction(elementContainer.getDescription(), insertHistory, circuitComponent)
|
||||
.setToolTip(createToolTipText(elementContainer.getDescription().getName()))
|
||||
.createJMenuItem());
|
||||
}
|
||||
|
||||
return parts;
|
||||
return componentsMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* removes all custom elements
|
||||
*/
|
||||
public void removeCustomElements() {
|
||||
for (ImportedItem item : importedElements) {
|
||||
library.removeElement(item.file);
|
||||
customMenu.remove(item.menuEntry);
|
||||
@Override
|
||||
public void libraryChanged() {
|
||||
componentsMenu.removeAll();
|
||||
|
||||
for (LibraryNode n : library.getRoot())
|
||||
addComponents(componentsMenu, n);
|
||||
|
||||
insertHistory.removeCustom();
|
||||
|
||||
JMenuItem m = componentsMenu.getItem(componentsMenu.getItemCount() - 1);
|
||||
if (m instanceof JMenu) {
|
||||
((JMenu) m).add(new ToolTipAction(Lang.get("menu_import")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
library.updateEntries();
|
||||
} catch (IOException ex) {
|
||||
SwingUtilities.invokeLater(new ErrorMessage(Lang.get("msg_errorImportingModel")).addCause(ex));
|
||||
}
|
||||
}
|
||||
}.setToolTip(Lang.get("menu_import_tt")).createJMenuItem());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addComponents(JMenu parts, LibraryNode node) {
|
||||
if (node.isLeaf()) {
|
||||
parts.add(new InsertAction(node, insertHistory, circuitComponent)
|
||||
.setToolTip(createToolTipText(node.getName()))
|
||||
.createJMenuItem());
|
||||
} else {
|
||||
JMenu subMenu = new JMenu(node.getName());
|
||||
for (LibraryNode child : node)
|
||||
addComponents(subMenu, child);
|
||||
parts.add(subMenu);
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,232 +106,50 @@ public class LibrarySelector implements ElementNotFoundNotification {
|
||||
return StringUtils.textToHTML(Lang.getNull("elem_" + elementName + "_tt"));
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the file path which is used to load missing nested elements
|
||||
*
|
||||
* @param filePath the file path
|
||||
*/
|
||||
public void setFilePath(File filePath) {
|
||||
treeFileMap = null;
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementTypeDescription elementNotFound(File file) throws IOException {
|
||||
// check if there is a file with the given name in the current directory
|
||||
// if so, load this file!
|
||||
File primary = new File(filePath, file.getName());
|
||||
if (primary.exists())
|
||||
file = primary;
|
||||
|
||||
// check if there is a file with the given name below the current directory
|
||||
// if so, load this file!
|
||||
File f = getFileFromTree(file.getName());
|
||||
if (f != null)
|
||||
return importElement(f).description;
|
||||
|
||||
// than check if the exact given file exists
|
||||
if (file.exists())
|
||||
return importElement(file).description;
|
||||
|
||||
// could not find the given file
|
||||
throw new IOException(Lang.get("err_couldNotFindIncludedFile_N0", file));
|
||||
}
|
||||
|
||||
private File getFileFromTree(String name) throws IOException {
|
||||
if (treeFileMap == null) {
|
||||
treeFileMap = new HashMap<>();
|
||||
populateTreeFileMap(treeFileMap, filePath);
|
||||
} else {
|
||||
if (!treeFileMap.containsKey(name)) { // if file not in map rescan folder
|
||||
treeFileMap.clear();
|
||||
populateTreeFileMap(treeFileMap, filePath);
|
||||
}
|
||||
}
|
||||
return treeFileMap.get(name);
|
||||
}
|
||||
|
||||
private void populateTreeFileMap(HashMap<String, File> map, File path) throws IOException {
|
||||
File[] list = path.listFiles();
|
||||
if (list != null) {
|
||||
for (File f : list) {
|
||||
final String name = f.getName();
|
||||
if (f.isFile() && name.endsWith(".dig")) {
|
||||
if (map.containsKey(name))
|
||||
throw new IOException(Lang.get("err_file_N0_ExistsTwiceBelow_N1", name, filePath));
|
||||
map.put(name, f);
|
||||
}
|
||||
if (f.isDirectory())
|
||||
populateTreeFileMap(map, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getActionName(ElementTypeDescription typeDescription) {
|
||||
if (typeDescription instanceof ElementTypeDescriptionCustom)
|
||||
return typeDescription.getShortName();
|
||||
else
|
||||
return typeDescription.getTranslatedName();
|
||||
}
|
||||
|
||||
private final class InsertAction extends ToolTipAction {
|
||||
|
||||
private final String name;
|
||||
final class InsertAction extends ToolTipAction {
|
||||
private final LibraryNode node;
|
||||
private final InsertHistory insertHistory;
|
||||
private final CircuitComponent circuitComponent;
|
||||
|
||||
private InsertAction(ElementTypeDescription typeDescription, InsertHistory insertHistory, CircuitComponent circuitComponent) {
|
||||
super(getActionName(typeDescription), new VisualElement(typeDescription.getName()).setShapeFactory(shapeFactory).createIcon(75));
|
||||
this.name = typeDescription.getName();
|
||||
private InsertAction(LibraryNode node, InsertHistory insertHistory, CircuitComponent circuitComponent) {
|
||||
super(node.getTranslatedName(), createIcon(node, shapeFactory));
|
||||
this.node = node;
|
||||
this.insertHistory = insertHistory;
|
||||
this.circuitComponent = circuitComponent;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
VisualElement visualElement = new VisualElement(name).setPos(new Vector(10, 10)).setShapeFactory(shapeFactory);
|
||||
VisualElement visualElement = new VisualElement(node.getName()).setPos(new Vector(10, 10)).setShapeFactory(shapeFactory);
|
||||
elementState.enter();
|
||||
circuitComponent.setPartToInsert(visualElement);
|
||||
if (getIcon() == null) {
|
||||
try {
|
||||
node.getDescription();
|
||||
setIcon(createIcon(node, shapeFactory));
|
||||
} catch (IOException ex) {
|
||||
SwingUtilities.invokeLater(new ErrorMessage(Lang.get("msg_errorImportingModel")).addCause(ex));
|
||||
}
|
||||
}
|
||||
insertHistory.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
private Imported importElement(File file) throws IOException {
|
||||
try {
|
||||
LOGGER.debug("load element " + file);
|
||||
Circuit circuit = Circuit.loadCircuit(file, shapeFactory);
|
||||
ElementTypeDescriptionCustom description =
|
||||
new ElementTypeDescriptionCustom(file,
|
||||
attributes -> new CustomElement(circuit, library, file),
|
||||
circuit.getAttributes(), circuit.getInputNames());
|
||||
description.setShortName(createShortName(file));
|
||||
library.addDescription(description, file);
|
||||
|
||||
InsertAction insertAction = new InsertAction(description, insertHistory, circuitComponent);
|
||||
String descriptionText = circuit.getAttributes().get(Keys.DESCRIPTION);
|
||||
if (descriptionText != null && descriptionText.length() > 0) {
|
||||
insertAction.setToolTip(StringUtils.textToHTML(descriptionText));
|
||||
description.setDescription(descriptionText);
|
||||
}
|
||||
|
||||
JMenuItem menuEntry = insertAction.createJMenuItem();
|
||||
ImportedItem item = findImportedItem(file);
|
||||
if (item != null) {
|
||||
if (customMenu != null) {
|
||||
customMenu.remove(item.menuEntry);
|
||||
}
|
||||
importedElements.remove(item);
|
||||
}
|
||||
importedElements.add(new ImportedItem(file, menuEntry));
|
||||
if (customMenu != null)
|
||||
customMenu.add(menuEntry);
|
||||
return new Imported(description, insertAction);
|
||||
} catch (PinException e) {
|
||||
throw new IOException(e);
|
||||
public boolean isCustom() {
|
||||
return node.getDescriptionOrNull() instanceof ElementLibrary.ElementTypeDescriptionCustom;
|
||||
}
|
||||
}
|
||||
|
||||
private ImportedItem findImportedItem(File file) {
|
||||
for (ImportedItem i : importedElements) {
|
||||
if (i.file.equals(file))
|
||||
return i;
|
||||
private static ImageIcon createIcon(LibraryNode node, ShapeFactory shapeFactory) {
|
||||
// don't load the description if only the icon is needed
|
||||
// create action without an icon instead
|
||||
if (node.isDescriptionLoaded()) {
|
||||
try {
|
||||
return new VisualElement(node.getDescription().getName()).setShapeFactory(shapeFactory).createIcon(75);
|
||||
} catch (IOException ex) {
|
||||
SwingUtilities.invokeLater(new ErrorMessage(Lang.get("msg_errorImportingModel")).addCause(ex));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String createShortName(File file) {
|
||||
return createShortName(file.getName());
|
||||
}
|
||||
|
||||
private String createShortName(String name) {
|
||||
if (name.endsWith(".dig")) return name.substring(0, name.length() - 4);
|
||||
|
||||
String transName = Lang.getNull("elem_" + name);
|
||||
if (transName == null)
|
||||
return name;
|
||||
else
|
||||
return transName;
|
||||
}
|
||||
|
||||
private final static class ImportedItem {
|
||||
private final File file;
|
||||
private final JMenuItem menuEntry;
|
||||
|
||||
private ImportedItem(File file, JMenuItem menuEntry) {
|
||||
this.file = file;
|
||||
this.menuEntry = menuEntry;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The description of a nested element.
|
||||
* This is a complete circuit which is used as a element.
|
||||
*/
|
||||
public static class ElementTypeDescriptionCustom extends ElementTypeDescription {
|
||||
private final File file;
|
||||
private final ElementAttributes attributes;
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Creates a new element
|
||||
*
|
||||
* @param file the file which is loaded
|
||||
* @param elementFactory a element factory which is used to create concrete elements if needed
|
||||
* @param attributes the attributes of the element
|
||||
* @param inputNames the names of the input signals
|
||||
*/
|
||||
public ElementTypeDescriptionCustom(File file, ElementFactory elementFactory, ElementAttributes attributes, PinDescription... inputNames) {
|
||||
super(file.getPath().replace('\\', '/'), elementFactory, inputNames);
|
||||
this.file = file;
|
||||
this.attributes = attributes;
|
||||
setShortName(file.getName());
|
||||
addAttribute(Keys.ROTATE);
|
||||
addAttribute(Keys.LABEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename
|
||||
* the retuned file is opened if the user wants to modify the element
|
||||
*
|
||||
* @return the filename
|
||||
*/
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the elements attributes
|
||||
*/
|
||||
public ElementAttributes getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom description for this field
|
||||
*
|
||||
* @param description the description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(ElementAttributes elementAttributes) {
|
||||
if (description != null)
|
||||
return description;
|
||||
else
|
||||
return super.getDescription(elementAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
private final static class Imported {
|
||||
private final ElementTypeDescription description;
|
||||
private final InsertAction insertAction;
|
||||
|
||||
private Imported(ElementTypeDescription description, InsertAction insertAction) {
|
||||
this.description = description;
|
||||
this.insertAction = insertAction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
private State runModelMicroState;
|
||||
|
||||
private Main() {
|
||||
this(null, null, null);
|
||||
this(null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,8 +137,8 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
* @param fileToOpen a file to open
|
||||
* @param savedListener a listener which is notified if the file is changed on disk
|
||||
*/
|
||||
public Main(Component parent, File fileToOpen, SavedListener savedListener) {
|
||||
this(parent, fileToOpen, savedListener, null);
|
||||
public Main(Component parent, File fileToOpen, SavedListener savedListener, ElementLibrary library) {
|
||||
this(parent, fileToOpen, savedListener, library, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,7 +148,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
* @param circuit circuit to show
|
||||
*/
|
||||
public Main(Component parent, Circuit circuit) {
|
||||
this(parent, null, null, circuit);
|
||||
this(parent, null, null, null, circuit);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,13 +159,14 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
* @param savedListener a listener which is notified if the file is changed on disk
|
||||
* @param circuit circuit to show
|
||||
*/
|
||||
private Main(Component parent, File fileToOpen, SavedListener savedListener, Circuit circuit) {
|
||||
private Main(Component parent, File fileToOpen, SavedListener savedListener, ElementLibrary parentsLibrary, Circuit circuit) {
|
||||
super(Lang.get("digital"));
|
||||
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
||||
setIconImages(IconCreator.createImages("icon32.png", "icon64.png", "icon128.png"));
|
||||
this.savedListener = savedListener;
|
||||
|
||||
library = new ElementLibrary();
|
||||
if (parentsLibrary == null) library = new ElementLibrary();
|
||||
else this.library = parentsLibrary;
|
||||
shapeFactory = new ShapeFactory(library, Settings.getInstance().get(Keys.SETTINGS_IEEE_SHAPES));
|
||||
|
||||
fileHistory = new FileHistory(this);
|
||||
@ -276,8 +277,8 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
if (file == null)
|
||||
file = new File(name);
|
||||
try {
|
||||
LibrarySelector.ElementTypeDescriptionCustom description =
|
||||
new LibrarySelector.ElementTypeDescriptionCustom(file,
|
||||
ElementLibrary.ElementTypeDescriptionCustom description =
|
||||
new ElementLibrary.ElementTypeDescriptionCustom(file,
|
||||
attributes -> new CustomElement(circuit, library, filename),
|
||||
circuit.getAttributes(), circuit.getInputNames());
|
||||
description.setShortName(name);
|
||||
@ -319,7 +320,6 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
setFilename(null, true);
|
||||
circuitComponent.setCircuit(new Circuit());
|
||||
windowPosManager.closeAll();
|
||||
librarySelector.removeCustomElements();
|
||||
}
|
||||
}
|
||||
}.setActive(normalMode);
|
||||
@ -330,7 +330,6 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
if (ClosingWindowListener.checkForSave(Main.this, Main.this)) {
|
||||
JFileChooser fc = getJFileChooser(lastFilename);
|
||||
if (fc.showOpenDialog(Main.this) == JFileChooser.APPROVE_OPTION) {
|
||||
librarySelector.removeCustomElements();
|
||||
loadFile(fc.getSelectedFile(), true);
|
||||
}
|
||||
}
|
||||
@ -342,7 +341,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JFileChooser fc = getJFileChooser(lastFilename);
|
||||
if (fc.showOpenDialog(Main.this) == JFileChooser.APPROVE_OPTION) {
|
||||
Main m = new Main(Main.this, fc.getSelectedFile(), null);
|
||||
Main m = new Main(Main.this, fc.getSelectedFile(), null, null);
|
||||
m.setLocationRelativeTo(Main.this);
|
||||
m.setVisible(true);
|
||||
}
|
||||
@ -399,7 +398,7 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
/**
|
||||
* Creates the edit menu
|
||||
*
|
||||
* @param menuBar the menu bar
|
||||
* @param menuBar the menu bar
|
||||
*/
|
||||
private void createEditMenu(JMenuBar menuBar) {
|
||||
JMenu edit = new JMenu(Lang.get("menu_edit"));
|
||||
@ -496,7 +495,8 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
|
||||
/**
|
||||
* Creates the start menu
|
||||
* @param menuBar the menu bar
|
||||
*
|
||||
* @param menuBar the menu bar
|
||||
* @param toolBar the tool bar
|
||||
*/
|
||||
private void createStartMenu(JMenuBar menuBar, JToolBar toolBar) {
|
||||
@ -820,14 +820,13 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
@Override
|
||||
public void open(File file) {
|
||||
if (ClosingWindowListener.checkForSave(Main.this, Main.this)) {
|
||||
librarySelector.removeCustomElements();
|
||||
loadFile(file, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadFile(File filename, boolean toPrefs) {
|
||||
try {
|
||||
librarySelector.setFilePath(filename.getParentFile());
|
||||
library.setFilePath(filename.getParentFile());
|
||||
Circuit circ = Circuit.loadCircuit(filename, shapeFactory);
|
||||
circuitComponent.setCircuit(circ);
|
||||
stoppedState.enter();
|
||||
@ -855,15 +854,21 @@ public class Main extends JFrame implements ClosingWindowListener.ConfirmSave, E
|
||||
}
|
||||
|
||||
private void setFilename(File filename, boolean toPrefs) {
|
||||
this.filename = filename;
|
||||
if (filename != null) {
|
||||
this.lastFilename = filename;
|
||||
librarySelector.setFilePath(filename.getParentFile());
|
||||
if (toPrefs)
|
||||
fileHistory.add(filename);
|
||||
setTitle(filename + " - " + Lang.get("digital"));
|
||||
} else
|
||||
setTitle(Lang.get("digital"));
|
||||
try {
|
||||
this.filename = filename;
|
||||
if (filename != null) {
|
||||
this.lastFilename = filename;
|
||||
library.setFilePath(filename.getParentFile());
|
||||
if (toPrefs)
|
||||
fileHistory.add(filename);
|
||||
setTitle(filename + " - " + Lang.get("digital"));
|
||||
} else {
|
||||
library.setFilePath(null);
|
||||
setTitle(Lang.get("digital"));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
new ErrorMessage(Lang.get("msg_errorReadingFile")).addCause(e).show(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,7 +16,6 @@ import de.neemann.digital.draw.library.ElementLibrary;
|
||||
import de.neemann.digital.draw.library.ElementNotFoundException;
|
||||
import de.neemann.digital.draw.shapes.Drawable;
|
||||
import de.neemann.digital.draw.shapes.ShapeFactory;
|
||||
import de.neemann.digital.gui.LibrarySelector;
|
||||
import de.neemann.digital.gui.Main;
|
||||
import de.neemann.digital.gui.SavedListener;
|
||||
import de.neemann.digital.gui.sync.NoSync;
|
||||
@ -562,20 +561,20 @@ public class CircuitComponent extends JComponent implements Circuit.ChangedListe
|
||||
Point p = new Point(e.getX(), e.getY());
|
||||
SwingUtilities.convertPointToScreen(p, CircuitComponent.this);
|
||||
AttributeDialog attributeDialog = new AttributeDialog(this, p, list, vp.getElementAttributes());
|
||||
if (elementType instanceof LibrarySelector.ElementTypeDescriptionCustom) {
|
||||
if (elementType instanceof ElementLibrary.ElementTypeDescriptionCustom) {
|
||||
attributeDialog.addButton(Lang.get("attr_openCircuitLabel"), new ToolTipAction(Lang.get("attr_openCircuit")) {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
attributeDialog.dispose();
|
||||
SwingUtilities.invokeLater(() -> new Main(CircuitComponent.this,
|
||||
((LibrarySelector.ElementTypeDescriptionCustom) elementType).getFile(),
|
||||
((ElementLibrary.ElementTypeDescriptionCustom) elementType).getFile(),
|
||||
filename -> {
|
||||
if (parentsSavedListener != null)
|
||||
parentsSavedListener.saved(filename);
|
||||
library.removeElement(filename);
|
||||
circuit.clearState();
|
||||
hasChanged();
|
||||
}).setVisible(true));
|
||||
}, library).setVisible(true));
|
||||
}
|
||||
}.setToolTip(Lang.get("attr_openCircuit_tt")));
|
||||
}
|
||||
|
@ -31,6 +31,23 @@ public abstract class ToolTipAction extends AbstractAction {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the icon
|
||||
*
|
||||
* @param icon the icon to set
|
||||
*/
|
||||
public void setIcon(Icon icon) {
|
||||
putValue("SmallIcon", icon);
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the icon
|
||||
*/
|
||||
public Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tool tip text
|
||||
*
|
||||
|
@ -584,8 +584,8 @@ Es sind nur {1} Variablen erlaubt, es wurden jedoch {2} gefunden.</string>
|
||||
<string name="menu_fast_tt">Führt die Schaltung aus, bis ein Stopsignal über ein BRK-Element detektiert wird.</string>
|
||||
<string name="menu_file">Datei</string>
|
||||
<string name="menu_help">Hilfe</string>
|
||||
<string name="menu_import">Importieren</string>
|
||||
<string name="menu_import_tt">Importiert eine Schaltung als verwendbares Bauteil</string>
|
||||
<string name="menu_import">Aktualisieren</string>
|
||||
<string name="menu_import_tt">Aktualisieren des Bauteile Menüs.</string>
|
||||
<string name="menu_maximize">Einpassen</string>
|
||||
<string name="menu_micro">Gatterschrittmodus</string>
|
||||
<string name="menu_micro_tt">Startet die Schaltung im Gatterschrittmodus</string>
|
||||
|
@ -571,8 +571,8 @@ allowed are {1} variables but {2} are found.</string>
|
||||
<string name="menu_fast_tt">Runs the circuit until a break is detected by the BRK component.</string>
|
||||
<string name="menu_file">File</string>
|
||||
<string name="menu_help">Help</string>
|
||||
<string name="menu_import">Import</string>
|
||||
<string name="menu_import_tt">Imports a circuit as a usable component!</string>
|
||||
<string name="menu_import">Update</string>
|
||||
<string name="menu_import_tt">Updates the components menu!</string>
|
||||
<string name="menu_maximize">Fit to window</string>
|
||||
<string name="menu_micro">Single gate stepping</string>
|
||||
<string name="menu_micro_tt">Runs the circuit in single gate step mode</string>
|
||||
|
@ -64,8 +64,7 @@ public class TestNesting extends TestCase {
|
||||
|
||||
private TestExecuter createTestExecuterForNesting(String file) throws IOException, NodeException, PinException, ElementNotFoundException {
|
||||
ElementLibrary library = new ElementLibrary();
|
||||
LibrarySelector librarySelector = new LibrarySelector(library, new ShapeFactory(library), null);
|
||||
librarySelector.setFilePath(new File(Resources.getRoot(), "dig"));
|
||||
library.setFilePath(new File(Resources.getRoot(), "dig"));
|
||||
return TestExecuter.createFromFile(file, library);
|
||||
}
|
||||
|
||||
|
@ -70,10 +70,9 @@ public class ToBreakRunner {
|
||||
|
||||
private ToBreakRunner(File filename, boolean doInit) throws IOException, PinException, NodeException, ElementNotFoundException {
|
||||
library = new ElementLibrary();
|
||||
library.setFilePath(filename.getParentFile());
|
||||
ShapeFactory shapeFactory = new ShapeFactory(library);
|
||||
circuit = Circuit.loadCircuit(filename, shapeFactory);
|
||||
LibrarySelector librarySelector = new LibrarySelector(library, shapeFactory, null);
|
||||
librarySelector.setFilePath(filename.getParentFile());
|
||||
|
||||
ModelCreator md = new ModelCreator(circuit, library);
|
||||
model = md.createModel(false);
|
||||
|
@ -23,6 +23,7 @@ public class TestElemConsistence extends TestCase {
|
||||
* @throws NodeException
|
||||
*/
|
||||
public void testConsistence() throws NodeException, PinException {
|
||||
/*
|
||||
ElementLibrary library = new ElementLibrary();
|
||||
for (ElementLibrary.ElementContainer e : library) {
|
||||
ElementTypeDescription etd = e.getDescription();
|
||||
@ -37,7 +38,7 @@ public class TestElemConsistence extends TestCase {
|
||||
checkPins(key, etd.getInputDescription(new ElementAttributes()));
|
||||
checkPins(key, etd.getOutputDescriptions(new ElementAttributes()));
|
||||
}
|
||||
}
|
||||
}*/ fail();
|
||||
}
|
||||
|
||||
private void checkPins(String key, PinDescriptions pins) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user