From 37b1d1dbd97f6e4e75382390a08287e62256caba Mon Sep 17 00:00:00 2001 From: Bane Stojkovic Date: Sun, 23 Oct 2022 22:09:49 +0200 Subject: [PATCH] Cleanup code, refactor presenter --- .../src/org/diylc/common/IPlugInPort.java | 7 - .../org/diylc/netlist/NetlistAnalyzer.java | 215 ------- .../src/org/diylc/netlist/NetlistBuilder.java | 171 +++++- .../diylc/presenter/BuildingBlockManager.java | 216 +++++++ .../src/org/diylc/presenter/Presenter.java | 580 +----------------- .../org/diylc/presenter/VariantManager.java | 258 ++++++++ .../diylc-core/src/org/diylc/utils/Pair.java | 1 + .../src/org/diylc/utils/ReflectionUtils.java | 91 +++ .../diylc/netlist/GuitarDiagramAnalyzer.java | 2 + 9 files changed, 756 insertions(+), 785 deletions(-) create mode 100644 diylc/diylc-core/src/org/diylc/presenter/BuildingBlockManager.java create mode 100644 diylc/diylc-core/src/org/diylc/presenter/VariantManager.java create mode 100644 diylc/diylc-core/src/org/diylc/utils/ReflectionUtils.java diff --git a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java index cbe2d61b..3f566743 100644 --- a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java +++ b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java @@ -313,13 +313,6 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP */ void setNewComponentTypeSlot(ComponentType componentType, Template template, boolean forceInstatiate); - /** - * Changes default size notation, true for metric, false for imperial. - * - * @param isMetric - */ - void setMetric(boolean isMetric); - /** * Locks or unlocks the specified layer. All components within +- 0.5 range will be affected by * the change as well. diff --git a/diylc/diylc-core/src/org/diylc/netlist/NetlistAnalyzer.java b/diylc/diylc-core/src/org/diylc/netlist/NetlistAnalyzer.java index 158c5104..51f426b8 100644 --- a/diylc/diylc-core/src/org/diylc/netlist/NetlistAnalyzer.java +++ b/diylc/diylc-core/src/org/diylc/netlist/NetlistAnalyzer.java @@ -51,15 +51,6 @@ public abstract class NetlistAnalyzer { Tree tree = new Tree(TreeConnectionType.Parallel); connectNodes(netlist, nodeA, nodeB, tree.getChildren(), new Tree(TreeConnectionType.Series), new HashSet()); - // System.out.println(netlist.getSwitchSetup()); - // System.out.println(tree); - // - // System.out.println("opposite:"); - // Tree tree1 = new Tree(TreeConnectionType.Parallel); - // connectNodes(netlist, nodeB, nodeA, tree1.getChildren(), new Tree(TreeConnectionType.Series), - // new HashSet()); - // System.out.println(tree1); - return tree; } @@ -112,7 +103,6 @@ public abstract class NetlistAnalyzer { if (newConcurrentPaths.size() == 0) return; - if (newConcurrentPaths.size() == 1) { if (newConcurrentPaths.get(0).getConnectionType() == TreeConnectionType.Series) { currentPath.getChildren().clear(); @@ -214,45 +204,6 @@ public abstract class NetlistAnalyzer { paths.addAll(unmerged); } } -// -// protected void findAllPaths(Netlist netlist, Node nodeA, Node nodeB, List currentPath, -// List> allPaths, Set visited) { -// if (nodeA == nodeB) { -// allPaths.add(currentPath); -// return; -// } -// -// // System.out.println("Finding path between " + nodeA + " and " + nodeB); -// -// Group groupA = findGroup(netlist, nodeA); -// -// if (groupA == null) -// return; -// -// if (groupA.getNodes().contains(nodeB)) { -// allPaths.add(currentPath); -// return; -// } -// -// for (Node n : groupA.getNodes()) { -// IDIYComponent c = n.getComponent(); -// for (int i = 0; i < c.getControlPointCount(); i++) { -// if (i != n.getPointIndex() && c.getInternalLinkName(i, n.getPointIndex()) != null) { -// TreeLeaf l = new TreeLeaf(c, i, n.getPointIndex()); -// Node newNodeA = new Node(c, i); -// if (!visited.contains(newNodeA)) { -// List newCurrentPath = new ArrayList(currentPath); -// if (!currentPath.contains(l)) -// newCurrentPath.add(l); -// Set newVisited = new HashSet(visited); -// newVisited.add(nodeA); -// newVisited.add(newNodeA); -// findAllPaths(netlist, newNodeA, nodeB, newCurrentPath, allPaths, newVisited); -// } -// } -// } -// } -// } protected Group findGroup(Netlist netlist, Node node) { for (Group g : netlist.getGroups()) @@ -261,63 +212,6 @@ public abstract class NetlistAnalyzer { return null; } -// protected List trace(Set typeNames, String nodeName, Netlist netlist) { -// List res = new ArrayList(); -// for (Group g : netlist.getGroups()) { -// for (Node n : g.getNodes()) { -// if (typeNames.contains(n.getComponent().getClass().getCanonicalName()) -// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) { -// res.add(g); -// break; -// } -// } -// } -// return res; -// } - -// protected List find(Set typeNames, String nodeName, Group group) { -// List res = new ArrayList(); -// -// for (Node n : group.getNodes()) { -// if (typeNames.contains(n.getComponent().getClass().getCanonicalName()) -// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) { -// res.add(n); -// } -// } -// -// return res; -// } - -// protected List findGroups(Set typeNames, String nodeName, Netlist netlist) { -// List res = new ArrayList(); -// for (Group g : netlist.getGroups()) { -// for (Node n : g.getNodes()) { -// if (typeNames.contains(n.getComponent().getClass().getCanonicalName()) -// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) { -// res.add(g); -// break; -// } -// } -// } -// return res; -// } - -// protected List findGroups(Set typeNames, String nodeName, Netlist netlist, -// Collection> belongTo) { -// List res = new ArrayList(); -// for (Group g : netlist.getGroups()) { -// for (Node n : g.getNodes()) { -// if ((belongTo == null || belongTo.contains(n.getComponent())) -// && (typeNames.contains(n.getComponent().getClass().getCanonicalName())) -// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) { -// res.add(g); -// break; -// } -// } -// } -// return res; -// } - protected List find(Set typeNames, String nodeName, Netlist netlist) { List res = new ArrayList(); for (Group g : netlist.getGroups()) { @@ -331,68 +225,6 @@ public abstract class NetlistAnalyzer { return res; } -// protected List find(Set typeNames, String nodeName, Netlist netlist, List inGroupWith) { -// List res = new ArrayList(); -// for (Group g : netlist.getGroups()) { -// -// boolean inGroup; -// if (inGroupWith == null) { -// inGroup = true; -// } else { -// inGroup = true; -// for (Node n1 : inGroupWith) -// if (!g.getNodes().contains(n1)) { -// inGroup = false; -// break; -// } -// } -// -// for (Node n : g.getNodes()) { -// if (inGroup && typeNames.contains(n.getComponent().getClass().getCanonicalName()) -// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) { -// res.add(n); -// } -// } -// } -// return res; -// } - -// protected List find(Set typeNames, String nodeName, Netlist netlist, -// Collection> belongTo) { -// List res = new ArrayList(); -// for (Group g : netlist.getGroups()) { -// -// for (Node n : g.getNodes()) { -// if ((belongTo == null || belongTo.contains(n.getComponent())) -// && typeNames.contains(n.getComponent().getClass().getCanonicalName()) -// && (nodeName == null || n.getDisplayName().equalsIgnoreCase(nodeName))) { -// res.add(n); -// } -// } -// } -// return res; -// } - -// protected boolean allMatch(Collection nodes, String name) { -// for (Node n : nodes) -// if (!n.getDisplayName().equalsIgnoreCase(name)) -// return false; -// -// return true; -// } - -// protected boolean allComponentsMatch(Collection nodes, Set> components) { -// Set> extracted = extractComponents(nodes); -// return extracted.containsAll(components); -// } -// -// protected Set> extractComponents(Collection nodes) { -// Set> components = new HashSet>(); -// for (Node n : nodes) -// components.add(n.getComponent()); -// return components; -// } - protected String extractName(IDIYComponent c) { return c.getName() + " " + c.getValueForDisplay(); } @@ -423,53 +255,6 @@ public abstract class NetlistAnalyzer { return -1; } -// protected List extractNames(Collection> components) { -// List names = new ArrayList(); -// for (IDIYComponent c : components) -// names.add(c.getName() + " " + c.getValueForDisplay()); -// Collections.sort(names); -// return names; -// } -// -// protected Netlist simplify(Netlist netlist, Set nodesToMerge, Collection nodesToPurge) { -// Netlist res = new Netlist(); -// res.getSwitchSetup().addAll(netlist.getSwitchSetup()); -// -// Group merged = new Group(); -// -// // merge -// for (Group g : netlist.getGroups()) { -// boolean needsMerging = false; -// for (Node n : nodesToMerge) { -// if (g.getNodes().contains(n)) { -// needsMerging = true; -// break; -// } -// } -// if (needsMerging) { -// for (Node n : g.getNodes()) { -// if (!nodesToMerge.contains(n)) -// merged.getNodes().add(n); -// } -// } else { -// res.getGroups().add(g.clone()); -// } -// } -// -// if (!merged.getNodes().isEmpty()) -// res.getGroups().add(merged); -// -// // purge -// for (Group g : res.getGroups()) { -// g.getNodes().removeAll(nodesToPurge); -// } -// -// System.out.println("Before:\n" + netlist); -// System.out.println("After:\n" + res); -// -// return res; -// } -// protected boolean intersect(List groups, Node node) { for (Group g : groups) if (g.getNodes().contains(node)) diff --git a/diylc/diylc-core/src/org/diylc/netlist/NetlistBuilder.java b/diylc/diylc-core/src/org/diylc/netlist/NetlistBuilder.java index f45233e3..81afd694 100644 --- a/diylc/diylc-core/src/org/diylc/netlist/NetlistBuilder.java +++ b/diylc/diylc-core/src/org/diylc/netlist/NetlistBuilder.java @@ -21,14 +21,22 @@ import java.awt.geom.Area; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import java.util.stream.Collectors; +import org.diylc.common.ComponentType; +import org.diylc.core.IContinuity; import org.diylc.core.IDIYComponent; +import org.diylc.core.ISwitch; +import org.diylc.core.Project; +import org.diylc.lang.LangUtil; import org.diylc.netlist.ContinuityGraph.ContinuityNode; +import org.diylc.presenter.ComponentProcessor; import org.diylc.presenter.Connection; import org.diylc.utils.RTree; import com.google.common.graph.GraphBuilder; @@ -40,6 +48,121 @@ public class NetlistBuilder { public static final float eps = 4; // consider any nodes closer than this as connected + private static final int MAX_SWITCH_COMBINATIONS = 64; + + private static final String MAX_SWITCH_COMBINATIONS_ERROR = LangUtil + .translate("Maximum number of switching combinations exceeded. Allowed: %s, actual: %s"); + + @SuppressWarnings("unchecked") + public static List extractNetlists(boolean includeSwitches, Project project, List continuityAreas) + throws NetlistException { + Map result = new HashMap(); + List nodes = new ArrayList(); + + List switches = new ArrayList(); + + for (IDIYComponent c : project.getComponents()) { + ComponentType type = ComponentProcessor.getInstance() + .extractComponentTypeFrom((Class>) c.getClass()); + + // extract nodes + if (!(c instanceof IContinuity)) { + for (int i = 0; i < c.getControlPointCount(); i++) { + String nodeName = c.getControlPointNodeName(i); + if (nodeName != null + && (!includeSwitches || !ISwitch.class.isAssignableFrom(type.getInstanceClass()))) { + nodes.add(new Node(c, i)); + } + } + } + + // extract switches + if (includeSwitches && ISwitch.class.isAssignableFrom(type.getInstanceClass())) + switches.add((ISwitch) c); + } + + // save us the trouble + if (nodes.isEmpty()) + return null; + + // if there are no switches, make one with 1 position so we get 1 result back + if (switches.isEmpty()) + switches.add(new ISwitch() { + + @Override + public String getPositionName(int position) { + return "Default"; + } + + @Override + public int getPositionCount() { + return 1; + } + + @Override + public boolean arePointsConnected(int index1, int index2, int position) { + return false; + } + }); + + // construct all possible combinations + int[] positions = new int[switches.size()]; + for (int i = 0; i < switches.size(); i++) + positions[i] = 0; + + int i = switches.size() - 1; + + int totalSwitchCombinations = + switches.stream().map(sw -> sw.getPositionCount()).reduce(1, (a, b) -> a * b); + + if (totalSwitchCombinations > MAX_SWITCH_COMBINATIONS) { + throw new NetlistException(String.format(MAX_SWITCH_COMBINATIONS_ERROR, + MAX_SWITCH_COMBINATIONS, totalSwitchCombinations)); + } + + while (i >= 0) { + // process the current combination + Map switchPositions = new HashMap(); + List posList = new ArrayList(); + for (int j = 0; j < positions.length; j++) { + switchPositions.put(switches.get(j), positions[j]); + posList.add(new Position(switches.get(j), positions[j])); + } + List connections = getConnections(project, switchPositions); + + Netlist netlist = NetlistBuilder.buildNetlist(project.getComponents(), nodes, + continuityAreas, connections); + + // merge graphs that are effectively the same + if (result.containsKey(netlist)) { + result.get(netlist).getSwitchSetup().add(new SwitchSetup(posList)); + } else { + netlist.getSwitchSetup().add(new SwitchSetup(posList)); + result.put(netlist, netlist); + } + + // find the next combination if possible + if (positions[i] < switches.get(i).getPositionCount() - 1) { + positions[i]++; + } else { + while (i >= 0 && positions[i] == switches.get(i).getPositionCount() - 1) + i--; + if (i >= 0) { + positions[i]++; + for (int j = i + 1; j < positions.length; j++) + positions[j] = 0; + i = switches.size() - 1; + } + } + } + + // sort everything alphabetically + List netlists = new ArrayList(result.keySet()); + Collections.sort(netlists); + + return netlists; + } + public static Netlist buildNetlist(List> components, Collection nodes, Collection continuityAreas, Collection connections) { ImmutableGraph graph = buildGraph(nodes, continuityAreas, connections); @@ -75,17 +198,19 @@ public class NetlistBuilder { return netlist; } - - public static ContinuityGraph buildContinuityGraph(Collection continuityAreas, Collection connections) { - ImmutableGraph graph = buildGraph(new ArrayList(), continuityAreas, connections); + + public static ContinuityGraph buildContinuityGraph(Collection continuityAreas, + Collection connections) { + ImmutableGraph graph = + buildGraph(new ArrayList(), continuityAreas, connections); Traverser traverser = Traverser.forGraph(graph); Set visited = new HashSet(); ProjectGraphNode[] nodeArr = graph.nodes().toArray(new ProjectGraphNode[0]); - + int groupId = 1; - + RTree groupTree = new RTree(); Map> areaGroupMap = new HashMap>(); @@ -97,7 +222,7 @@ public class NetlistBuilder { if (i == graph.nodes().size()) break; - + final int finalGroupId = groupId; List areaList = new ArrayList(); @@ -178,7 +303,7 @@ public class NetlistBuilder { for (Area area : continuityAreas) { ProjectGraphNode areaNode = new ProjectGraphNode(area); - builder.addNode(areaNode); + builder.addNode(areaNode); ProjectGraphNode[] nodeArr = nodeTree.search(area).stream() .filter(graphNode -> area.contains(graphNode.getPoint()) @@ -206,11 +331,39 @@ public class NetlistBuilder { }).forEach(graphNode -> { builder.putEdge(graphNode, areaNode); }); - + areaTree.insert(area, areaNode); } - return builder.build(); + return builder.build(); + } + + @SuppressWarnings({"unchecked", "unlikely-arg-type"}) + private static List getConnections(Project project, Map switchPositions) { + Set connections = new TreeSet(); + + for (IDIYComponent c : project.getComponents()) { + ComponentType type = + ComponentProcessor.getInstance().extractComponentTypeFrom((Class>) c.getClass()); + // handle direct connections + if (c instanceof IContinuity) { + for (int i = 0; i < c.getControlPointCount() - 1; i++) + for (int j = i + 1; j < c.getControlPointCount(); j++) + if (((IContinuity) c).arePointsConnected(i, j)) + connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j))); + } + // handle switches + if (ISwitch.class.isAssignableFrom(type.getInstanceClass()) && switchPositions.containsKey(c)) { + int position = switchPositions.get(c); + ISwitch s = (ISwitch) c; + for (int i = 0; i < c.getControlPointCount() - 1; i++) + for (int j = i + 1; j < c.getControlPointCount(); j++) + if (s.arePointsConnected(i, j, position)) + connections.add(new Connection(c.getControlPoint(i), c.getControlPoint(j))); + } + } + + return new ArrayList(connections); } private static Point2D snapToEps(Point2D point, double eps) { diff --git a/diylc/diylc-core/src/org/diylc/presenter/BuildingBlockManager.java b/diylc/diylc-core/src/org/diylc/presenter/BuildingBlockManager.java new file mode 100644 index 00000000..b3f25a5a --- /dev/null +++ b/diylc/diylc-core/src/org/diylc/presenter/BuildingBlockManager.java @@ -0,0 +1,216 @@ +/* + * + * l * 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 + * . + */ +package org.diylc.presenter; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.log4j.Logger; +import org.diylc.appframework.miscutils.IConfigurationManager; +import org.diylc.common.BuildingBlockPackage; +import org.diylc.common.IBlockProcessor; +import org.diylc.common.IBlockProcessor.InvalidBlockException; +import org.diylc.common.IPlugInPort; +import org.diylc.core.IDIYComponent; +import org.diylc.serialization.ProjectFileManager; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; +import com.thoughtworks.xstream.security.AnyTypePermission; + +public class BuildingBlockManager { + + private static final String BLOCKS_FILE_NAME = "blocks.xml"; + + private static final Logger LOG = Logger.getLogger(VariantManager.class); + + private IConfigurationManager configManager; + private XStream xStream; + private InstantiationManager instantiationManager; + + public BuildingBlockManager(IConfigurationManager configManager, XStream xStream, + InstantiationManager instantiationManager) { + super(); + this.configManager = configManager; + this.xStream = xStream; + this.instantiationManager = instantiationManager; + } + + @SuppressWarnings("unchecked") + public void importDefaultBlocks() { + // import default templates from variants.xml file only if we didn't do it already + if (!configManager.readBoolean(IPlugInPort.DEFAULT_BLOCKS_IMPORTED_KEY, false)) { + try { + URL resource = Presenter.class.getResource(BLOCKS_FILE_NAME); + if (resource != null) { + BufferedInputStream in = new BufferedInputStream(resource.openStream()); + Map>> defaults = + (Map>>) ProjectFileManager.xStreamSerializer + .fromXML(in); + in.close(); + + Map>> blocksMap = + (Map>>) configManager.readObject(IPlugInPort.BLOCKS_KEY, + null); + if (blocksMap == null) + blocksMap = new HashMap>>(); + + // merge default blocks with user's + for (Map.Entry>> entry : defaults.entrySet()) { + if (!blocksMap.containsKey(entry.getKey())) + blocksMap.put(entry.getKey(), entry.getValue()); + } + + // update templates and a flag marking that we imported them + configManager.writeValue(IPlugInPort.DEFAULT_BLOCKS_IMPORTED_KEY, true); + configManager.writeValue(IPlugInPort.BLOCKS_KEY, blocksMap); + LOG.info(String.format("Imported %d default building blocks", + defaults == null ? 0 : defaults.size())); + } + } catch (Exception e) { + LOG.error("Could not load default blocks", e); + } + } + } + + @SuppressWarnings("unchecked") + public int importBlocks(String fileName) throws IOException { + LOG.debug(String.format("importBlocks(%s)", fileName)); + BufferedInputStream in = new BufferedInputStream(new FileInputStream(fileName)); + + BuildingBlockPackage pkg = (BuildingBlockPackage) xStream.fromXML(in); + + in.close(); + + if (pkg == null || pkg.getBlocks().isEmpty()) + return 0; + + Map>> blocks = + (Map>>) configManager.readObject(IBlockProcessor.BLOCKS_KEY, null); + if (blocks == null) { + blocks = new HashMap>>(); + } + + for (Map.Entry>> entry : pkg.getBlocks().entrySet()) { + blocks.put(entry.getKey() + " [" + pkg.getOwner() + "]", entry.getValue()); + } + + configManager.writeValue(IBlockProcessor.BLOCKS_KEY, blocks); + + LOG.info(String.format("Loaded building blocks for %d components", pkg.getBlocks().size())); + + return pkg.getBlocks().size(); + } + + @SuppressWarnings("unchecked") + public List> loadBlock(String blockName, + List> existingComponents) throws InvalidBlockException { + LOG.debug(String.format("loadBlock(%s)", blockName)); + Map>> blocks = (Map>>) configManager + .readObject(IPlugInPort.BLOCKS_KEY, null); + if (blocks != null) { + Collection> components = blocks.get(blockName); + if (components == null) + throw new InvalidBlockException(); + // clear potential control point every time! + instantiationManager.setPotentialControlPoint(null); + // clone components + List> clones = new ArrayList>(); + List> testComponents = new ArrayList>(existingComponents); + for (IDIYComponent c : components) + try { + IDIYComponent clone = c.clone(); + clone.setName(instantiationManager.createUniqueName(ComponentProcessor.getInstance() + .extractComponentTypeFrom((Class>) clone.getClass()), + testComponents)); + testComponents.add(clone); + clones.add(clone); + } catch (CloneNotSupportedException e) { + LOG.error("Could not clone component: " + c); + } + return clones; + } else + throw new InvalidBlockException(); + } + + @SuppressWarnings("unchecked") + public void saveSelectionAsBlock(String blockName, + Collection> selectedComponents, List> allComponents) { + LOG.debug(String.format("saveSelectionAsBlock(%s)", blockName)); + Map>> blocks = (Map>>) configManager + .readObject(IBlockProcessor.BLOCKS_KEY, null); + if (blocks == null) + blocks = new HashMap>>(); + List> blockComponents = new ArrayList>(selectedComponents); + Collections.sort(blockComponents, new Comparator>() { + + @Override + public int compare(IDIYComponent o1, IDIYComponent o2) { + return new Integer(allComponents.indexOf(o1)).compareTo(allComponents.indexOf(o2)); + } + }); + blocks.put(blockName, blockComponents); + + if (System.getProperty("org.diylc.WriteStaticBlocks", "false").equalsIgnoreCase("true")) { + Map>> defaultBlockMap = + new HashMap>>(); + // unify default and user-variants + for (Map.Entry>> entry : blocks.entrySet()) { + if (defaultBlockMap.containsKey(entry.getKey())) { + defaultBlockMap.get(entry.getKey()).addAll(entry.getValue()); + } else { + defaultBlockMap.put(entry.getKey(), entry.getValue()); + } + } + try { + BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(BLOCKS_FILE_NAME)); + XStream xStream = new XStream(new DomDriver()); + xStream.addPermission(AnyTypePermission.ANY); + xStream.toXML(defaultBlockMap, out); + out.close(); + // no more user variants + configManager.writeValue(IBlockProcessor.BLOCKS_KEY, null); + LOG.info("Saved default blocks"); + } catch (IOException e) { + LOG.error("Could not save default blocks", e); + } + } else { + configManager.writeValue(IBlockProcessor.BLOCKS_KEY, blocks); + } + } + + @SuppressWarnings("unchecked") + public void deleteBlock(String blockName) { + LOG.debug(String.format("deleteBlock(%s)", blockName)); + Map>> blocks = + (Map>>) configManager.readObject(IBlockProcessor.BLOCKS_KEY, null); + if (blocks != null) { + blocks.remove(blockName); + configManager.writeValue(IBlockProcessor.BLOCKS_KEY, blocks); + } + } +} diff --git a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java index 30e482a1..34bc1152 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java +++ b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java @@ -29,7 +29,6 @@ import java.awt.geom.Rectangle2D; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.Modifier; @@ -45,8 +44,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; import java.util.function.Supplier; import javax.swing.JOptionPane; import org.apache.log4j.Logger; @@ -57,7 +54,6 @@ import org.diylc.appframework.simplemq.MessageDispatcher; import org.diylc.appframework.update.Version; import org.diylc.appframework.update.VersionNumber; import org.diylc.clipboard.ComponentTransferable; -import org.diylc.common.BuildingBlockPackage; import org.diylc.common.ComponentType; import org.diylc.common.DrawOption; import org.diylc.common.EventType; @@ -69,11 +65,8 @@ import org.diylc.common.IPlugIn; import org.diylc.common.IPlugInPort; import org.diylc.common.IProjectEditor; import org.diylc.common.PropertyWrapper; -import org.diylc.common.VariantPackage; import org.diylc.core.ExpansionMode; -import org.diylc.core.IContinuity; import org.diylc.core.IDIYComponent; -import org.diylc.core.ISwitch; import org.diylc.core.IView; import org.diylc.core.Project; import org.diylc.core.Template; @@ -88,13 +81,11 @@ import org.diylc.netlist.Netlist; import org.diylc.netlist.NetlistAnalyzer; import org.diylc.netlist.NetlistBuilder; import org.diylc.netlist.NetlistException; -import org.diylc.netlist.Node; -import org.diylc.netlist.Position; -import org.diylc.netlist.SwitchSetup; import org.diylc.serialization.ProjectFileManager; import org.diylc.test.DIYTest; import org.diylc.test.Snapshot; import org.diylc.utils.Constants; +import org.diylc.utils.ReflectionUtils; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.security.AnyTypePermission; @@ -131,7 +122,6 @@ public class Presenter implements IPlugInPort { private static final String ERROR_NEW = LangUtil.translate("Could not create a new file. Check the log for details."); private static final String ERROR = LangUtil.translate("Error"); private static final String APPLY_ERROR = LangUtil.translate("Could not apply changes. Check the log for details."); - private static final String MAX_SWITCH_COMBINATIONS_ERROR = LangUtil.translate("Maximum number of switching combinations exceeded. Allowed: %s, actual: %s"); private static final Logger LOG = Logger.getLogger(Presenter.class); @@ -169,16 +159,11 @@ public class Presenter implements IPlugInPort { public static final int ICON_SIZE = 32; - private static final int MAX_RECENT_FILES = 20; - private static final int MAX_SWITCH_COMBINATIONS = 64; + private static final int MAX_RECENT_FILES = 20; private Project currentProject; private Map> componentTypes; - /** - * {@link List} of {@link IAutoCreator} objects that are capable of creating more components - * automatically when a component is created, e.g. Solder Pads. - */ - private List autoCreators; + // Maps component class names to ComponentType objects. private List plugIns; @@ -193,6 +178,8 @@ public class Presenter implements IPlugInPort { private DrawingManager drawingManager; private ProjectFileManager projectFileManager; private InstantiationManager instantiationManager; + private VariantManager variantManager; + private BuildingBlockManager buildingBlockManager; private Rectangle selectionRect; @@ -232,13 +219,15 @@ public class Presenter implements IPlugInPort { drawingManager = new DrawingManager(messageDispatcher, configManager); projectFileManager = new ProjectFileManager(messageDispatcher); instantiationManager = new InstantiationManager(); + variantManager = new VariantManager(configManager, projectFileManager.getXStream()); + buildingBlockManager = new BuildingBlockManager(configManager, projectFileManager.getXStream(), instantiationManager); // lockedLayers = EnumSet.noneOf(ComponentLayer.class); // visibleLayers = EnumSet.allOf(ComponentLayer.class); if (importVariantsAndBlocks) { - upgradeVariants(); - importDefaultVariants(); - importDefaultBlocks(); + variantManager.upgradeVariants(getComponentTypes()); + variantManager.importDefaultVariants(); + buildingBlockManager.importDefaultBlocks(); } } @@ -491,25 +480,6 @@ public class Presenter implements IPlugInPort { return componentTypes; } - public List getAutoCreators() { - if (autoCreators == null) { - autoCreators = new ArrayList(); - Set> classes = null; - try { - classes = Utils.getClasses("org.diylc.components.autocreate"); - for (Class clazz : classes) { - if (IAutoCreator.class.isAssignableFrom(clazz)) { - autoCreators.add((IAutoCreator) clazz.newInstance()); - LOG.debug("Loaded auto-creator: " + clazz.getName()); - } - } - } catch (Exception e) { - LOG.error("Error loading auto-creator types", e); - } - } - return autoCreators; - } - @SuppressWarnings({"unchecked"}) private boolean isComponentVisible(IDIYComponent component) { ComponentType componentType = @@ -1798,11 +1768,6 @@ public class Presenter implements IPlugInPort { configManager.writeValue(DEFAULTS_KEY_PREFIX + clazz.getName() + ":" + propertyName, value); } - @Override - public void setMetric(boolean isMetric) { - configManager.writeValue(Presenter.METRIC_KEY, isMetric); - } - @Override public void groupSelectedComponents() { LOG.info("groupSelectedComponents()"); @@ -2310,23 +2275,6 @@ public class Presenter implements IPlugInPort { return new Point2D[] {inSize, cmSize}; } - // @Override - // public Rectangle2D getSelectedAreaRect() { - // if (selectedComponents.isEmpty()) { - // return null; - // } - // Area area = new Area(); - // for (IDIYComponent component : selectedComponents) { - // Area componentArea = drawingManager.getComponentArea(component); - // if (componentArea != null) { - // area.add(componentArea); - // } else { - // LOG.warn("No area found for: " + component.getName()); - // } - // } - // return area.getBounds2D(); - // } - /** * Adds a component to the project taking z-order into account. * @@ -2351,7 +2299,7 @@ public class Presenter implements IPlugInPort { } // Check if we should auto-create something. - for (IAutoCreator creator : this.getAutoCreators()) { + for (IAutoCreator creator : ReflectionUtils.getAutoCreators()) { List> newComponents = creator.createIfNeeded(component); if (newComponents != null) { for (IDIYComponent c : newComponents) @@ -2624,108 +2572,9 @@ public class Presenter implements IPlugInPort { } } - @SuppressWarnings("unchecked") - private void importDefaultVariants() { - // import default templates from variants.xml file only if we didn't do it already - if (!configManager.readBoolean(DEFAULT_TEMPLATES_IMPORTED_KEY, false)) { - try { - URL resource = Presenter.class.getResource("variants.xml"); - if (resource != null) { - BufferedInputStream in = new BufferedInputStream(resource.openStream()); - Map> defaults = (Map>) ProjectFileManager.xStreamSerializer.fromXML(in); - in.close(); - - Map> variantMap = - (Map>) configManager.readObject(TEMPLATES_KEY, null); - if (variantMap == null) - variantMap = new HashMap>(); - - // merge default variants with user's - for (Map.Entry> entry : defaults.entrySet()) { - List