Added 'File' -> 'Import Netlist' option that can import components from

a Tango PCB file
This commit is contained in:
bancika
2021-01-03 00:03:44 +01:00
parent 4144956a09
commit 75758e0250
19 changed files with 1039 additions and 3 deletions
@@ -23,6 +23,7 @@ package org.diylc.common;
import java.util.List; import java.util.List;
import org.diylc.netlist.INetlistParser;
import org.diylc.netlist.Netlist; import org.diylc.netlist.Netlist;
/** /**
@@ -47,5 +48,11 @@ public interface INetlistProcessor {
*/ */
List<INetlistAnalyzer> getNetlistAnalyzers(); List<INetlistAnalyzer> getNetlistAnalyzers();
/**
* Finds all available {@link INetlistParser} implementations.
*
* @return
*/
List<INetlistParser> getNetlistParserDefinitions();
} }
@@ -0,0 +1,163 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
package org.diylc.netlist;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.diylc.core.IDIYComponent;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
public abstract class AbstractNetlistParser implements INetlistParser {
private static Size X_OFFSET = new Size(1.5d, SizeUnit.in);
private static Size Y_OFFSET = new Size(0.3d, SizeUnit.in);
private static int ROW_COUNT = 15;
public List<ParsedNetlistEntry> parseFile(String fileName, List<String> outputWarnings) throws NetlistParseException {
String content;
try {
content = new String(Files.readAllBytes(Paths.get(fileName)));
} catch (IOException e) {
throw new NetlistParseException("Error reading file", e);
}
return parse(content, outputWarnings);
}
public List<ParsedNetlistEntry> parse(String content, List<String> outputWarnings) throws NetlistParseException {
List<ParsedNetlistEntry> result = new ArrayList<ParsedNetlistEntry>();
Pattern pattern = Pattern.compile(getItemRegex(), Pattern.MULTILINE | Pattern.DOTALL);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
String type;
try {
type = matcher.group("Type").trim();
} catch (Exception e) {
outputWarnings.add("'Type' group not found.");
continue;
}
if (type == null) {
outputWarnings.add("'Type' group not found.");
continue;
}
Map<String, Object> valueMap = new HashMap<String, Object>();
List<Class<?>> typeCandidates = getComponentTypeCandidates(type, valueMap);
if (typeCandidates == null) {
outputWarnings.add("Type mappings not found for " + type + ".");
continue;
}
for (String propertyName : getPropertyNames()) {
String valueStr = matcher.group(propertyName).trim();
try {
Object value = parseValue(type, propertyName, valueStr);
valueMap.put(propertyName, value);
} catch (Exception e) {
outputWarnings
.add("Error while parsing value for " + type + "." + propertyName + " = " + valueStr);
}
}
result.add(new ParsedNetlistEntry(typeCandidates, type, valueMap));
}
Collections.sort(result, new Comparator<ParsedNetlistEntry>() {
@Override
public int compare(ParsedNetlistEntry o1, ParsedNetlistEntry o2) {
int comp = o1.getRawType().compareToIgnoreCase(o2.getRawType());
if (comp == 0 && o1.getValues().containsKey("Name") && o2.getValues().containsKey("Name"))
comp = o1.getValues().get("Name").toString().compareToIgnoreCase(o2.getValues().get("Name").toString());
return comp;
}
});
return result;
}
public List<IDIYComponent<?>> generateComponents(List<ParsedNetlistComponent> components,
List<String> outputWarnings) {
double dx = 0;
double dy = 0;
List<IDIYComponent<?>> result = new ArrayList<IDIYComponent<?>>();
for (int i = 0; i < components.size(); i++) {
ParsedNetlistComponent parsedComponent = components.get(i);
if (parsedComponent.getType() == null) {
outputWarnings.add("Type not selected for " + parsedComponent.getValues().get("Name"));
continue;
}
Class<?> clazz = parsedComponent.getType();
IDIYComponent<?> component;
try {
component = (IDIYComponent<?>) clazz.newInstance();
} catch (Exception e) {
outputWarnings.add(e.getMessage());
continue;
}
for (int j = 0; j < component.getControlPointCount(); j++) {
Point2D p = component.getControlPoint(j);
Point2D controlPoint = new Point2D.Double(p.getX() + dx, p.getY() + dy);
component.setControlPoint(controlPoint, j);
}
if (i > 0 && i % ROW_COUNT == 0) {
dx += X_OFFSET.convertToPixels();
dy = 0;
} else {
dy += Y_OFFSET.convertToPixels();
}
Method[] methods = clazz.getMethods();
for (Map.Entry<String, Object> value : parsedComponent.getValues().entrySet()) {
try {
Optional<Method> first = Arrays.stream(methods).filter(x -> x.getName().equals("set" + value.getKey())).findFirst();
if (first.isPresent()) {
Method setter = first.get();
setter.invoke(component, value.getValue());
} else {
outputWarnings.add("No setter found for " + value.getKey());
}
} catch (Exception e) {
outputWarnings.add("Error setting " + value.getKey() + ": " + e.getMessage());
}
}
result.add(component);
}
return result;
}
}
@@ -0,0 +1,66 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
package org.diylc.netlist;
import java.util.List;
import java.util.Map;
import org.diylc.core.IDIYComponent;
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
public interface INetlistParser {
String getName();
String getFileExt();
String getItemRegex();
List<Class<?>> getComponentTypeCandidates(String type, Map<String, Object> additionalOutputs);
List<String> getPropertyNames();
Object parseValue(String type, String propertyName, String valueStr);
List<ParsedNetlistEntry> parseFile(String fileName, List<String> outputWarnings)
throws NetlistParseException;
List<ParsedNetlistEntry> parse(String content, List<String> outputWarnings)
throws NetlistParseException;
List<IDIYComponent<?>> generateComponents(List<ParsedNetlistComponent> components,
List<String> outputWarnings);
}
@@ -0,0 +1,50 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
package org.diylc.netlist;
public class NetlistParseException extends Exception {
private static final long serialVersionUID = 1L;
public NetlistParseException() {
super();
// TODO Auto-generated constructor stub
}
public NetlistParseException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public NetlistParseException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public NetlistParseException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public NetlistParseException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}
@@ -0,0 +1,26 @@
package org.diylc.netlist;
import java.util.Map;
public class ParsedNetlistComponent {
public Class<?> type;
public Map<String, Object> values;
public ParsedNetlistComponent() {
}
public ParsedNetlistComponent(Class<?> type, Map<String, Object> values) {
super();
this.type = type;
this.values = values;
}
public Class<?> getType() {
return type;
}
public Map<String, Object> getValues() {
return values;
}
}
@@ -0,0 +1,55 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2018 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.netlist;
import java.util.List;
import java.util.Map;
public class ParsedNetlistEntry {
private List<Class<?>> typeCandidates;
private Map<String, Object> values;
private String rawType;
public ParsedNetlistEntry() {
}
public ParsedNetlistEntry(List<Class<?>> typeCandidates, String rawType,
Map<String, Object> values) {
super();
this.typeCandidates = typeCandidates;
this.rawType = rawType;
this.values = values;
}
public List<Class<?>> getTypeCandidates() {
return typeCandidates;
}
public String getRawType() {
return rawType;
}
public Map<String, Object> getValues() {
return values;
}
}
@@ -83,6 +83,7 @@ import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit; import org.diylc.core.measures.SizeUnit;
import org.diylc.lang.LangUtil; import org.diylc.lang.LangUtil;
import org.diylc.netlist.Group; import org.diylc.netlist.Group;
import org.diylc.netlist.INetlistParser;
import org.diylc.netlist.Netlist; import org.diylc.netlist.Netlist;
import org.diylc.netlist.NetlistAnalyzer; import org.diylc.netlist.NetlistAnalyzer;
import org.diylc.netlist.Node; import org.diylc.netlist.Node;
@@ -3403,6 +3404,34 @@ public class Presenter implements IPlugInPort {
} }
} }
@Override
public List<INetlistParser> getNetlistParserDefinitions() {
Set<Class<?>> classes;
try {
classes = Utils.getClasses("org.diylc.netlist");
List<INetlistParser> result = new ArrayList<INetlistParser>();
for (Class<?> clazz : classes) {
if (!Modifier.isAbstract(clazz.getModifiers()) && INetlistParser.class.isAssignableFrom(clazz)) {
result.add((INetlistParser) clazz.newInstance());
}
}
Collections.sort(result, new Comparator<INetlistParser>() {
@Override
public int compare(INetlistParser o1, INetlistParser o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
});
return result;
} catch (Exception e) {
LOG.error("Could not load INetlistParserDefinition implementations", e);
return null;
}
}
// Test stuff // Test stuff
@Override @Override
@@ -3418,6 +3418,10 @@
<releaseDate>2020-12-28 00:00:00.000 CET</releaseDate> <releaseDate>2020-12-28 00:00:00.000 CET</releaseDate>
<name></name> <name></name>
<changes> <changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added 'File' -> 'Import Netlist' option that can import components from a Tango PCB file</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change> <org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType> <changeType>NEW_FEATURE</changeType>
<description>Português translation added (thanks Pedro Rizzi!)</description> <description>Português translation added (thanks Pedro Rizzi!)</description>
@@ -28,7 +28,7 @@ package org.diylc.netlist;
*/ */
public interface ISpiceMapper { public interface ISpiceMapper {
int mapToSpiceNode(int pontIndex); int mapToSpiceNode(int pointIndex);
String getComment(); String getComment();
@@ -0,0 +1,116 @@
package org.diylc.netlist;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.diylc.components.passive.AxialElectrolyticCapacitor;
import org.diylc.components.passive.AxialFilmCapacitor;
import org.diylc.components.passive.CapacitorSymbol;
import org.diylc.components.passive.MultiSectionCapacitor;
import org.diylc.components.passive.RadialCeramicDiskCapacitor;
import org.diylc.components.passive.RadialElectrolytic;
import org.diylc.components.passive.RadialFilmCapacitor;
import org.diylc.components.passive.Resistor;
import org.diylc.components.passive.ResistorSymbol;
import org.diylc.components.semiconductors.DIL_IC;
import org.diylc.components.semiconductors.DiodeGlass;
import org.diylc.components.semiconductors.DiodePlastic;
import org.diylc.components.semiconductors.DiodeSymbol;
import org.diylc.components.semiconductors.LED;
import org.diylc.components.semiconductors.LEDSymbol;
import org.diylc.components.semiconductors.PhotoDiodeSymbol;
import org.diylc.components.semiconductors.SchottkyDiodeSymbol;
import org.diylc.components.semiconductors.ZenerDiodeSymbol;
import org.diylc.core.measures.Capacitance;
import org.diylc.core.measures.Resistance;
public class TangoNetlistParser extends AbstractNetlistParser {
@Override
public String getName() {
return "Tango";
}
@Override
public String getFileExt() {
return "pcb";
}
@Override
public String getItemRegex() {
return "\\[\\s*(?<Name>.+?)\\n(?<Type>.+?)\\n(?<Value>.+?)\\s*\\]";
}
@Override
public List<Class<?>> getComponentTypeCandidates(String type,
Map<String, Object> additionalOutputs) {
List<Class<?>> types = new ArrayList<Class<?>>();
if ("RESISTOR".equalsIgnoreCase(type)) {
types.add(Resistor.class);
types.add(ResistorSymbol.class);
}
if (type.toUpperCase().startsWith("CAP_CERAMIC")) {
types.add(RadialCeramicDiskCapacitor.class);
types.add(CapacitorSymbol.class);
}
if (type.toUpperCase().startsWith("CAP_FILM")) {
types.add(AxialFilmCapacitor.class);
types.add(RadialFilmCapacitor.class);
types.add(CapacitorSymbol.class);
}
if (type.toUpperCase().startsWith("CAP_ELECTRO")) {
additionalOutputs.put("Polarized", true);
types.add(AxialElectrolyticCapacitor.class);
types.add(RadialElectrolytic.class);
types.add(MultiSectionCapacitor.class);
types.add(CapacitorSymbol.class);
}
if (type.toUpperCase().startsWith("DIP")) {
try {
int pinCount = Integer.parseInt(type.substring(3));
additionalOutputs.put("PinCount", DIL_IC.PinCount.valueOf("_" + pinCount));
} catch (Exception e) {
}
types.add(DIL_IC.class);
}
if (type.equalsIgnoreCase("DIODE")) {
types.add(DiodeGlass.class);
types.add(DiodePlastic.class);
types.add(SchottkyDiodeSymbol.class);
types.add(PhotoDiodeSymbol.class);
types.add(DiodeSymbol.class);
types.add(ZenerDiodeSymbol.class);
}
if (type.equalsIgnoreCase("LED")) {
types.add(LED.class);
types.add(LEDSymbol.class);
}
return types;
}
@Override
public List<String> getPropertyNames() {
return Arrays.asList("Name", "Value");
}
@Override
public Object parseValue(String type, String propertyName, String valueStr) {
if ("RESISTOR".equalsIgnoreCase(type) && "Value".equals(propertyName))
return Resistance.parseResistance(valueStr);
if ((type.toUpperCase().startsWith("CAP_CERAMIC") || type.toUpperCase().startsWith("CAP_FILM")
|| type.toUpperCase().startsWith("CAP_ELECTRO")) && "Value".equals(propertyName))
return Capacitance.parseCapacitance(valueStr + "F");
return valueStr;
}
}
@@ -0,0 +1,90 @@
package org.diylc.netlist;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
public class TangoParserTests {
@Test
public void testParse1() {
String content = "[\r\n" +
"R9\r\n" +
"RESISTOR\r\n" +
"100k\r\n" +
"\r\n" +
"]\r\n" +
"[\r\n" +
"D4\r\n" +
"LED\r\n" +
"LED\r\n" +
"\r\n" +
"]\r\n" +
"[\r\n" +
"C3\r\n" +
"CAP_FILM\r\n" +
"82n\r\n" +
"\r\n" +
"]\r\n" +
"[\r\n" +
"C2\r\n" +
"CAP_ELECTRO_200\r\n" +
"1u\r\n" +
"\r\n" +
"]\r\n" +
"[\r\n" +
"C1\r\n" +
"CAP_CERAMIC1\r\n" +
"820p\r\n" +
"\r\n" +
"]\r\n" +
"[\r\n" +
"U2\r\n" +
"DIP14\r\n" +
"TL074\r\n" +
"\r\n" +
"]\r\n" +
"[\r\n" +
"D1\r\n" +
"DIODE\r\n" +
"Zener 12V\r\n" +
"\r\n" +
"]\r\n" +
"[\r\n" +
"B1\r\n" +
"PADS2\r\n" +
"9V\r\n" +
"\r\n" +
"]\r\n" +
"(\r\n" +
"unnamed_net15\r\n" +
"U4-11\r\n" +
")\r\n" +
"(\r\n" +
"unnamed_net14\r\n" +
"U3-3\r\n" +
"U1-3\r\n" +
"R7-1\r\n" +
"R8-2\r\n" +
"U2-3\r\n" +
")\r\n" +
"(\r\n" +
"unnamed_net13\r\n" +
"R1-2\r\n" +
"B1-1\r\n" +
")";
List<String> outputWarnings = new ArrayList<String>();
try {
TangoNetlistParser parser = new TangoNetlistParser();
List<ParsedNetlistEntry> parsed = parser.parse(content, outputWarnings);
Assert.assertNotNull(parsed);
} catch (NetlistParseException e) {
fail("Unexpected error:" + e.getMessage());
}
}
}
Binary file not shown.
Binary file not shown.
@@ -39,12 +39,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.stream.Collectors;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import javax.swing.filechooser.FileFilter;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
@@ -71,7 +73,10 @@ import org.diylc.core.measures.SizeUnit;
import org.diylc.editor.FlexibleLeadsEditor; import org.diylc.editor.FlexibleLeadsEditor;
import org.diylc.lang.LangUtil; import org.diylc.lang.LangUtil;
import org.diylc.netlist.Group; import org.diylc.netlist.Group;
import org.diylc.netlist.INetlistParser;
import org.diylc.netlist.Netlist; import org.diylc.netlist.Netlist;
import org.diylc.netlist.ParsedNetlistComponent;
import org.diylc.netlist.ParsedNetlistEntry;
import org.diylc.netlist.Summary; import org.diylc.netlist.Summary;
import org.diylc.presenter.Presenter; import org.diylc.presenter.Presenter;
import org.diylc.serialization.ProjectFileManager; import org.diylc.serialization.ProjectFileManager;
@@ -83,6 +88,7 @@ import org.diylc.swing.plugins.edit.ComponentTransferable;
import org.diylc.swing.plugins.edit.FindDialog; import org.diylc.swing.plugins.edit.FindDialog;
import org.diylc.swing.plugins.file.BomDialog; import org.diylc.swing.plugins.file.BomDialog;
import org.diylc.swing.plugins.file.FileFilterEnum; import org.diylc.swing.plugins.file.FileFilterEnum;
import org.diylc.swing.plugins.file.NetlistImportDialog;
import org.diylc.swingframework.ButtonDialog; import org.diylc.swingframework.ButtonDialog;
import org.diylc.swingframework.CheckBoxListDialog; import org.diylc.swingframework.CheckBoxListDialog;
import org.diylc.swingframework.IDrawingProvider; import org.diylc.swingframework.IDrawingProvider;
@@ -121,6 +127,10 @@ public class ActionFactory {
public ImportAction createImportAction(IPlugInPort plugInPort, ISwingUI swingUI) { public ImportAction createImportAction(IPlugInPort plugInPort, ISwingUI swingUI) {
return new ImportAction(plugInPort, swingUI); return new ImportAction(plugInPort, swingUI);
} }
public ImportNetlistAction createImportNetlistAction(IPlugInPort plugInPort, ISwingUI swingUI) {
return new ImportNetlistAction(plugInPort, swingUI);
}
public SaveAction createSaveAction(IPlugInPort plugInPort, ISwingUI swingUI) { public SaveAction createSaveAction(IPlugInPort plugInPort, ISwingUI swingUI) {
return new SaveAction(plugInPort, swingUI); return new SaveAction(plugInPort, swingUI);
@@ -473,6 +483,101 @@ public class ActionFactory {
} }
} }
} }
public static class ImportNetlistAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private IPlugInPort plugInPort;
private ISwingUI swingUI;
private List<INetlistParser> parserDefinitions;
private List<String> extensions;
private FileFilter filter;
public ImportNetlistAction(IPlugInPort plugInPort, ISwingUI swingUI) {
super();
this.plugInPort = plugInPort;
this.swingUI = swingUI;
putValue(AbstractAction.NAME, "Import Netlist");
putValue(AbstractAction.SMALL_ICON, IconLoader.ImportNetlist.getIcon());
this.parserDefinitions = plugInPort.getNetlistParserDefinitions();
this.extensions = parserDefinitions.stream().map(x -> x.getFileExt()).collect(Collectors.toList());
this.filter = new FileFilter() {
@Override
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
String fileExt = f.getName();
fileExt = fileExt.substring(fileExt.lastIndexOf('.') + 1).toLowerCase();
for (String ext : extensions) {
if (ext.equals(fileExt)) {
return true;
}
}
return false;
}
@Override
public String getDescription() {
return LangUtil.translate("Netlist files");
}
};
}
@Override
public void actionPerformed(ActionEvent e) {
LOG.info("ImportNetlistAction triggered");
final File file = DialogFactory.getInstance().showOpenDialog(this.filter,
null, this.extensions.get(0), null);
// TODO: identity by extension
final INetlistParser parser = parserDefinitions.get(0);
if (file != null) {
swingUI.executeBackgroundTask(new ITask<List<ParsedNetlistEntry>>() {
@Override
public List<ParsedNetlistEntry> doInBackground() throws Exception {
LOG.debug("Importing netlist from " + file.getAbsolutePath());
List<String> outputWarnings = new ArrayList<String>();
List<ParsedNetlistEntry> entries = parser.parseFile(file.getAbsolutePath(), outputWarnings);
return entries;
}
@Override
public void complete(List<ParsedNetlistEntry> entries) {
try {
NetlistImportDialog dialog = DialogFactory.getInstance().createNetlistImportDialog(plugInPort,entries);
dialog.setVisible(true);
if (ButtonDialog.OK.equals(dialog.getSelectedButtonCaption())) {
List<String> outputWarnings = new ArrayList<String>();
Map<String, Class<?>> results = dialog.getResults();
List<ParsedNetlistComponent> parsedComponents = entries.stream().map(entry ->
new ParsedNetlistComponent(results.get(entry.getRawType()), entry.getValues())).collect(Collectors.toList());
List<IDIYComponent<?>> components = parser.generateComponents(parsedComponents, outputWarnings);
plugInPort.pasteComponents(components, false, false);
}
} catch (Exception e) {
swingUI.showMessage("Could not import netlist file: " + e.getMessage(), "Error",
ISwingUI.ERROR_MESSAGE);
e.printStackTrace();
}
}
@Override
public void failed(Exception e) {
swingUI.showMessage("Could not import netlist file: " + e.getMessage(), "Error",
ISwingUI.ERROR_MESSAGE);
}
}, true);
}
}
}
public static class SaveAction extends AbstractAction { public static class SaveAction extends AbstractAction {
@@ -29,6 +29,7 @@ import javax.swing.filechooser.FileFilter;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.common.PropertyWrapper; import org.diylc.common.PropertyWrapper;
import org.diylc.netlist.ParsedNetlistEntry;
import org.diylc.plugins.cloud.model.UserEntity; import org.diylc.plugins.cloud.model.UserEntity;
import org.diylc.swing.gui.components.OverwritePromptFileChooser; import org.diylc.swing.gui.components.OverwritePromptFileChooser;
import org.diylc.swing.gui.editor.PropertyEditorDialog; import org.diylc.swing.gui.editor.PropertyEditorDialog;
@@ -38,6 +39,7 @@ import org.diylc.swing.plugins.cloud.view.UploadDialog;
import org.diylc.swing.plugins.cloud.view.UserEditDialog; import org.diylc.swing.plugins.cloud.view.UserEditDialog;
import org.diylc.swing.plugins.edit.FindDialog; import org.diylc.swing.plugins.edit.FindDialog;
import org.diylc.swing.plugins.file.BomDialog; import org.diylc.swing.plugins.file.BomDialog;
import org.diylc.swing.plugins.file.NetlistImportDialog;
import org.diylc.swingframework.AboutDialog; import org.diylc.swingframework.AboutDialog;
import org.diylc.swingframework.IFileChooserAccessory; import org.diylc.swingframework.IFileChooserAccessory;
import org.diylc.swingframework.ProgressDialog; import org.diylc.swingframework.ProgressDialog;
@@ -229,4 +231,9 @@ public class DialogFactory {
ProgressDialog dialog = new ProgressDialog(mainFrame, title, buttonCaptions, description, useProgress); ProgressDialog dialog = new ProgressDialog(mainFrame, title, buttonCaptions, description, useProgress);
return dialog; return dialog;
} }
public NetlistImportDialog createNetlistImportDialog(IPlugInPort plugInPort, List<ParsedNetlistEntry> entries) {
NetlistImportDialog dialog = new NetlistImportDialog(mainFrame, plugInPort, entries);
return dialog;
}
} }
@@ -67,7 +67,8 @@ public enum IconLoader {
JarBeanInto("jar_bean_into.png"), GraphEdgeDirected("graph_edge_directed.png"), LaserPointer("laserpointer.png"), TapeMeasure("tape_measure1.png"), JarBeanInto("jar_bean_into.png"), GraphEdgeDirected("graph_edge_directed.png"), LaserPointer("laserpointer.png"), TapeMeasure("tape_measure1.png"),
Elements("elements1.png"), GraphNodes("graph_nodes.png"), User("user1.png"), FlexibleLeads("flexible_leads.png"), Pads("pads.png"), Lock("lock.png"), Elements("elements1.png"), GraphNodes("graph_nodes.png"), User("user1.png"), FlexibleLeads("flexible_leads.png"), Pads("pads.png"), Lock("lock.png"),
Unlock("lock_open.png"), Earth("earth.png"), Loadline("loadline.png"), LoadlineAdd("loadline_add.png"), SnapToGrid("snap_to_grid.png"), Unlock("lock_open.png"), Earth("earth.png"), Loadline("loadline.png"), LoadlineAdd("loadline_add.png"), SnapToGrid("snap_to_grid.png"),
SnapToComponents("snap_to_components.png"), SnapToNone("snap_to_none.png"), TraceProximity("trace_proximity.png"), ComponentLarge("component_large.png"); SnapToComponents("snap_to_components.png"), SnapToNone("snap_to_none.png"), TraceProximity("trace_proximity.png"),
ComponentLarge("component_large.png"), ImportNetlist("import_netlist.png");
protected String name; protected String name;
Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

@@ -72,7 +72,8 @@ public class FileMenuPlugin implements IPlugIn, IDynamicSubmenuHandler {
ActionFactory actionFactory = ActionFactory.getInstance(); ActionFactory actionFactory = ActionFactory.getInstance();
swingUI.injectMenuAction(actionFactory.createNewAction(plugInPort), FILE_TITLE); swingUI.injectMenuAction(actionFactory.createNewAction(plugInPort), FILE_TITLE);
swingUI.injectMenuAction(actionFactory.createOpenAction(plugInPort, swingUI), FILE_TITLE); swingUI.injectMenuAction(actionFactory.createOpenAction(plugInPort, swingUI), FILE_TITLE);
swingUI.injectMenuAction(actionFactory.createImportAction(plugInPort, swingUI), FILE_TITLE); swingUI.injectMenuAction(actionFactory.createImportAction(plugInPort, swingUI), FILE_TITLE);
swingUI.injectMenuAction(actionFactory.createImportNetlistAction(plugInPort, swingUI), FILE_TITLE);
swingUI.injectMenuAction(actionFactory.createSaveAction(plugInPort, swingUI), FILE_TITLE); swingUI.injectMenuAction(actionFactory.createSaveAction(plugInPort, swingUI), FILE_TITLE);
swingUI.injectMenuAction(actionFactory.createSaveAsAction(plugInPort, swingUI), FILE_TITLE); swingUI.injectMenuAction(actionFactory.createSaveAsAction(plugInPort, swingUI), FILE_TITLE);
swingUI.injectDynamicSubmenu("Recent Files", IconLoader.History.getIcon(), FILE_TITLE, this); swingUI.injectDynamicSubmenu("Recent Files", IconLoader.History.getIcon(), FILE_TITLE, this);
@@ -0,0 +1,316 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
package org.diylc.swing.plugins.file;
import java.awt.Component;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.ComponentType;
import org.diylc.common.IPlugInPort;
import org.diylc.lang.LangUtil;
import org.diylc.netlist.ParsedNetlistEntry;
import org.diylc.swingframework.ButtonDialog;
public class NetlistImportDialog extends ButtonDialog {
private static final long serialVersionUID = 1L;
public static String NETLIST_DEFAULT_TYPES = "netlistDefaultTypes";
private List<Class<?>> selectedTypes;
private List<Boolean> setDefault;
private Map<Class<?>, String> componentTypeDisplay;
private List<Class<?>> allTypes;
private Map<String, String> netlistDefaultTypes;
private List<String> rawTypes;
private Map<String, List<Class<?>>> availableTypes;
private JTable table;
@SuppressWarnings("unchecked")
public NetlistImportDialog(JFrame owner, IPlugInPort plugInPort,
List<ParsedNetlistEntry> entries) {
super(owner, LangUtil.translate("Import Netlist"),
new String[] {ButtonDialog.OK, ButtonDialog.CANCEL});
this.rawTypes = entries.stream().map(x -> x.getRawType()).distinct().sorted().collect(Collectors.toList());
this.availableTypes = new HashMap<String, List<Class<?>>>();
for (ParsedNetlistEntry entry : entries) {
this.availableTypes.put(entry.getRawType(), entry.getTypeCandidates());
}
this.netlistDefaultTypes = (Map<String, String>) ConfigurationManager.getInstance()
.readObject(NETLIST_DEFAULT_TYPES, null);
this.setDefault = rawTypes.stream().map(
type -> netlistDefaultTypes != null && netlistDefaultTypes.containsKey(type))
.collect(Collectors.toList());
Map<String, List<ComponentType>> componentTypes = plugInPort.getComponentTypes();
List<ComponentType> allComponentTypes = new ArrayList<ComponentType>();
this.componentTypeDisplay = new HashMap<Class<?>, String>();
for (Map.Entry<String, List<ComponentType>> e : componentTypes.entrySet()) {
for (ComponentType type : e.getValue()) {
this.componentTypeDisplay.put(type.getInstanceClass(), e.getKey() + " - " + type.getName());
allComponentTypes.add(type);
}
}
this.allTypes = allComponentTypes.stream()
.sorted((t1, t2) -> (t1.getCategory() + " = " + t1.getName())
.compareToIgnoreCase((t2.getCategory() + " = " + t2.getName())))
.map(x -> x.getInstanceClass()).collect(Collectors.toList());
this.selectedTypes =
rawTypes.stream().map(type -> getDefaultType(type)).collect(Collectors.toList());
setPreferredSize(new Dimension(600, 400));
layoutGui();
}
private Class<?> getDefaultType(String rawType) {
if (this.netlistDefaultTypes != null
&& this.netlistDefaultTypes.containsKey(rawType)) {
Optional<Class<?>> first = this.allTypes.stream()
.filter(
e -> e.getCanonicalName().equals(this.netlistDefaultTypes.get(rawType)))
.findFirst();
if (first.isPresent())
return first.get();
}
List<Class<?>> list = this.availableTypes.get(rawType);
return list == null || list.isEmpty() ? null : list.get(0);
}
public Map<String, Class<?>> getResults() {
Map<String, Class<?>> result = new HashMap<String, Class<?>>();
for (int i = 0; i < rawTypes.size(); i++)
result.put(rawTypes.get(i), selectedTypes.get(i));
return result;
}
@Override
protected JComponent getMainComponent() {
JScrollPane scrollPane = new JScrollPane(getTable());
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
return scrollPane;
}
@SuppressWarnings("unchecked")
@Override
public void setVisible(boolean b) {
super.setVisible(b);
// hiding, store changes in config
if (!b && OK.equals(getSelectedButtonCaption())) {
netlistDefaultTypes = (Map<String, String>) ConfigurationManager.getInstance()
.readObject(NETLIST_DEFAULT_TYPES, null);
if (netlistDefaultTypes == null)
netlistDefaultTypes = new HashMap<String, String>();
for (int i = 0; i < rawTypes.size(); i++)
if (setDefault.get(i))
netlistDefaultTypes.put(rawTypes.get(i),
selectedTypes.get(i).getCanonicalName());
else
netlistDefaultTypes.remove(rawTypes.get(i));
ConfigurationManager.getInstance().writeValue(NETLIST_DEFAULT_TYPES, netlistDefaultTypes);
}
}
public JTable getTable() {
if (table == null) {
table = new JTable(new NetlistTableModel());
table.setFillsViewportHeight(true);
JComboBox<Class<?>> comboBox = new JComboBox<Class<?>>();
comboBox.setRenderer(new TypeListCellRenderer());
table.setDefaultRenderer(Class.class, new TypeTableCellRenderer());
table.setDefaultEditor(Class.class, new TypeCellEditor(comboBox));
resizeColumnWidth(table);
}
return table;
}
public void resizeColumnWidth(JTable table) {
final TableColumnModel columnModel = table.getColumnModel();
for (int column = 0; column < table.getColumnCount(); column++) {
int width = 48; // Min width
for (int row = 0; row < table.getRowCount(); row++) {
TableCellRenderer renderer = table.getCellRenderer(row, column);
Component comp = table.prepareRenderer(renderer, row, column);
width = Math.max(comp.getPreferredSize().width + 1, width);
}
if (width > 300)
width = 300;
columnModel.getColumn(column).setPreferredWidth(width);
}
}
class NetlistTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
@Override
public int getRowCount() {
return rawTypes.size();
}
@Override
public int getColumnCount() {
return 3;
}
@Override
public String getColumnName(int column) {
switch (column) {
case 0:
return "Imported Type";
case 1:
return "DIYLC Component Type";
case 2:
return "Default";
}
return null;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return String.class;
case 1:
return Class.class;
case 2:
return Boolean.class;
}
return null;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex >= 1;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return rawTypes.get(rowIndex);
case 1:
return selectedTypes.get(rowIndex);
case 2:
return setDefault.get(rowIndex);
}
return null;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
switch (columnIndex) {
case 1:
selectedTypes.set(rowIndex, (Class<?>) aValue);
break;
case 2:
setDefault.set(rowIndex, (Boolean) aValue);
break;
}
}
}
class TypeListCellRenderer extends JLabel implements ListCellRenderer<Class<?>> {
private static final long serialVersionUID = 1L;
@Override
public Component getListCellRendererComponent(JList<? extends Class<?>> list, Class<?> value,
int index, boolean isSelected, boolean cellHasFocus) {
if (value == null)
setText("<html><i>Undefined - skip this component</i></html>");
else
setText(componentTypeDisplay.get(value));
return this;
}
}
class TypeTableCellRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, column);
if (value == null)
label.setText("<html><i>Undefined - skip this component</i></html>");
else
label.setText(componentTypeDisplay.get(value));
return label;
}
}
class TypeCellEditor extends DefaultCellEditor {
private static final long serialVersionUID = 1L;
public TypeCellEditor(JComboBox<Class<?>> comboBox) {
super(comboBox);
}
@SuppressWarnings("unchecked")
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column) {
JComboBox<Class<?>> comboBox = (JComboBox<Class<?>>) super.getTableCellEditorComponent(table,
value, isSelected, row, column);
comboBox.removeAllItems();
List<Class<?>> showTypes = availableTypes.get(rawTypes.get(row));
if (showTypes == null || showTypes.isEmpty())
showTypes = allTypes;
comboBox.addItem(null);
for (Class<?> c : showTypes) {
comboBox.addItem(c);
}
comboBox.setSelectedItem(selectedTypes.get(row));
return comboBox;
}
}
}