mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 17:22:09 +10:00
Added 'File' -> 'Import Netlist' option that can import components from
a Tango PCB file
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user