Merge branch 'master' into feature/multimeter3

This commit is contained in:
Branislav Stojkovic
2025-03-25 13:18:37 +01:00
80 changed files with 1036 additions and 864 deletions
+3
View File
@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}
+16
View File
@@ -0,0 +1,16 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="DIYLCStarter" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="org.diylc.DIYLCStarter" />
<module name="diylc-swing" />
<option name="VM_PARAMETERS" value="-Xms1024m -Xmx4096m -Dsun.java2d.uiScale=1.5 -Dorg.diylc.scriptRun=true -Dfile.encoding=UTF-8 --add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED --add-exports java.desktop/com.apple.eio=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens java.desktop/java.awt.geom=ALL-UNNAMED" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.diylc.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
-2
View File
@@ -1,2 +0,0 @@
#org.diylc.utils.Constants.CANVAS_COLOR=#005D96
#org.diylc.utils.Constants.GRID_COLOR=#FFFFFF
@@ -76,7 +76,7 @@ public abstract class AbstractCurvedComponent<T> extends AbstractTransparentComp
* @param curve * @param curve
* @param g2d * @param g2d
* @param componentState * @param componentState
* @param theme * @param drawingObserver
*/ */
protected abstract void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState, protected abstract void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState,
IDrawingObserver drawingObserver); IDrawingObserver drawingObserver);
@@ -29,10 +29,13 @@ public abstract class AbstractTransparentComponent<T> extends AbstractComponent<
public static byte MAX_ALPHA = 127; public static byte MAX_ALPHA = 127;
protected byte alpha = MAX_ALPHA; protected Byte alpha = MAX_ALPHA;
@EditableProperty @EditableProperty
public Byte getAlpha() { public Byte getAlpha() {
if (alpha == null) {
alpha = MAX_ALPHA;
}
return alpha; return alpha;
} }
@@ -0,0 +1,10 @@
package org.diylc.core;
public enum BoardUndersideDisplay {
NONE, ABOVE, BELOW, LEFT, RIGHT;
@Override
public String toString() {
return super.toString().charAt(0) + super.toString().substring(1).toLowerCase();
}
}
@@ -0,0 +1,16 @@
package org.diylc.core;
import org.diylc.core.measures.Size;
import java.awt.geom.Rectangle2D;
public interface IBoard {
Rectangle2D getBoardRectangle();
BoardUndersideDisplay getBoardUndersideDisplay();
Size getUndersideOffset();
boolean shouldExportToGerber();
}
@@ -17,6 +17,7 @@ import org.apache.log4j.Logger;
import com.bancika.gerberwriter.DataLayer; import com.bancika.gerberwriter.DataLayer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoard;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.core.IView; import org.diylc.core.IView;
import org.diylc.core.Project; import org.diylc.core.Project;
@@ -31,12 +32,15 @@ public class GerberExporter {
public static void exportGerber(String fileNameBase, Project currentProject, IView view, public static void exportGerber(String fileNameBase, Project currentProject, IView view,
Graphics2D graphics2d, String diylcVersion) { Graphics2D graphics2d, String diylcVersion) {
List<IGerberBoard> gerberBoards =
currentProject.getComponents().stream().filter(c -> c instanceof IGerberBoard)
.map(x -> (IGerberBoard) x).collect(Collectors.toList());
Map<IGerberBoard, List<IDIYComponent<?>>> boardComponentMap = List<IBoard> gerberBoards =
new HashMap<IGerberBoard, List<IDIYComponent<?>>>(); currentProject.getComponents().stream()
.filter(IBoard.class::isInstance)
.map(IBoard.class::cast)
.filter(IBoard::shouldExportToGerber).collect(Collectors.toList());
Map<IBoard, List<IDIYComponent<?>>> boardComponentMap =
new HashMap<IBoard, List<IDIYComponent<?>>>();
// DefaultGerberBoard defaultGerberBoard = new DefaultGerberBoard(); // DefaultGerberBoard defaultGerberBoard = new DefaultGerberBoard();
@@ -45,7 +49,7 @@ public class GerberExporter {
currentProject.getComponents().stream().filter(c -> c instanceof IGerberComponent) currentProject.getComponents().stream().filter(c -> c instanceof IGerberComponent)
.forEach(c -> { .forEach(c -> {
Point2D firstPoint = c.getControlPoint(0); Point2D firstPoint = c.getControlPoint(0);
IGerberBoard board = gerberBoards.stream() IBoard board = gerberBoards.stream()
.filter(b -> b.getBoardRectangle().contains(firstPoint)).findFirst().orElse(null); .filter(b -> b.getBoardRectangle().contains(firstPoint)).findFirst().orElse(null);
if (board == null) { if (board == null) {
componentsWithoutBoard.add(c); componentsWithoutBoard.add(c);
@@ -1,8 +0,0 @@
package org.diylc.core.gerber;
import java.awt.geom.Rectangle2D;
public interface IGerberBoard {
Rectangle2D getBoardRectangle();
}
@@ -125,25 +125,28 @@ public class LangUtil {
public static List<Language> getAvailableLanguages() { public static List<Language> getAvailableLanguages() {
List<Language> res = new ArrayList<Language>(); List<Language> res = new ArrayList<Language>();
List<File> files = ResourceUtils.getResourceFiles(LANG_DIR); Map<String, String> langContents = ResourceUtils.getResourceContents(LANG_DIR);
try { try {
for (File file : files) { langContents.entrySet().stream()
String key = file.getName().replaceFirst("[.][^.]+$", ""); .sorted(Map.Entry.comparingByKey())
.forEach(entry -> {
String key = entry.getKey().replaceFirst("[.][^.]+$", "");
Map<String, String> details = new HashMap<String, String>(); Map<String, String> details = new HashMap<String, String>();
try (Stream<String> stream = Files.lines( try {
Paths.get(file.getAbsolutePath()), StandardCharsets.UTF_8)) { String content = entry.getValue();
stream.forEach(s -> { String[] lines = content.split("\n");
if (s.contains("=")) { for (String line : lines) {
String[] parts = s.split("="); if (line.contains("=")) {
String[] parts = line.split("=");
if (parts.length == 2) if (parts.length == 2)
details.put(parts[0].toLowerCase().trim(), parts[1].trim()); details.put(parts[0].toLowerCase().trim(), parts[1].trim());
} }
}); }
} catch (IOException e) { } catch (Exception e) {
LOG.error("Error loading language file", e); LOG.error("Error loading language file", e);
} }
res.add(new Language(key, details)); res.add(new Language(key, details));
} });
Collections.sort(res); Collections.sort(res);
return res; return res;
} catch (Exception e) { } catch (Exception e) {
@@ -18,7 +18,6 @@
package org.diylc.presenter; package org.diylc.presenter;
import java.io.*; import java.io.*;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -42,7 +41,7 @@ import org.diylc.serialization.ProjectFileManager;
public class BuildingBlockManager { public class BuildingBlockManager {
private static final String BLOCKS_FILE_NAME = "blocks.xml"; private static final String BLOCKS_FILE_NAME = "import-defaults/blocks.xml";
private static final Logger LOG = Logger.getLogger(VariantManager.class); private static final Logger LOG = Logger.getLogger(VariantManager.class);
@@ -26,12 +26,8 @@ import java.awt.Image;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.lang.reflect.Modifier;
import java.util.Collection; import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@@ -52,6 +48,11 @@ import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.KeywordPolicy; import org.diylc.core.annotations.KeywordPolicy;
import org.diylc.lang.LangUtil; import org.diylc.lang.LangUtil;
import org.reflections.Reflections;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import static org.reflections.scanners.Scanners.TypesAnnotated;
/** /**
* Utility class with component processing methods. * Utility class with component processing methods.
@@ -68,6 +69,7 @@ public class ComponentProcessor {
private Map<String, IPropertyValidator> propertyValidatorCache; private Map<String, IPropertyValidator> propertyValidatorCache;
private Map<String, ComponentType> componentTypeMap; private Map<String, ComponentType> componentTypeMap;
private Map<String, IComponentTransformer> componentTransformerMap; private Map<String, IComponentTransformer> componentTransformerMap;
private Map<String, List<ComponentType>> componentTypes;
public static ComponentProcessor getInstance() { public static ComponentProcessor getInstance() {
if (instance == null) { if (instance == null) {
@@ -138,6 +140,10 @@ public class ComponentProcessor {
Graphics2D g2d = (Graphics2D) image.getGraphics(); Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
// g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, // g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
// RenderingHints.VALUE_STROKE_PURE); // RenderingHints.VALUE_STROKE_PURE);
componentInstance.drawIcon(g2d, Presenter.ICON_SIZE, Presenter.ICON_SIZE); componentInstance.drawIcon(g2d, Presenter.ICON_SIZE, Presenter.ICON_SIZE);
@@ -225,6 +231,50 @@ public class ComponentProcessor {
return result; return result;
} }
public Map<String, List<ComponentType>> getComponentTypes() {
if (componentTypes == null) {
LOG.info("Loading component types.");
componentTypes = new HashMap<String, List<ComponentType>>();
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.forPackage("org.diylc")
.filterInputsBy(new FilterBuilder().includePackage("org.diylc.components"))
.setScanners(TypesAnnotated));
Set<Class<?>> componentTypeClasses = null;
try {
componentTypeClasses = reflections.getTypesAnnotatedWith(ComponentDescriptor.class, false);
for (Class<?> clazz : componentTypeClasses) {
if (!Modifier.isAbstract(clazz.getModifiers()) && IDIYComponent.class.isAssignableFrom(clazz)) {
ComponentType componentType =
ComponentProcessor.getInstance().extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) clazz);
if (componentType == null)
continue;
// just to store in the cache
ComponentProcessor.getInstance().extractProperties(clazz);
List<ComponentType> nestedList;
if (componentTypes.containsKey(componentType.getCategory())) {
nestedList = componentTypes.get(componentType.getCategory());
} else {
nestedList = new ArrayList<ComponentType>();
componentTypes.put(componentType.getCategory(), nestedList);
}
nestedList.add(componentType);
}
}
for (Map.Entry<String, List<ComponentType>> e : componentTypes.entrySet()) {
LOG.debug(e.getKey() + ": " + e.getValue());
}
} catch (Exception e) {
LOG.error("Error loading component types", e);
}
}
return componentTypes;
}
/** /**
* Returns properties that have the same value for all the selected components. * Returns properties that have the same value for all the selected components.
* *
@@ -17,10 +17,7 @@
*/ */
package org.diylc.presenter; package org.diylc.presenter;
import java.io.BufferedInputStream; import java.io.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -55,16 +52,15 @@ public class DatasheetService {
private DatasheetService() {} private DatasheetService() {}
public List<String[]> loadDatasheet(Class<?> clazz) { public List<String[]> loadDatasheet(Class<?> clazz) {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
return datasheetCache.computeIfAbsent(clazz.getCanonicalName(), key -> { return datasheetCache.computeIfAbsent(clazz.getCanonicalName(), key -> {
String fileName = clazz.getSimpleName() + ".datasheet"; String fileName = clazz.getSimpleName() + ".datasheet";
LOG.info("Loading datasheet file for " + fileName); LOG.info("Loading datasheet file for " + fileName);
URL resource = classloader.getResource(fileName); InputStream inputStream = clazz.getResourceAsStream("/datasheets/" + fileName);
if (resource == null) { if (inputStream == null) {
LOG.warn("Datasheet file not found: " + fileName); LOG.warn("Datasheet file not found: " + fileName);
return null; return null;
} }
try (BufferedInputStream in = new BufferedInputStream(resource.openStream())) { try (BufferedInputStream in = new BufferedInputStream(inputStream)) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
List<String[]> types = List<String[]> types =
@@ -49,20 +49,9 @@ import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.IConfigurationManager; import org.diylc.appframework.miscutils.IConfigurationManager;
import org.diylc.appframework.simplemq.MessageDispatcher; import org.diylc.appframework.simplemq.MessageDispatcher;
import org.diylc.common.DrawOption; import org.diylc.common.*;
import org.diylc.common.EventType; import org.diylc.components.AbstractTransparentComponent;
import org.diylc.common.GridType; import org.diylc.core.*;
import org.diylc.common.IComponentFilter;
import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache;
import org.diylc.core.ComponentForRender;
import org.diylc.core.ComponentState;
import org.diylc.core.IContinuity;
import org.diylc.core.IDIYComponent;
import org.diylc.core.ILayeredComponent;
import org.diylc.core.Project;
import org.diylc.core.Theme;
import org.diylc.core.VisibilityPolicy;
import org.diylc.core.measures.Size; import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit; import org.diylc.core.measures.SizeUnit;
import org.diylc.netlist.ContinuityGraph; import org.diylc.netlist.ContinuityGraph;
@@ -78,6 +67,7 @@ import org.diylc.utils.Constants;
public class DrawingManager { public class DrawingManager {
private static final Logger LOG = Logger.getLogger(DrawingManager.class); private static final Logger LOG = Logger.getLogger(DrawingManager.class);
public static final byte MIRROR_ALPHA = 64;
public static int CONTROL_POINT_SIZE = 7; public static int CONTROL_POINT_SIZE = 7;
public static double EXTRA_SPACE = 0.25; public static double EXTRA_SPACE = 0.25;
@@ -195,38 +185,35 @@ public class DrawingManager {
G2DWrapper g2dWrapper = new G2DWrapper(g2d, zoom); G2DWrapper g2dWrapper = new G2DWrapper(g2d, zoom);
if (drawOptions.contains(DrawOption.ANTIALIASING)) { configureRenderingHints(g2d, drawOptions);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, // group components with boards that contain them
RenderingHints.VALUE_TEXT_ANTIALIAS_ON); Map<IBoard, List<IDIYComponent<?>>> boardMap = project.getComponents().stream()
} else { .filter(IBoard.class::isInstance)
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); .map(IBoard.class::cast)
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, .filter(b -> b.getBoardUndersideDisplay() != BoardUndersideDisplay.NONE)
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); .collect(Collectors.toMap(x -> x, x -> new ArrayList<IDIYComponent<?>>()));
Map<IDIYComponent<?>, Set<IBoard>> componentBoardMap = new HashMap<IDIYComponent<?>, Set<IBoard>>();
for (IBoard board : boardMap.keySet()) {
Rectangle2D boardRect = board.getBoardRectangle();
for (IDIYComponent<?> c : project.getComponents()) {
if (c == board) {
continue;
}
boolean include = true;
for (int i = 0; i < c.getControlPointCount(); i++) {
if (!boardRect.contains(c.getControlPoint(i))) {
include = false;
break;
}
}
if (include) {
boardMap.get(board).add(c);
componentBoardMap.computeIfAbsent(c, key -> new HashSet<IBoard>()).add(board);
}
} }
if (configManager.readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
// RenderingHints.VALUE_STROKE_PURE);
} else {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
} }
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
// AffineTransform initialTx = g2d.getTransform(); // AffineTransform initialTx = g2d.getTransform();
Dimension canvasDimension = Dimension canvasDimension =
@@ -297,7 +284,7 @@ public class DrawingManager {
// drawn in the same state. // drawn in the same state.
boolean trackArea = lastDrawnStateMap.get(component) != state; boolean trackArea = lastDrawnStateMap.get(component) != state;
synchronized (g2d) { synchronized (this) {
g2dWrapper.startedDrawingComponent(i); g2dWrapper.startedDrawingComponent(i);
if (!trackArea) { if (!trackArea) {
g2dWrapper.stopTracking(); g2dWrapper.stopTracking();
@@ -312,11 +299,7 @@ public class DrawingManager {
long componentStart = System.nanoTime(); long componentStart = System.nanoTime();
try { try {
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache drawComponent(project, drawOptions, scaleFactor, visibleRect, component, g2dWrapper, state, zoom, i, outlineMode);
DrawingCache.Instance.draw(component, g2dWrapper, state,
drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, scaleFactor, i, visibleRect);
else // go straight to the wrapper
component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
if (g2dWrapper.isTrackingContinuityArea()) { if (g2dWrapper.isTrackingContinuityArea()) {
LOG.info("Component " + component.getName() + " of type " LOG.info("Component " + component.getName() + " of type "
@@ -349,6 +332,29 @@ public class DrawingManager {
componentAreaMap.put(component, area); componentAreaMap.put(component, area);
lastDrawnStateMap.put(component, state); lastDrawnStateMap.put(component, state);
} }
// Mirror components that belong to boards that need to be mirrored
if (componentBoardMap.containsKey(component)) {
@SuppressWarnings("unchecked")
ComponentType componentType = ComponentProcessor.getInstance()
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
if (componentType.getTransformer() != null) {
Set<IBoard> boards = componentBoardMap.get(component);
for (IBoard board : boards) {
drawMirroredComponent(project, board, component, componentType, g2dWrapper, state, outlineMode);
}
}
}
// if a component itself is a board that needs to be mirrored, do it
if (IBoard.class.isInstance(component) && componentBoardMap.values().stream()
.anyMatch(boards -> boards.contains(component))) {
ComponentType componentType = ComponentProcessor.getInstance()
.extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) component.getClass());
if (componentType.getTransformer() != null) {
drawMirroredComponent(project, (IBoard) component, component, componentType, g2dWrapper, state, outlineMode);
}
}
} }
} }
@@ -510,6 +516,86 @@ public class DrawingManager {
return failedComponents; return failedComponents;
} }
private static void drawMirroredComponent(Project project, IBoard board, IDIYComponent<?> component,
ComponentType componentType, G2DWrapper g2dWrapper, ComponentState state, boolean outlineMode) {
double offset = board.getUndersideOffset().convertToPixels();
Rectangle2D boardRectangle = board.getBoardRectangle();
try {
IDIYComponent<?> clonedComponent = component.clone();
int direction = 0;
Point2D pivotPoint = new Point2D.Double();
switch (board.getBoardUndersideDisplay()) {
case ABOVE:
direction = IComponentTransformer.VERTICAL;
pivotPoint.setLocation(boardRectangle.getMinX(), boardRectangle.getMinY() - offset / 2);
break;
case BELOW:
direction = IComponentTransformer.VERTICAL;
pivotPoint.setLocation(boardRectangle.getMinX(), boardRectangle.getMaxY() + offset / 2);
break;
case LEFT:
direction = IComponentTransformer.HORIZONTAL;
pivotPoint.setLocation(boardRectangle.getMinX() - offset / 2, boardRectangle.getMinY());
break;
case RIGHT:
direction = IComponentTransformer.HORIZONTAL;
pivotPoint.setLocation(boardRectangle.getMaxX() + offset / 2, boardRectangle.getMinY());
break;
}
componentType.getTransformer().mirror(clonedComponent, pivotPoint, direction);
if (AbstractTransparentComponent.class.isInstance(clonedComponent)) {
AbstractTransparentComponent<?> transparentComponent = (AbstractTransparentComponent<?>) clonedComponent;
transparentComponent.setAlpha(MIRROR_ALPHA);
}
clonedComponent.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
private static void drawComponent(Project project, Set<DrawOption> drawOptions, Double scaleFactor, Rectangle2D visibleRect, IDIYComponent<?> component, G2DWrapper g2dWrapper, ComponentState state, double zoom, int i, boolean outlineMode) {
if (drawOptions.contains(DrawOption.ENABLE_CACHING)) // go through the DrawingCache
DrawingCache.Instance.draw(component, g2dWrapper, state,
drawOptions.contains(DrawOption.OUTLINE_MODE), project, zoom, scaleFactor, i, visibleRect);
else // go straight to the wrapper
component.draw(g2dWrapper, state, outlineMode, project, g2dWrapper);
}
private void configureRenderingHints(Graphics2D g2d, Set<DrawOption> drawOptions) {
if (drawOptions.contains(DrawOption.ANTIALIASING)) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
} else {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
}
if (configManager.readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
// g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
// RenderingHints.VALUE_STROKE_PURE);
} else {
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
}
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
}
private double zoomCached = 0; private double zoomCached = 0;
private Dimension canvasDimensionCached; private Dimension canvasDimensionCached;
private double extraSpaceCached; private double extraSpaceCached;
@@ -78,7 +78,6 @@ import org.diylc.core.Project;
import org.diylc.core.Template; import org.diylc.core.Template;
import org.diylc.core.Theme; import org.diylc.core.Theme;
import org.diylc.core.VisibilityPolicy; import org.diylc.core.VisibilityPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.IAutoCreator; import org.diylc.core.annotations.IAutoCreator;
import org.diylc.core.gerber.GerberExporter; import org.diylc.core.gerber.GerberExporter;
import org.diylc.core.measures.Size; import org.diylc.core.measures.Size;
@@ -94,11 +93,6 @@ import org.diylc.test.DIYTest;
import org.diylc.test.Snapshot; import org.diylc.test.Snapshot;
import org.diylc.utils.Constants; import org.diylc.utils.Constants;
import org.diylc.utils.ReflectionUtils; import org.diylc.utils.ReflectionUtils;
import org.reflections.Reflections;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import static org.reflections.scanners.Scanners.TypesAnnotated;
/** /**
* The main presenter class, contains core app logic and drawing routines. * The main presenter class, contains core app logic and drawing routines.
@@ -135,6 +129,9 @@ public class Presenter implements IPlugInPort, IConfigListener {
private static final Logger LOG = Logger.getLogger(Presenter.class); private static final Logger LOG = Logger.getLogger(Presenter.class);
public static final Double[] ZOOM_LEVELS =
{0.25d, 0.3333d, 0.5d, 0.6667d, 0.75d, 1d, 1.25d, 1.5d, 2d, 2.5d, 3d};
public static VersionNumber CURRENT_VERSION = null; public static VersionNumber CURRENT_VERSION = null;
private static List<Version> RECENT_VERSIONS = null; private static List<Version> RECENT_VERSIONS = null;
@@ -147,7 +144,6 @@ public class Presenter implements IPlugInPort, IConfigListener {
private static final int MAX_RECENT_FILES = 20; private static final int MAX_RECENT_FILES = 20;
private Project currentProject; private Project currentProject;
private Map<String, List<ComponentType>> componentTypes;
// Maps component class names to ComponentType objects. // Maps component class names to ComponentType objects.
private List<IPlugIn> plugIns; private List<IPlugIn> plugIns;
@@ -242,7 +238,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
@Override @Override
public java.lang.Double[] getAvailableZoomLevels() { public java.lang.Double[] getAvailableZoomLevels() {
return new java.lang.Double[] {0.25d, 0.3333d, 0.5d, 0.6667d, 0.75d, 1d, 1.25d, 1.5d, 2d, 2.5d, 3d}; return ZOOM_LEVELS;
} }
@Override @Override
@@ -424,47 +420,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Map<String, List<ComponentType>> getComponentTypes() { public Map<String, List<ComponentType>> getComponentTypes() {
if (componentTypes == null) { return ComponentProcessor.getInstance().getComponentTypes();
LOG.info("Loading component types.");
componentTypes = new HashMap<String, List<ComponentType>>();
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.forPackage("org.diylc")
.filterInputsBy(new FilterBuilder().includePackage("org.diylc.components"))
.setScanners(TypesAnnotated));
Set<Class<?>> componentTypeClasses = null;
try {
componentTypeClasses = reflections.getTypesAnnotatedWith(ComponentDescriptor.class, false);
for (Class<?> clazz : componentTypeClasses) {
if (!Modifier.isAbstract(clazz.getModifiers()) && IDIYComponent.class.isAssignableFrom(clazz)) {
ComponentType componentType =
ComponentProcessor.getInstance().extractComponentTypeFrom((Class<? extends IDIYComponent<?>>) clazz);
if (componentType == null)
continue;
// just to store in the cache
ComponentProcessor.getInstance().extractProperties(clazz);
List<ComponentType> nestedList;
if (componentTypes.containsKey(componentType.getCategory())) {
nestedList = componentTypes.get(componentType.getCategory());
} else {
nestedList = new ArrayList<ComponentType>();
componentTypes.put(componentType.getCategory(), nestedList);
}
nestedList.add(componentType);
}
}
for (Map.Entry<String, List<ComponentType>> e : componentTypes.entrySet()) {
LOG.debug(e.getKey() + ": " + e.getValue());
}
} catch (Exception e) {
LOG.error("Error loading component types", e);
}
}
return componentTypes;
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
@@ -2559,7 +2515,8 @@ public class Presenter implements IPlugInPort, IConfigListener {
} }
} }
try { try {
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("variants.xml")); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(
"import-defaults/variants.xml"));
XStream xStream = new XStream(new DomDriver()); XStream xStream = new XStream(new DomDriver());
xStream.addPermission(AnyTypePermission.ANY); xStream.addPermission(AnyTypePermission.ANY);
ProjectFileManager.xStreamSerializer.toXML(defaultVariantMap, out); ProjectFileManager.xStreamSerializer.toXML(defaultVariantMap, out);
@@ -21,7 +21,6 @@ import java.io.BufferedInputStream;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -46,7 +45,7 @@ import org.diylc.serialization.ProjectFileManager;
public class VariantManager { public class VariantManager {
private static final String VARIANTS_FILE_NAME = "variants.xml"; private static final String VARIANTS_FILE_NAME = "import-defaults/variants.xml";
private static final Logger LOG = Logger.getLogger(VariantManager.class); private static final Logger LOG = Logger.getLogger(VariantManager.class);
@@ -24,36 +24,78 @@ package org.diylc.utils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.lang.LangUtil; import org.diylc.lang.LangUtil;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.nio.file.Files; import java.net.URLDecoder;
import java.nio.file.Path; import java.nio.charset.StandardCharsets;
import java.nio.file.Paths; import java.util.HashMap;
import java.util.ArrayList; import java.util.Map;
import java.util.List; import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ResourceUtils { public class ResourceUtils {
private static final Logger LOG = Logger.getLogger(LangUtil.class); private static final Logger LOG = Logger.getLogger(ResourceUtils.class);
public static Map<String, String> getResourceContents(String dir) {
Map<String, String> contents = new HashMap<>();
public static List<File> getResourceFiles(String dir) {
List<File> files = new ArrayList<>();
URL url = LangUtil.class.getResource("/" + dir);
Path path = null;
try { try {
path = Paths.get(url.toURI()); // Get all resources in the directory
Files.walk(path, 5).forEach(p -> { URL dirUrl = ResourceUtils.class.getClassLoader().getResource(dir);
if (!p.toFile().isDirectory()) { if (dirUrl != null) {
files.add(p.toFile()); if (dirUrl.getProtocol().equals("jar")) {
// Running from JAR
String jarPath = dirUrl.getPath();
// Remove the "file:" prefix and decode the URL
jarPath = URLDecoder.decode(jarPath.substring(5, jarPath.indexOf("!")), StandardCharsets.UTF_8);
JarFile jarFile = new JarFile(jarPath);
try {
jarFile.stream()
.filter(entry -> entry.getName().startsWith(dir + "/") && !entry.isDirectory())
.forEach(entry -> {
try {
String relativePath = entry.getName().substring(dir.length() + 1);
// Read the entire file content as string
String content = new String(jarFile.getInputStream(entry).readAllBytes(), StandardCharsets.UTF_8);
contents.put(relativePath, content);
} catch (IOException e) {
LOG.warn("Could not read resource: " + entry.getName(), e);
} }
}); });
} catch (URISyntaxException e) { } finally {
LOG.error("Error loading language file", e); try {
jarFile.close();
} catch (IOException e) { } catch (IOException e) {
LOG.error("Error loading language file", e); LOG.warn("Could not close JAR file", e);
} }
return files; }
} else {
// Running from filesystem
java.io.File dirFile = new java.io.File(dirUrl.toURI());
if (dirFile.exists() && dirFile.isDirectory()) {
java.io.File[] files = dirFile.listFiles();
if (files != null) {
for (java.io.File file : files) {
if (file.isFile()) {
try {
String relativePath = file.getName();
String content = new String(java.nio.file.Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
contents.put(relativePath, content);
} catch (IOException e) {
LOG.warn("Could not read file: " + file, e);
}
}
}
}
}
}
}
} catch (Exception e) {
LOG.error("Error loading resources from directory: " + dir, e);
}
return contents;
} }
} }
@@ -0,0 +1,27 @@
<org.diylc.core.Theme>
<name>Gray</name>
<bgColor>
<red>170</red>
<green>170</green>
<blue>170</blue>
<alpha>255</alpha>
</bgColor>
<gridColor>
<red>150</red>
<green>150</green>
<blue>150</blue>
<alpha>255</alpha>
</gridColor>
<dotColor>
<red>100</red>
<green>100</green>
<blue>100</blue>
<alpha>255</alpha>
</dotColor>
<outlineColor>
<red>0</red>
<green>0</green>
<blue>0</blue>
<alpha>255</alpha>
</outlineColor>
</org.diylc.core.Theme>
+14 -2
View File
@@ -246,9 +246,13 @@
<minor>1</minor> <minor>1</minor>
<build>0</build> <build>0</build>
</versionNumber> </versionNumber>
<releaseDate>2025-03-09 00:00:00.000 CET</releaseDate> <releaseDate>2025-03-24 00:00:00.000 CET</releaseDate>
<name></name> <name></name>
<changes> <changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added ability to render the underside of boards along with the top side for easier validation, building and debugging</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>Configurable 'High DPI Rendering' feature which makes the diagram smoother on high-resolution displays but can affect performance</description> <description>Configurable 'High DPI Rendering' feature which makes the diagram smoother on high-resolution displays but can affect performance</description>
@@ -257,6 +261,10 @@
<changeType>IMPROVEMENT</changeType> <changeType>IMPROVEMENT</changeType>
<description>Significantly improved rendering performance</description> <description>Significantly improved rendering performance</description>
</org.diylc.appframework.update.Change> </org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Increased initial memory allocation to 1GB for smoother performance</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change> <org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType> <changeType>IMPROVEMENT</changeType>
<description>Upgraded source code structure to modern standards and introduced Maven</description> <description>Upgraded source code structure to modern standards and introduced Maven</description>
@@ -271,7 +279,7 @@
</org.diylc.appframework.update.Change> </org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change> <org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType> <changeType>IMPROVEMENT</changeType>
<description>Updated the windows installer to avoid false positive virus detection</description> <description>Updated the windows installer (hopefully) to avoid false positive anti-virus detection</description>
</org.diylc.appframework.update.Change> </org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change> <org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType> <changeType>BUG_FIX</changeType>
@@ -281,6 +289,10 @@
<changeType>BUG_FIX</changeType> <changeType>BUG_FIX</changeType>
<description>Rotating selected components sometimes wacks the alignment off the grid</description> <description>Rotating selected components sometimes wacks the alignment off the grid</description>
</org.diylc.appframework.update.Change> </org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Ctrl+X (Command+X) shortcut for Cut action doesn't work because 'Project Explorer' steals the focus on X key press</description>
</org.diylc.appframework.update.Change>
</changes> </changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url> <url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version> </org.diylc.appframework.update.Version>
@@ -1,266 +1,80 @@
package org.diylc.presenter; package org.diylc.presenter;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class) import java.util.List;
import static org.junit.Assert.*;
public class DatasheetServiceTest { public class DatasheetServiceTest {
private DatasheetService service; private DatasheetService service;
private static final Class<?> TEST_CLASS = DatasheetServiceTest.class;
@Mock
private ClassLoader mockClassLoader;
@Before @Before
public void setUp() { public void setUp() {
service = DatasheetService.getInstance(); service = DatasheetService.getInstance();
service.clearCache(); // Clear cache before each test service.clearCache();
Thread.currentThread().setContextClassLoader(mockClassLoader);
} }
@Test @Test
public void testLoadDatasheet() throws Exception { public void testLoadDatasheet() {
// Create a mock datasheet content List<String[]> result = service.loadDatasheet(TEST_CLASS);
String datasheetContent = assertNotNull(result);
"1N4001,50V,1A,1.1V\n" + assertEquals(4, result.size());
"1N4002,100V,1A,1.1V\n" + assertArrayEquals(new String[]{"TEST", "KEY", "10.0", "20.0"}, result.get(0));
"1N4003,200V,1A,1.1V";
// Create a mock URL that returns our test content
URL mockUrl = mock(URL.class);
when(mockUrl.openStream()).thenReturn(
new ByteArrayInputStream(datasheetContent.getBytes()));
// Setup the mock ClassLoader to return our mock URL
when(mockClassLoader.getResource("TestComponent.datasheet"))
.thenReturn(mockUrl);
// Test loading the datasheet
List<String[]> result = service.loadDatasheet(TestComponent.class);
// Verify results
assertNotNull("Datasheet should not be null", result);
assertEquals("Should have 3 entries", 3, result.size());
// Verify first entry
String[] firstEntry = result.get(0);
assertEquals("1N4001", firstEntry[0]);
assertEquals("50V", firstEntry[1]);
assertEquals("1A", firstEntry[2]);
assertEquals("1.1V", firstEntry[3]);
// Verify second entry
String[] secondEntry = result.get(1);
assertEquals("1N4002", secondEntry[0]);
assertEquals("100V", secondEntry[1]);
// Verify third entry
String[] thirdEntry = result.get(2);
assertEquals("1N4003", thirdEntry[0]);
assertEquals("200V", thirdEntry[1]);
} }
@Test @Test
public void testLoadDatasheetFileNotFound() { public void testLoadDatasheetFileNotFound() {
// Setup the mock ClassLoader to return null (file not found) List<String[]> result = service.loadDatasheet(String.class);
when(mockClassLoader.getResource("TestComponent.datasheet")) assertNull(result);
.thenReturn(null);
List<String[]> result = service.loadDatasheet(TestComponent.class);
assertNull("Result should be null when file is not found", result);
} }
@Test @Test
public void testLookupExactMatch() throws Exception { public void testLookupExactMatch() {
// Create a mock datasheet content String[] result = service.lookup(TEST_CLASS, 0.0, "TEST|KEY", 10.0);
String datasheetContent = assertNotNull(result);
"TEST,KEY,10.0\n" +
"TEST,KEY,20.0\n" +
"TEST,OTHER,15.0\n" +
"OTHER,KEY,10.0";
URL mockUrl = mock(URL.class);
when(mockUrl.openStream()).thenReturn(
new ByteArrayInputStream(datasheetContent.getBytes()));
when(mockClassLoader.getResource("DatasheetServiceTest.datasheet"))
.thenReturn(mockUrl);
// Create test data
String[] result = service.lookup(
DatasheetServiceTest.class, // Using test class itself as component class
0.1, // 0.1% tolerance
"TEST|KEY", // Key to look up
10.0 // Value to match
);
assertNotNull("Should find matching entry", result);
assertEquals("TEST", result[0]);
assertEquals("KEY", result[1]);
assertEquals("10.0", result[2]); assertEquals("10.0", result[2]);
} }
@Test @Test
public void testLookupWithinTolerance() throws Exception { public void testLookupWithinTolerance() {
// Create a mock datasheet content String[] result = service.lookup(TEST_CLASS, 5.0, "TEST|KEY", 10.5);
String datasheetContent = assertNotNull(result);
"TEST,KEY,10.0\n" +
"TEST,KEY,20.0\n" +
"TEST,OTHER,15.0\n" +
"OTHER,KEY,10.0";
URL mockUrl = mock(URL.class);
when(mockUrl.openStream()).thenReturn(
new ByteArrayInputStream(datasheetContent.getBytes()));
when(mockClassLoader.getResource("DatasheetServiceTest.datasheet"))
.thenReturn(mockUrl);
// Should match 10.0 with 5% tolerance when looking for 10.2
String[] result = service.lookup(
DatasheetServiceTest.class,
5.0, // 5% tolerance
"TEST|KEY",
10.2 // Should match 10.0 within 5% tolerance
);
assertNotNull("Should find matching entry within tolerance", result);
assertEquals("10.0", result[2]); assertEquals("10.0", result[2]);
} }
@Test @Test
public void testLookupNoMatch() throws Exception { public void testLookupOutsideTolerance() {
// Create a mock datasheet content String[] result = service.lookup(TEST_CLASS, 5.0, "TEST|KEY", 12.0);
String datasheetContent = assertNull(result);
"TEST,KEY,10.0\n" +
"TEST,KEY,20.0\n" +
"TEST,OTHER,15.0\n" +
"OTHER,KEY,10.0";
URL mockUrl = mock(URL.class);
when(mockUrl.openStream()).thenReturn(
new ByteArrayInputStream(datasheetContent.getBytes()));
when(mockClassLoader.getResource("DatasheetServiceTest.datasheet"))
.thenReturn(mockUrl);
// Should not match when value is outside tolerance
String[] result = service.lookup(
DatasheetServiceTest.class,
1.0, // 1% tolerance
"TEST|KEY",
15.0 // No value close enough to match
);
assertNull("Should not find matching entry", result);
} }
@Test @Test
public void testLookupNonexistentKey() throws Exception { public void testLookupNoMatch() {
// Create a mock datasheet content String[] result = service.lookup(TEST_CLASS, 0.0, "TEST,KEY", 30.0);
String datasheetContent = assertNull(result);
"TEST,KEY,10.0\n" +
"TEST,KEY,20.0\n" +
"TEST,OTHER,15.0\n" +
"OTHER,KEY,10.0";
URL mockUrl = mock(URL.class);
when(mockUrl.openStream()).thenReturn(
new ByteArrayInputStream(datasheetContent.getBytes()));
when(mockClassLoader.getResource("DatasheetServiceTest.datasheet"))
.thenReturn(mockUrl);
String[] result = service.lookup(
DatasheetServiceTest.class,
0.1,
"NONEXISTENT|KEY", // Key that doesn't exist in datasheet
10.0
);
assertNull("Should not find matching entry for nonexistent key", result);
} }
@Test @Test
public void testLookupWithTolerance() throws Exception { public void testLookupNonexistentKey() {
// Create a mock datasheet content with resistor values String[] result = service.lookup(TEST_CLASS, 0.0, "NONEXISTENT,KEY", 10.0);
String datasheetContent = assertNull(result);
"0805,1%,100,0.125W\n" +
"0805,1%,220,0.125W\n" +
"0805,1%,470,0.125W";
URL mockUrl = mock(URL.class);
when(mockUrl.openStream()).thenReturn(
new ByteArrayInputStream(datasheetContent.getBytes()));
when(mockClassLoader.getResource("TestComponent.datasheet"))
.thenReturn(mockUrl);
// Test lookup with 5% tolerance (should match 220 when looking for 225)
String[] result = service.lookup(TestComponent.class, 5.0, "0805|1%", 225.0);
assertNotNull("Should find matching entry within tolerance", result);
assertEquals("0805", result[0]);
assertEquals("1%", result[1]);
assertEquals("220", result[2]);
} }
@Test @Test
public void testLookupOutsideTolerance() throws Exception { public void testLookupWithTolerance() {
// Create a mock datasheet content String[] result = service.lookup(TEST_CLASS, 50.0, "TEST|KEY", 15.0);
String datasheetContent = assertNotNull(result);
"0805,1%,100,0.125W\n" + assertEquals("10.0", result[2]);
"0805,1%,220,0.125W\n" +
"0805,1%,470,0.125W";
URL mockUrl = mock(URL.class);
when(mockUrl.openStream()).thenReturn(
new ByteArrayInputStream(datasheetContent.getBytes()));
when(mockClassLoader.getResource("TestComponent.datasheet"))
.thenReturn(mockUrl);
// Test lookup with value outside tolerance
String[] result = service.lookup(TestComponent.class, 1.0, "0805|1%", 250.0);
assertNull("Should not find matching entry outside tolerance", result);
} }
@Test @Test
public void testLookupMultipleValues() throws Exception { public void testLookupMultipleValues() {
// Create a mock datasheet content with multiple value matches String[] result = service.lookup(TEST_CLASS, 0.0, "TEST|KEY", 10.0, 20.0);
String datasheetContent = assertNotNull(result);
"TO220,NPN,50,5,0.7\n" + // Vce, Ic, Vbe assertEquals("10.0", result[2]);
"TO220,NPN,60,8,0.7\n" + assertEquals("20.0", result[3]);
"TO220,NPN,100,10,0.7";
URL mockUrl = mock(URL.class);
when(mockUrl.openStream()).thenReturn(
new ByteArrayInputStream(datasheetContent.getBytes()));
when(mockClassLoader.getResource("TestComponent.datasheet"))
.thenReturn(mockUrl);
// Test lookup matching multiple values within tolerance
String[] result = service.lookup(TestComponent.class, 5.0, "TO220|NPN",
98.0, 9.8, 0.71);
assertNotNull("Should find matching entry for multiple values", result);
assertEquals("TO220", result[0]);
assertEquals("NPN", result[1]);
assertEquals("100", result[2]);
assertEquals("10", result[3]);
assertEquals("0.7", result[4]);
}
// Test component class
private static class TestComponent {
// Empty class just for testing
} }
} }
@@ -0,0 +1,4 @@
TEST,KEY,10.0,20.0
TEST,KEY,20.0,30.0
TEST,OTHER,15.0,25.0
OTHER,KEY,10.0,20.0
@@ -1,4 +0,0 @@
TEST,KEY,10.0 mm
TEST,KEY,20.0 mm
TEST,OTHER,15.0 mm
OTHER,KEY,10.0 mm
-16
View File
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="lib" path="lib/log4j-1.2.15.jar"/>
<classpathentry kind="lib" path="lib/app-framework.jar"/>
<classpathentry kind="lib" path="lib/jep-2.4.1.jar"/>
<classpathentry kind="lib" path="lib/poi-3.5-FINAL-20090928.jar"/>
<classpathentry kind="lib" path="lib/svgSalamander-1.1.2.4.jar"/>
<classpathentry kind="lib" path="lib/xstream-1.4.19.jar"/>
<classpathentry kind="lib" path="lib/gerber-writer-api-1.0.0.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/diylc-core"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>
-34
View File
@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>diylc-library</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
<filteredResources>
<filter>
<id>1741597247360</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>
@@ -442,6 +442,10 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
break; break;
} }
Composite oldComposite = g2d.getComposite();
if (getAlpha() < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA));
}
if (shouldShadeLeads()) { if (shouldShadeLeads()) {
Shape lineShape = stroke.createStrokedShape(line); Shape lineShape = stroke.createStrokedShape(line);
@@ -463,6 +467,7 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
if (isCopperArea) if (isCopperArea)
observer.stopTrackingContinuityArea(); observer.stopTrackingContinuityArea();
} }
g2d.setComposite(oldComposite);
} }
protected LineStyle getStyle() { protected LineStyle getStyle() {
@@ -35,7 +35,9 @@ import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.VerticalAlignment; import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.AbstractTransparentComponent;
import org.diylc.core.BoardUndersideDisplay;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IBoard;
import org.diylc.core.IDrawingObserver; import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project; import org.diylc.core.Project;
import org.diylc.core.VisibilityPolicy; import org.diylc.core.VisibilityPolicy;
@@ -43,9 +45,10 @@ import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.Size; import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit; import org.diylc.core.measures.SizeUnit;
public abstract class AbstractBoard extends AbstractTransparentComponent<String> { public abstract class AbstractBoard extends AbstractTransparentComponent<String> implements IBoard {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public static final Size DEFAULT_UNDERSIDE_OFFSET = new Size(0.1, SizeUnit.in);
public static Color BORDER_COLOR = PHENOLIC_COLOR.darker(); public static Color BORDER_COLOR = PHENOLIC_COLOR.darker();
public static Color COORDINATE_COLOR = Color.gray.brighter(); public static Color COORDINATE_COLOR = Color.gray.brighter();
@@ -74,6 +77,9 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
protected Size width; protected Size width;
protected BoardSizingMode mode = BoardSizingMode.TwoPoints; protected BoardSizingMode mode = BoardSizingMode.TwoPoints;
protected BoardUndersideDisplay boardUndersideDisplay = BoardUndersideDisplay.NONE;
protected Size undersideOffset = DEFAULT_UNDERSIDE_OFFSET;
@Override @Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) { IDrawingObserver drawingObserver) {
@@ -364,6 +370,45 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
this.mode = mode; this.mode = mode;
} }
@EditableProperty(name = "Underside Display")
@Override
public BoardUndersideDisplay getBoardUndersideDisplay() {
if (this.boardUndersideDisplay == null) {
this.boardUndersideDisplay = BoardUndersideDisplay.NONE;
}
return this.boardUndersideDisplay;
}
public void setBoardUndersideDisplay(BoardUndersideDisplay boardUndersideDisplay) {
this.boardUndersideDisplay = boardUndersideDisplay;
}
@EditableProperty(name = "Underside Offset")
@Override
public Size getUndersideOffset() {
if (undersideOffset == null) {
undersideOffset = DEFAULT_UNDERSIDE_OFFSET;
}
return undersideOffset;
}
public void setUndersideOffset(Size undersideOffset) {
this.undersideOffset = undersideOffset;
}
@Override
public Rectangle2D getBoardRectangle() {
Point2D finalSecondPoint = getFinalSecondPoint();
return new Rectangle2D.Double(firstPoint.getX(), firstPoint.getY(),
finalSecondPoint.getX() - firstPoint.getX(), finalSecondPoint.getY() - firstPoint.getY());
}
@Override
public boolean shouldExportToGerber() {
return false;
}
@Override @Override
public Rectangle2D getCachingBounds() { public Rectangle2D getCachingBounds() {
Point2D finalSecondPoint = getFinalSecondPoint(); Point2D finalSecondPoint = getFinalSecondPoint();
@@ -38,12 +38,11 @@ import org.diylc.core.Project;
import org.diylc.core.annotations.BomPolicy; import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor; import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty; import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.gerber.IGerberBoard;
@ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic", @ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic",
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board", zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board",
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, transformer = SimpleComponentTransformer.class) bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, transformer = SimpleComponentTransformer.class)
public class BlankBoard extends AbstractBoard implements IGerberBoard { public class BlankBoard extends AbstractBoard {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -134,6 +133,11 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard {
return null; return null;
} }
@Override
public boolean shouldExportToGerber() {
return true;
}
static enum Type { static enum Type {
ROUND, SQUARE; ROUND, SQUARE;
@@ -142,12 +146,4 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard {
return name().substring(0, 1) + name().substring(1).toLowerCase(); return name().substring(0, 1) + name().substring(1).toLowerCase();
} }
} }
@Override
public Rectangle2D getBoardRectangle() {
Point2D finalSecondPoint = getFinalSecondPoint();
return new Rectangle2D.Double(firstPoint.getX(), firstPoint.getY(),
finalSecondPoint.getX() - firstPoint.getX(), finalSecondPoint.getY() - firstPoint.getY());
}
} }
@@ -133,11 +133,6 @@ public class CopperTrace extends AbstractLeadedComponent<Void> implements ILayer
return super.getBorderColor(); return super.getBorderColor();
} }
@Override
public Byte getAlpha() {
return super.getAlpha();
}
@Override @Override
public Size getLength() { public Size getLength() {
return super.getLength(); return super.getLength();
@@ -111,11 +111,6 @@ public class CurvedTrace extends AbstractCurvedComponent<Void> implements ILayer
@Override @Override
public void setValue(Void value) {} public void setValue(Void value) {}
@Override
public Byte getAlpha() {
return super.getAlpha();
}
@Override @Override
public void setAlpha(Byte alpha) { public void setAlpha(Byte alpha) {
super.setAlpha(alpha); super.setAlpha(alpha);
@@ -21,13 +21,13 @@
*/ */
package org.diylc.components.connectivity; package org.diylc.components.connectivity;
import java.awt.Color; import java.awt.*;
import java.awt.Graphics2D;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.components.AbstractComponent; import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
@@ -49,7 +49,7 @@ import org.diylc.utils.Constants;
zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class,
enableCache = true) enableCache = true)
public class Eyelet extends AbstractComponent<String> { public class Eyelet extends AbstractTransparentComponent<String> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -71,6 +71,12 @@ public class Eyelet extends AbstractComponent<String> {
} }
int diameter = getClosestOdd((int) size.convertToPixels()); int diameter = getClosestOdd((int) size.convertToPixels());
int holeDiameter = getClosestOdd((int) holeSize.convertToPixels()); int holeDiameter = getClosestOdd((int) holeSize.convertToPixels());
Composite oldComposite = g2d.getComposite();
if (getAlpha() < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA));
}
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f)); g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
g2d.setColor(color); g2d.setColor(color);
drawingObserver.startTrackingContinuityArea(true); drawingObserver.startTrackingContinuityArea(true);
@@ -84,6 +90,8 @@ public class Eyelet extends AbstractComponent<String> {
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: color.darker()); : color.darker());
g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter);
g2d.setComposite(oldComposite);
} }
@Override @Override
@@ -21,8 +21,7 @@
*/ */
package org.diylc.components.connectivity; package org.diylc.components.connectivity;
import java.awt.Color; import java.awt.*;
import java.awt.Graphics2D;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
@@ -33,6 +32,7 @@ import com.bancika.gerberwriter.GerberFunctions;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer; import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractComponent; import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
@@ -52,7 +52,8 @@ import org.diylc.core.measures.SizeUnit;
@ComponentDescriptor(name = "Ground Fill", author = "Branislav Stojkovic", category = "Connectivity", @ComponentDescriptor(name = "Ground Fill", author = "Branislav Stojkovic", category = "Connectivity",
instanceNamePrefix = "GF", description = "Polygonal ground fill area", zOrder = IDIYComponent.TRACE, instanceNamePrefix = "GF", description = "Polygonal ground fill area", zOrder = IDIYComponent.TRACE,
bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class) bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, transformer = SimpleComponentTransformer.class)
public class GroundFill extends AbstractComponent<Void> implements ILayeredComponent, IGerberComponentSimple { public class GroundFill extends AbstractTransparentComponent<Void>
implements ILayeredComponent, IGerberComponentSimple {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -83,7 +84,12 @@ public class GroundFill extends AbstractComponent<Void> implements ILayeredCompo
yPoints[i] = (int)controlPoints[i].getY(); yPoints[i] = (int)controlPoints[i].getY();
} }
drawingObserver.startTrackingContinuityArea(true); drawingObserver.startTrackingContinuityArea(true);
Composite oldComposite = g2d.getComposite();
if (getAlpha() < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA));
}
g2d.fillPolygon(xPoints, yPoints, controlPoints.length); g2d.fillPolygon(xPoints, yPoints, controlPoints.length);
g2d.setComposite(oldComposite);
drawingObserver.stopTrackingContinuityArea(); drawingObserver.stopTrackingContinuityArea();
// Do not track any changes that follow because the whole board has been // Do not track any changes that follow because the whole board has been
// tracked so far. // tracked so far.
@@ -103,11 +103,6 @@ public class Jumper extends AbstractLeadedComponent<Void> implements IContinuity
return super.getBorderColor(); return super.getBorderColor();
} }
@Override
public Byte getAlpha() {
return super.getAlpha();
}
@Override @Override
public Size getLength() { public Size getLength() {
return super.getLength(); return super.getLength();
@@ -233,11 +233,6 @@ public class Line extends AbstractLeadedComponent<Void> {
return super.getBorderColor(); return super.getBorderColor();
} }
@Override
public Byte getAlpha() {
return super.getAlpha();
}
@Override @Override
public Size getLength() { public Size getLength() {
return super.getLength(); return super.getLength();
@@ -17,8 +17,7 @@
*/ */
package org.diylc.components.connectivity; package org.diylc.components.connectivity;
import java.awt.Color; import java.awt.*;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
@@ -29,6 +28,7 @@ import com.bancika.gerberwriter.GerberFunctions;
import org.diylc.common.PCBLayer; import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractComponent; import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
@@ -55,7 +55,8 @@ import org.diylc.utils.Constants;
zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB", keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB",
transformer = SimpleComponentTransformer.class, enableCache = true) transformer = SimpleComponentTransformer.class, enableCache = true)
public class SolderPad extends AbstractComponent<Void> implements ILayeredComponent, IGerberComponentCustom { public class SolderPad extends AbstractTransparentComponent<Void>
implements ILayeredComponent, IGerberComponentCustom {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -90,6 +91,11 @@ public class SolderPad extends AbstractComponent<Void> implements ILayeredCompon
gerberDrawingObserver.startGerberOutput(gerberCopperLayer, GerberFunctions.CONNECTOR_PAD, false); gerberDrawingObserver.startGerberOutput(gerberCopperLayer, GerberFunctions.CONNECTOR_PAD, false);
gerberDrawingObserver.startGerberOutput(org.diylc.core.gerber.GerberLayer.SolderMaskBot, "Material", false); gerberDrawingObserver.startGerberOutput(org.diylc.core.gerber.GerberLayer.SolderMaskBot, "Material", false);
} }
Composite oldComposite = g2d.getComposite();
if (getAlpha() < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA));
}
if (type == Type.ROUND) { if (type == Type.ROUND) {
g2d.fill(new Ellipse2D.Double(point.getX() - diameter / 2, point.getY() - diameter / 2, g2d.fill(new Ellipse2D.Double(point.getX() - diameter / 2, point.getY() - diameter / 2,
diameter, diameter)); diameter, diameter));
@@ -116,6 +122,7 @@ public class SolderPad extends AbstractComponent<Void> implements ILayeredCompon
g2d.fill(new Ellipse2D.Double(point.getX() - holeDiameter / 2, g2d.fill(new Ellipse2D.Double(point.getX() - holeDiameter / 2,
point.getY() - holeDiameter / 2, holeDiameter, holeDiameter)); point.getY() - holeDiameter / 2, holeDiameter, holeDiameter));
} }
g2d.setComposite(oldComposite);
if (gerberDrawingObserver != null) if (gerberDrawingObserver != null)
gerberDrawingObserver.stopGerberOutput(); gerberDrawingObserver.stopGerberOutput();
} }
@@ -21,14 +21,14 @@
*/ */
package org.diylc.components.connectivity; package org.diylc.components.connectivity;
import java.awt.Color; import java.awt.*;
import java.awt.Graphics2D;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.OrientationHV; import org.diylc.common.OrientationHV;
import org.diylc.components.AbstractComponent; import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.boards.AbstractBoard; import org.diylc.components.boards.AbstractBoard;
import org.diylc.components.boards.VeroBoard; import org.diylc.components.boards.VeroBoard;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
@@ -49,7 +49,7 @@ import org.diylc.utils.Constants;
description = "Designates the place where a trace on the vero board needs to be cut", instanceNamePrefix = "Cut", description = "Designates the place where a trace on the vero board needs to be cut", instanceNamePrefix = "Cut",
zOrder = IDIYComponent.BOARD + 1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false, zOrder = IDIYComponent.BOARD + 1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
transformer = SimpleComponentTransformer.class, enableCache = true) transformer = SimpleComponentTransformer.class, enableCache = true)
public class TraceCut extends AbstractComponent<Void> implements ILayeredComponent { public class TraceCut extends AbstractTransparentComponent<Void> implements ILayeredComponent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -79,6 +79,10 @@ public class TraceCut extends AbstractComponent<Void> implements ILayeredCompone
if (checkPointsClipped(g2d.getClip())) { if (checkPointsClipped(g2d.getClip())) {
return; return;
} }
Composite oldComposite = g2d.getComposite();
if (getAlpha() < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA));
}
g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f)); g2d.setStroke(ObjectCache.getInstance().fetchZoomableStroke(1f));
int size = getClosestOdd((int) this.size.convertToPixels()); int size = getClosestOdd((int) this.size.convertToPixels());
int cutWidth = getClosestOdd((int) CUT_WIDTH.convertToPixels()); int cutWidth = getClosestOdd((int) CUT_WIDTH.convertToPixels());
@@ -105,6 +109,7 @@ public class TraceCut extends AbstractComponent<Void> implements ILayeredCompone
g2d.setColor(getBoardColor().darker()); g2d.setColor(getBoardColor().darker());
g2d.drawOval((int)(point.getX() - holeSize / 2), (int)(point.getY() - holeSize / 2), holeSize, holeSize); g2d.drawOval((int)(point.getX() - holeSize / 2), (int)(point.getY() - holeSize / 2), holeSize, holeSize);
} }
g2d.setComposite(oldComposite);
} }
@Override @Override
@@ -21,13 +21,13 @@
*/ */
package org.diylc.components.connectivity; package org.diylc.components.connectivity;
import java.awt.Color; import java.awt.*;
import java.awt.Graphics2D;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.components.AbstractComponent; import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SimpleComponentTransformer; import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
@@ -47,7 +47,7 @@ import org.diylc.utils.Constants;
zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, zOrder = IDIYComponent.TRACE + 0.1, bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false,
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class,
enableCache = true) enableCache = true)
public class Turret extends AbstractComponent<String> { public class Turret extends AbstractTransparentComponent<String> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -67,6 +67,10 @@ public class Turret extends AbstractComponent<String> {
if (checkPointsClipped(g2d.getClip())) { if (checkPointsClipped(g2d.getClip())) {
return; return;
} }
Composite oldComposite = g2d.getComposite();
if (getAlpha() < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA));
}
int diameter = getClosestOdd((int) size.convertToPixels()); int diameter = getClosestOdd((int) size.convertToPixels());
int holeDiameter = getClosestOdd((int) holeSize.convertToPixels()); int holeDiameter = getClosestOdd((int) holeSize.convertToPixels());
g2d.setColor(color); g2d.setColor(color);
@@ -82,6 +86,7 @@ public class Turret extends AbstractComponent<String> {
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: color.darker()); : color.darker());
g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter); g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter);
g2d.setComposite(oldComposite);
} }
@Override @Override
@@ -304,7 +304,8 @@ public class Freeway3x3_03 extends AbstractTransparentComponent<Void> implements
if (svgDiagram == null) { if (svgDiagram == null) {
try { try {
byte[] data = byte[] data =
IOUtils.toByteArray(Freeway3x3_03.class.getResourceAsStream("/freeway_3x3-03.svg")); IOUtils.toByteArray(Freeway3x3_03.class.getResourceAsStream(
"/component-drawings/freeway_3x3-03.svg"));
ByteArrayInputStream bis = new ByteArrayInputStream(data); ByteArrayInputStream bis = new ByteArrayInputStream(data);
SVGUniverse universe = new SVGUniverse(); SVGUniverse universe = new SVGUniverse();
URI url = universe.loadSVG(bis, URI url = universe.loadSVG(bis,
@@ -40,7 +40,6 @@ import org.diylc.awt.ImageUtils;
import org.diylc.common.ObjectCache; import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation; import org.diylc.common.Orientation;
import org.diylc.components.AbstractTransparentComponent; import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.boards.AbstractBoard;
import org.diylc.components.transform.ImageTransformer; import org.diylc.components.transform.ImageTransformer;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
@@ -72,7 +71,7 @@ public class Image extends AbstractTransparentComponent<Void> {
private Orientation orientation; private Orientation orientation;
static { static {
String name = "/image.png"; String name = "/diylc-library-images/image.png";
try (InputStream inputStream = Image.class.getResourceAsStream(name)) { try (InputStream inputStream = Image.class.getResourceAsStream(name)) {
if (inputStream != null) { if (inputStream != null) {
ICON = new ImageIcon(inputStream.readAllBytes(), name); ICON = new ImageIcon(inputStream.readAllBytes(), name);
@@ -99,7 +98,7 @@ public class Image extends AbstractTransparentComponent<Void> {
public Image() { public Image() {
try { try {
data = IOUtils.toByteArray(Image.class.getResourceAsStream("/image.png")); data = IOUtils.toByteArray(Image.class.getResourceAsStream("/diylc-library-images/image.png"));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -81,7 +81,8 @@ public class SVGImage extends AbstractTransparentComponent<Void> {
public SVGImage() { public SVGImage() {
try { try {
data = IOUtils.toByteArray(SVGImage.class.getResourceAsStream("/diylc.svg")); data = IOUtils.toByteArray(SVGImage.class.getResourceAsStream(
"/diylc-library-images/diylc.svg"));
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -43,7 +43,7 @@ public class CliffJackTransformer implements IComponentTransformer {
@Override @Override
public boolean mirroringChangesCircuit() { public boolean mirroringChangesCircuit() {
return true; return false;
} }
@Override @Override
@@ -48,14 +48,26 @@ public class MiniToggleSwitchTransformer implements IComponentTransformer {
@Override @Override
public void rotate(IDIYComponent<?> component, Point2D center, int direction) { public void rotate(IDIYComponent<?> component, Point2D center, int direction) {
AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.getX(), center.getY());
for (int index = 0; index < component.getControlPointCount(); index++) {
Point2D p = new Point2D.Double();
rotate.transform(component.getControlPoint(index), p);
component.setControlPoint(p, index);
}
MiniToggleSwitch sw = (MiniToggleSwitch) component; MiniToggleSwitch sw = (MiniToggleSwitch) component;
// Calculate center of all control points
double sumX = 0, sumY = 0;
for (int i = 0; i < sw.getControlPointCount(); i++) {
Point2D p = sw.getControlPoint(i);
sumX += p.getX();
sumY += p.getY();
}
Point2D controlCenter = new Point2D.Double(
sumX / sw.getControlPointCount(),
sumY / sw.getControlPointCount()
);
// Calculate where control center should end up after rotation
Point2D targetCenter = new Point2D.Double();
AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2 * direction, center.getX(), center.getY());
rotate.transform(controlCenter, targetCenter);
// Update orientation first - this will rotate points around first point
OrientationHV o = sw.getOrientation(); OrientationHV o = sw.getOrientation();
int oValue = o.ordinal(); int oValue = o.ordinal();
oValue += direction; oValue += direction;
@@ -65,6 +77,29 @@ public class MiniToggleSwitchTransformer implements IComponentTransformer {
oValue = 0; oValue = 0;
o = OrientationHV.values()[oValue]; o = OrientationHV.values()[oValue];
sw.setOrientation(o); sw.setOrientation(o);
// Recalculate current control center after orientation change
sumX = 0;
sumY = 0;
for (int i = 0; i < sw.getControlPointCount(); i++) {
Point2D p = sw.getControlPoint(i);
sumX += p.getX();
sumY += p.getY();
}
Point2D newControlCenter = new Point2D.Double(
sumX / sw.getControlPointCount(),
sumY / sw.getControlPointCount()
);
// Calculate and apply translation to move control center to target position
double dx = targetCenter.getX() - newControlCenter.getX();
double dy = targetCenter.getY() - newControlCenter.getY();
// Apply translation to all points
for (int i = 0; i < sw.getControlPointCount(); i++) {
Point2D p = sw.getControlPoint(i);
sw.setControlPoint(new Point2D.Double(p.getX() + dx, p.getY() + dy), i);
}
} }
@Override @Override

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

-30
View File
@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="lib" path="lib/commons-compiler-3.0.6.jar"/>
<classpathentry kind="lib" path="lib/janino-3.0.6.jar"/>
<classpathentry kind="lib" path="lib/log4j-1.2.15.jar"/>
<classpathentry kind="lib" path="lib/junit-4.7.jar"/>
<classpathentry kind="lib" path="lib/jettison-1.0.1.jar"/>
<classpathentry kind="lib" path="lib/app-framework.jar" sourcepath="/app-framework"/>
<classpathentry kind="lib" path="lib/swing-framework.jar" sourcepath="/swing-framework"/>
<classpathentry kind="lib" path="lib/balloontip-1.2.4.1.jar"/>
<classpathentry kind="lib" path="lib/jep-2.4.1.jar"/>
<classpathentry kind="lib" path="lib/poi-3.5-FINAL-20090928.jar"/>
<classpathentry kind="lib" path="lib/AppleJavaExtensions.jar"/>
<classpathentry kind="lib" path="lib/orsonpdf-1.8.jar"/>
<classpathentry kind="lib" path="lib/gestures-wrapper-0.2.jar"/>
<classpathentry kind="lib" path="lib/jar-loader.jar"/>
<classpathentry kind="lib" path="lib/svgSalamander-1.1.2.4.jar"/>
<classpathentry kind="lib" path="lib/xstream-1.4.19.jar"/>
<classpathentry kind="lib" path="lib/guava-31.1-jre.jar"/>
<classpathentry kind="lib" path="lib/pdfbox-2.0.27.jar"/>
<classpathentry kind="lib" path="lib/commons-logging-1.2.jar"/>
<classpathentry kind="lib" path="lib/gerber-writer-api-1.0.0.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/diylc-core"/>
<classpathentry kind="lib" path="lib/java-http-proxy.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="library/main.jar" sourcepath="/diylc-library"/>
<classpathentry kind="output" path="bin"/>
</classpath>
-34
View File
@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>diylc-swing</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
<filteredResources>
<filter>
<id>1741597247368</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>
@@ -1,26 +1,25 @@
#!/bin/bash #!/bin/bash
#set -x # Enable debug mode #set -x # Enable debug mode
HERE="$(dirname "$(readlink -f "$0")")" # Get the AppImage directory
if [ -n "$APPDIR" ]; then
HERE="$APPDIR/usr/bin"
else
HERE="$(cd "$(dirname "$0")" && pwd)"
fi
echo "diylc.sh: Running from directory: $HERE" echo "diylc.sh: Running from directory: $HERE"
# Check if Java is available # Use system Java
if [ -d "$HERE/jre" ]; then
export JAVA_HOME="$HERE/jre"
export PATH="$JAVA_HOME/bin:$PATH"
JAVA="$JAVA_HOME/bin/java"
echo "diylc.sh: Using bundled JRE: $JAVA"
else
JAVA="$(which java)" JAVA="$(which java)"
echo "diylc.sh: Using system Java: $JAVA" if [ -z "$JAVA" ] || [ ! -x "$JAVA" ]; then
fi echo "diylc.sh: ERROR - System Java not found or not executable!"
echo "diylc.sh: Please install Java 17 or later"
# Debug: Check Java existence
if [ ! -x "$JAVA" ]; then
echo "diylc.sh: ERROR - Java binary not found or not executable!"
exit 1 exit 1
fi fi
echo "diylc.sh: Using system Java: $JAVA"
cd "$HERE" cd "$HERE"
echo "diylc.sh: Current working directory: $(pwd)" echo "diylc.sh: Current working directory: $(pwd)"
@@ -28,11 +27,9 @@ echo "diylc.sh: Current working directory: $(pwd)"
echo "diylc.sh: Executing DIYLCStarter with Java" echo "diylc.sh: Executing DIYLCStarter with Java"
exec "$JAVA" \ exec "$JAVA" \
-Xms512m \ -Xms1024m \
-Xmx4096m \ -Xmx4096m \
-cp "$HERE/../lib/diylc.jar" \ -cp "$APPDIR/usr/lib/diylc.jar" \
--add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED \
--add-exports java.desktop/com.apple.eio=ALL-UNNAMED \
--add-opens java.base/java.util=ALL-UNNAMED \ --add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.lang=ALL-UNNAMED \ --add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.text=ALL-UNNAMED \ --add-opens java.base/java.text=ALL-UNNAMED \
+16 -1
View File
@@ -2,4 +2,19 @@
JAVA_BIN="$(which java)" JAVA_BIN="$(which java)"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
CLASS_PATH="${DIR}/diylc.jar" CLASS_PATH="${DIR}/diylc.jar"
exec java -Xms512m -Xmx4096m -Dorg.diylc.scriptRun=true -Dfile.encoding=UTF-8 -cp "$CLASS_PATH" --add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED --add-exports java.desktop/com.apple.eio=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens java.desktop/java.awt.geom=ALL-UNNAMED org.diylc.DIYLCStarter "$@"
exec java \
-Xms1024m \
-Xmx4096m \
-Dorg.diylc.scriptRun=true \
-Dfile.encoding=UTF-8 \
-cp "$CLASS_PATH" \
--add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED \
--add-exports java.desktop/com.apple.eio=ALL-UNNAMED \
--add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.text=ALL-UNNAMED \
--add-opens java.desktop/java.awt=ALL-UNNAMED \
--add-opens java.desktop/java.awt.font=ALL-UNNAMED \
--add-opens java.desktop/java.awt.geom=ALL-UNNAMED \
org.diylc.DIYLCStarter "$@"
+72
View File
@@ -0,0 +1,72 @@
#!/bin/bash
# Build the AppImage
echo "Building AppImage..."
cd ../..
#mvn clean package -P linux-appimage
# Check if build was successful
if [ $? -ne 0 ]; then
echo "Build failed!"
exit 1
fi
# Get the AppImage path
APPIMAGE="target/DIYLayoutCreator-5.1.0-x86_64.AppImage"
ZIP_FILE="target/diylc-5.1.0-linux.zip"
# Check if files exist
if [ ! -f "$APPIMAGE" ]; then
echo "AppImage not found at $APPIMAGE"
exit 1
fi
if [ ! -f "$ZIP_FILE" ]; then
echo "Zip file not found at $ZIP_FILE"
exit 1
fi
# Create test directory
TEST_DIR="target/appimage-test"
rm -rf "$TEST_DIR"
mkdir -p "$TEST_DIR"
# Copy files to test directory
echo "Copying files to test directory..."
cp "$APPIMAGE" "$TEST_DIR/"
cp "$ZIP_FILE" "$TEST_DIR/"
# Extract zip file
echo "Extracting zip file..."
cd "$TEST_DIR"
unzip "diylc-5.1.0-linux.zip"
# Make AppImage executable
chmod +x "DIYLayoutCreator-5.1.0-x86_64.AppImage"
# Test AppImage structure
echo "Testing AppImage structure..."
if [ -f "DIYLayoutCreator-5.1.0-x86_64.AppImage" ]; then
echo "AppImage file exists and is executable"
echo "AppImage size: $(ls -lh DIYLayoutCreator-5.1.0-x86_64.AppImage | awk '{print $5}')"
echo "AppImage permissions: $(ls -l DIYLayoutCreator-5.1.0-x86_64.AppImage | awk '{print $1}')"
# Check if AppImage has the correct magic number
if file "DIYLayoutCreator-5.1.0-x86_64.AppImage" | grep -q "ELF 64-bit LSB executable"; then
echo "AppImage has correct ELF format"
else
echo "Warning: AppImage might not have correct ELF format"
fi
# Check if AppImage has the correct AppImage magic bytes
if dd if="DIYLayoutCreator-5.1.0-x86_64.AppImage" bs=8 count=1 2>/dev/null | grep -q "AI"; then
echo "AppImage has correct AppImage magic bytes"
else
echo "Warning: AppImage might not have correct AppImage magic bytes"
fi
echo "AppImage structure test completed successfully!"
else
echo "AppImage file not found in test directory!"
exit 1
fi
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
# Get the directory where this script is located
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Set DEBUG environment variable
export DEBUG=true
# Run the VersionReader class
java -cp "../target/diylc.jar" --add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.text=ALL-UNNAMED \
--add-opens java.desktop/java.awt=ALL-UNNAMED \
--add-opens java.desktop/java.awt.font=ALL-UNNAMED \
--add-opens java.desktop/java.awt.geom=ALL-UNNAMED \
org.diylc.utils.VersionReader "$SCRIPT_DIR/../"
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
# Get the directory where this script is located
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# FTP settings
FTP_USER="diylc_deploy@diy-fever.com"
FTP_HOST="ftp.diy-fever.com"
# Check if password is set
if [ -z "$DIYLC_DEPLOY_PWD" ]; then
echo "Error: DIYLC_DEPLOY_PWD environment variable is not set"
exit 1
fi
# Source file path
SOURCE_FILE="$SCRIPT_DIR/../../diylc-core/src/main/resources/update.xml"
# Check if source file exists
if [ ! -f "$SOURCE_FILE" ]; then
echo "Error: update.xml not found at $SOURCE_FILE"
exit 1
fi
# Upload using FTP
echo "Uploading update.xml to $FTP_USER@$FTP_HOST..."
ftp -n "$FTP_HOST" << EOF
user $FTP_USER $DIYLC_DEPLOY_PWD
binary
put "$SOURCE_FILE" update.xml
quit
EOF
# Check FTP exit status
if [ $? -eq 0 ]; then
echo "Upload successful"
else
echo "Upload failed"
exit 1
fi
@@ -24,7 +24,7 @@
<requires64Bit>true</requires64Bit> <requires64Bit>true</requires64Bit>
<minVersion>17</minVersion> <minVersion>17</minVersion>
<maxVersion></maxVersion> <maxVersion></maxVersion>
<initialHeapSize>512</initialHeapSize> <initialHeapSize>1024</initialHeapSize>
<maxHeapSize>4096</maxHeapSize> <maxHeapSize>4096</maxHeapSize>
<opt>-Dorg.diylc.scriptRun=true</opt> <opt>-Dorg.diylc.scriptRun=true</opt>
<opt>-Dfile.encoding=UTF-8</opt> <opt>-Dfile.encoding=UTF-8</opt>
+5
View File
@@ -74,6 +74,7 @@ And
Angle Angle
Angle Offset Angle Offset
Anti-Aliasing Anti-Aliasing
Apply Model
Arrow Size Arrow Size
Author Author
Auto-Create Pads Auto-Create Pads
@@ -85,6 +86,8 @@ Below
Board Board
Board Color Board Color
Board Width Board Width
Board1
Board2
Boards Boards
Bobbin 1 Bobbin 1
Bobbin 2 Bobbin 2
@@ -588,6 +591,8 @@ Tubular Beveled
Two Two
Type Type
Ultra-miniature Ultra-miniature
Underside Display
Underside Offset
Underside Pad Color Underside Pad Color
Underside Trace Color Underside Trace Color
Undo Undo
+113 -93
View File
@@ -260,47 +260,6 @@
</target> </target>
</configuration> </configuration>
</execution> </execution>
<execution>
<id>sign-jar-launcher</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<!-- Extract JavaAppLauncher -->
<unzip src="${project.build.directory}/diylc.jar" dest="${project.build.directory}/jar-contents">
<patternset>
<include name="com/oracle/appbundler/JavaAppLauncher"/>
</patternset>
</unzip>
<!-- Make it executable -->
<chmod file="${project.build.directory}/jar-contents/com/oracle/appbundler/JavaAppLauncher" perm="755"/>
<!-- Sign the launcher -->
<exec executable="codesign" failonerror="true">
<arg value="--force"/>
<arg value="--sign"/>
<arg value="${env.APPLE_DEVELOPER_IDENTITY}"/>
<arg value="--timestamp"/>
<arg value="--options"/>
<arg value="runtime"/>
<arg value="--entitlements"/>
<arg value="${project.basedir}/deploy/mac/entitlements.plist"/>
<arg value="--all-architectures"/>
<arg value="--strict"/>
<arg value="--verbose"/>
<arg value="${project.build.directory}/jar-contents/com/oracle/appbundler/JavaAppLauncher"/>
</exec>
<!-- Update the jar with signed launcher -->
<jar destfile="${project.build.directory}/diylc.jar" update="true">
<fileset dir="${project.build.directory}/jar-contents"/>
</jar>
</target>
</configuration>
</execution>
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>
@@ -328,7 +287,7 @@
<goal>single</goal> <goal>single</goal>
</goals> </goals>
<configuration> <configuration>
<finalName>diylc-${project.version}</finalName> <finalName>diylc-${project.version}-universal</finalName>
<appendAssemblyId>false</appendAssemblyId> <appendAssemblyId>false</appendAssemblyId>
</configuration> </configuration>
</execution> </execution>
@@ -391,39 +350,6 @@
<copy file="${project.basedir}/deploy/linux/appimage/com.diy_fever.DIYLayoutCreator.metainfo.xml" <copy file="${project.basedir}/deploy/linux/appimage/com.diy_fever.DIYLayoutCreator.metainfo.xml"
todir="${appdir.dir}/usr/share/metainfo" /> todir="${appdir.dir}/usr/share/metainfo" />
<!-- Download and extract JRE for Linux -->
<!-- Ensure clean jre folders -->
<delete dir="${jre.dest.linux}" />
<mkdir dir="${jre.dest.linux}" />
<mkdir dir="${project.build.directory}/downloads" />
<!-- Download JRE 17 if not already present -->
<get src="${jdk.url.linux}"
dest="${project.build.directory}/downloads/${jdk.archive.linux}"
usetimestamp="true" />
<!-- Extract JRE -->
<untar src="${project.build.directory}/downloads/${jdk.archive.linux}"
dest="${jre.dest.linux}"
compression="gzip" />
<!-- Move extracted folder into AppImage location -->
<mkdir dir="${appdir.dir}/usr/bin/jre" />
<move todir="${appdir.dir}/usr/bin/jre">
<fileset dir="${jre.dest.linux}/jdk-${jdk.version}-jre" />
</move>
<!-- Clean up temporary directory -->
<delete dir="${jre.dest.linux}" />
<echo message="JRE 17 bundled into ${appdir.dir}/usr/bin/jre" />
<!-- Update the launch script to use the correct JRE path -->
<replace file="${appdir.dir}/usr/bin/diylc.sh">
<replacetoken>JAVA_HOME="$APPDIR/usr/lib/jre"</replacetoken>
<replacevalue>JAVA_HOME="$APPDIR/usr/bin/jre"</replacevalue>
</replace>
<echo message="AppDir structure created successfully at: ${appdir.dir}" /> <echo message="AppDir structure created successfully at: ${appdir.dir}" />
</target> </target>
</configuration> </configuration>
@@ -539,9 +465,17 @@
<fileset dir="${appdir.dir}" /> <fileset dir="${appdir.dir}" />
</copy> </copy>
<!-- Run AppImageTool in Docker --> <!-- Ensure proper permissions in Docker volume -->
<exec executable="chmod" failonerror="true" osfamily="mac">
<arg line="-R 755 ${project.build.directory}/docker-tmp/AppDir/AppRun" />
</exec>
<exec executable="chmod" failonerror="true" osfamily="mac">
<arg line="-R 755 ${project.build.directory}/docker-tmp/AppDir/usr/bin/diylc.sh" />
</exec>
<!-- Run AppImageTool in Docker with proper volume mounting -->
<exec executable="docker" failonerror="true" osfamily="mac"> <exec executable="docker" failonerror="true" osfamily="mac">
<arg line="run --rm -v &quot;${project.build.directory}/docker-tmp:/workspace&quot; -w /workspace appimagecrafters/appimage-builder:latest /bin/bash -c &quot;ARCH=x86_64 appimagetool AppDir ${appimage.output.file}&quot;" /> <arg line="run --rm -v &quot;${project.build.directory}/docker-tmp:/workspace&quot; -w /workspace appimagecrafters/appimage-builder:latest /bin/bash -c &quot;chmod +x AppDir/AppRun AppDir/usr/bin/diylc.sh &amp;&amp; ARCH=x86_64 appimagetool AppDir ${appimage.output.file}&quot;" />
</exec> </exec>
<!-- Copy the AppImage to the build directory --> <!-- Copy the AppImage to the build directory -->
@@ -703,6 +637,49 @@
</configuration> </configuration>
</execution> </execution>
<!-- Sign JAR launcher -->
<execution>
<id>sign-jar-launcher</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<!-- Extract JavaAppLauncher -->
<unzip src="${project.build.directory}/diylc.jar" dest="${project.build.directory}/jar-contents">
<patternset>
<include name="com/oracle/appbundler/JavaAppLauncher"/>
</patternset>
</unzip>
<!-- Make it executable -->
<chmod file="${project.build.directory}/jar-contents/com/oracle/appbundler/JavaAppLauncher" perm="755"/>
<!-- Sign the launcher -->
<exec executable="codesign" failonerror="true">
<arg value="--force"/>
<arg value="--sign"/>
<arg value="${env.APPLE_DEVELOPER_IDENTITY}"/>
<arg value="--timestamp"/>
<arg value="--options"/>
<arg value="runtime"/>
<arg value="--entitlements"/>
<arg value="${project.basedir}/deploy/mac/entitlements.plist"/>
<arg value="--all-architectures"/>
<arg value="--strict"/>
<arg value="--verbose"/>
<arg value="${project.build.directory}/jar-contents/com/oracle/appbundler/JavaAppLauncher"/>
</exec>
<!-- Update the jar with signed launcher -->
<jar destfile="${project.build.directory}/diylc.jar" update="true">
<fileset dir="${project.build.directory}/jar-contents"/>
</jar>
</target>
</configuration>
</execution>
<!-- Create macOS app bundle --> <!-- Create macOS app bundle -->
<execution> <execution>
<id>create-mac-bundle</id> <id>create-mac-bundle</id>
@@ -740,7 +717,7 @@
<runtime dir="${jre.dest.osx}/Contents/Home" /> <runtime dir="${jre.dest.osx}/Contents/Home" />
<arch name="x86_64"/> <arch name="x86_64"/>
<classpath file="${project.build.directory}/diylc.jar" /> <classpath file="${project.build.directory}/diylc.jar" />
<option value="-Xms512m" /> <option value="-Xms1024m" />
<option value="-Xmx4096m" /> <option value="-Xmx4096m" />
<option value="--add-exports=java.desktop/com.apple.eawt.event=ALL-UNNAMED" /> <option value="--add-exports=java.desktop/com.apple.eawt.event=ALL-UNNAMED" />
<option value="--add-exports=java.desktop/com.apple.eio=ALL-UNNAMED" /> <option value="--add-exports=java.desktop/com.apple.eio=ALL-UNNAMED" />
@@ -761,13 +738,6 @@
<option value="-Xdock:icon=Contents/Resources/diylc.icns"/> <option value="-Xdock:icon=Contents/Resources/diylc.icns"/>
</bundleapp> </bundleapp>
<!-- First remove existing signatures -->
<echo message="Removing any existing signatures..."/>
<exec executable="codesign" failonerror="false">
<arg value="--remove-signature"/>
<arg value="${project.build.directory}/DIYLC.app"/>
</exec>
<echo message="Creating unsigned zip for distribution..."/> <echo message="Creating unsigned zip for distribution..."/>
<!-- Create unsigned zip for distribution --> <!-- Create unsigned zip for distribution -->
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-x86-unsigned.zip"> <zip destfile="${project.build.directory}/diylc-${project.version}-osx-x86-unsigned.zip">
@@ -776,6 +746,13 @@
</zip> </zip>
<echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-x86-unsigned.zip"/> <echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-x86-unsigned.zip"/>
<!-- First remove existing signatures -->
<echo message="Removing any existing signatures..."/>
<exec executable="codesign" failonerror="false">
<arg value="--remove-signature"/>
<arg value="${project.build.directory}/DIYLC.app"/>
</exec>
<!-- Sign the entire app bundle in one shot --> <!-- Sign the entire app bundle in one shot -->
<echo message="Signing complete app bundle..."/> <echo message="Signing complete app bundle..."/>
<exec executable="codesign" failonerror="true"> <exec executable="codesign" failonerror="true">
@@ -973,6 +950,49 @@
</configuration> </configuration>
</execution> </execution>
<!-- Sign JAR launcher -->
<execution>
<id>sign-jar-launcher</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<!-- Extract JavaAppLauncher -->
<unzip src="${project.build.directory}/diylc.jar" dest="${project.build.directory}/jar-contents">
<patternset>
<include name="com/oracle/appbundler/JavaAppLauncher"/>
</patternset>
</unzip>
<!-- Make it executable -->
<chmod file="${project.build.directory}/jar-contents/com/oracle/appbundler/JavaAppLauncher" perm="755"/>
<!-- Sign the launcher -->
<exec executable="codesign" failonerror="true">
<arg value="--force"/>
<arg value="--sign"/>
<arg value="${env.APPLE_DEVELOPER_IDENTITY}"/>
<arg value="--timestamp"/>
<arg value="--options"/>
<arg value="runtime"/>
<arg value="--entitlements"/>
<arg value="${project.basedir}/deploy/mac/entitlements.plist"/>
<arg value="--all-architectures"/>
<arg value="--strict"/>
<arg value="--verbose"/>
<arg value="${project.build.directory}/jar-contents/com/oracle/appbundler/JavaAppLauncher"/>
</exec>
<!-- Update the jar with signed launcher -->
<jar destfile="${project.build.directory}/diylc.jar" update="true">
<fileset dir="${project.build.directory}/jar-contents"/>
</jar>
</target>
</configuration>
</execution>
<!-- Create macOS app bundle --> <!-- Create macOS app bundle -->
<execution> <execution>
<id>create-mac-bundle</id> <id>create-mac-bundle</id>
@@ -1011,7 +1031,7 @@
<arch name="arm64"/> <arch name="arm64"/>
<arch name="arm64e"/> <arch name="arm64e"/>
<classpath file="${project.build.directory}/diylc.jar" /> <classpath file="${project.build.directory}/diylc.jar" />
<option value="-Xms512m" /> <option value="-Xms1024m" />
<option value="-Xmx4096m" /> <option value="-Xmx4096m" />
<option value="--add-exports=java.desktop/com.apple.eawt.event=ALL-UNNAMED" /> <option value="--add-exports=java.desktop/com.apple.eawt.event=ALL-UNNAMED" />
<option value="--add-exports=java.desktop/com.apple.eio=ALL-UNNAMED" /> <option value="--add-exports=java.desktop/com.apple.eio=ALL-UNNAMED" />
@@ -1032,13 +1052,6 @@
<option value="-Xdock:icon=Contents/Resources/diylc.icns"/> <option value="-Xdock:icon=Contents/Resources/diylc.icns"/>
</bundleapp> </bundleapp>
<!-- First remove existing signatures -->
<echo message="Removing any existing signatures..."/>
<exec executable="codesign" failonerror="false">
<arg value="--remove-signature"/>
<arg value="${project.build.directory}/DIYLC.app"/>
</exec>
<echo message="Creating unsigned zip for distribution..."/> <echo message="Creating unsigned zip for distribution..."/>
<!-- Create unsigned zip for distribution --> <!-- Create unsigned zip for distribution -->
<zip destfile="${project.build.directory}/diylc-${project.version}-osx-arm-unsigned.zip"> <zip destfile="${project.build.directory}/diylc-${project.version}-osx-arm-unsigned.zip">
@@ -1047,6 +1060,13 @@
</zip> </zip>
<echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-arm-unsigned.zip"/> <echo message="Unsigned zip created at: ${project.build.directory}/diylc-${project.version}-osx-arm-unsigned.zip"/>
<!-- First remove existing signatures -->
<echo message="Removing any existing signatures..."/>
<exec executable="codesign" failonerror="false">
<arg value="--remove-signature"/>
<arg value="${project.build.directory}/DIYLC.app"/>
</exec>
<!-- Sign the entire app bundle in one shot --> <!-- Sign the entire app bundle in one shot -->
<echo message="Signing complete app bundle..."/> <echo message="Signing complete app bundle..."/>
<exec executable="codesign" failonerror="true"> <exec executable="codesign" failonerror="true">
@@ -28,7 +28,7 @@ public class CopyAction extends AbstractAction {
this.clipboardOwner = clipboardOwner; this.clipboardOwner = clipboardOwner;
putValue(AbstractAction.NAME, "Copy"); putValue(AbstractAction.NAME, "Copy");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Copy.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.Copy.getIcon());
} }
@@ -28,7 +28,7 @@ public class CutAction extends AbstractAction {
this.clipboardOwner = clipboardOwner; this.clipboardOwner = clipboardOwner;
putValue(AbstractAction.NAME, "Cut"); putValue(AbstractAction.NAME, "Cut");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_X, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_X,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Cut.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.Cut.getIcon());
} }
@@ -21,7 +21,7 @@ public class DuplicateAction extends AbstractAction {
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Duplicate"); putValue(AbstractAction.NAME, "Duplicate");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_D, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_D,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.DocumentsGear.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.DocumentsGear.getIcon());
} }
@@ -23,7 +23,7 @@ public class EditSelectionAction extends AbstractAction {
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Edit Selection"); putValue(AbstractAction.NAME, "Edit Selection");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_E, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_E,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.EditComponent.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.EditComponent.getIcon());
} }
@@ -21,7 +21,7 @@ public class GroupAction extends AbstractAction {
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Group Selection"); putValue(AbstractAction.NAME, "Group Selection");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_G, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_G,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Group.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.Group.getIcon());
} }
@@ -32,7 +32,7 @@ public class NudgeAction extends AbstractAction {
putValue(AbstractAction.NAME, "Nudge"); putValue(AbstractAction.NAME, "Nudge");
putValue(AbstractAction.SMALL_ICON, IconLoader.FitToSize.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.FitToSize.getIcon());
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Q, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Q,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
} }
@Override @Override
@@ -27,7 +27,7 @@ public class PasteAction extends AbstractAction {
this.clipboard = clipboard; this.clipboard = clipboard;
putValue(AbstractAction.NAME, "Paste"); putValue(AbstractAction.NAME, "Paste");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_V, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_V,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Paste.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.Paste.getIcon());
} }
@@ -21,7 +21,7 @@ public class SelectAllAction extends AbstractAction {
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Select All"); putValue(AbstractAction.NAME, "Select All");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Selection.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.Selection.getIcon());
} }
@@ -21,7 +21,7 @@ public class UngroupAction extends AbstractAction {
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Ungroup Selection"); putValue(AbstractAction.NAME, "Ungroup Selection");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_U, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_U,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Ungroup.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.Ungroup.getIcon());
} }
@@ -66,7 +66,7 @@ public class ImportAction extends AbstractAction {
}, InMemoryConfigurationManager.getInstance()); }, InMemoryConfigurationManager.getInstance());
putValue(AbstractAction.NAME, "Import"); putValue(AbstractAction.NAME, "Import");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.ElementInto.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.ElementInto.getIcon());
} }
@@ -28,7 +28,7 @@ public class NewAction extends AbstractAction {
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "New"); putValue(AbstractAction.NAME, "New");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.DocumentPlain.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.DocumentPlain.getIcon());
} }
@@ -28,7 +28,7 @@ public class OpenAction extends AbstractAction {
this.swingUI = swingUI; this.swingUI = swingUI;
putValue(AbstractAction.NAME, "Open"); putValue(AbstractAction.NAME, "Open");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.FolderOut.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.FolderOut.getIcon());
} }
@@ -28,7 +28,7 @@ public class SaveAction extends AbstractAction {
this.swingUI = swingUI; this.swingUI = swingUI;
putValue(AbstractAction.NAME, "Save"); putValue(AbstractAction.NAME, "Save");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.DiskBlue.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.DiskBlue.getIcon());
} }
@@ -29,7 +29,7 @@ public class SaveAsAction extends AbstractAction {
this.swingUI = swingUI; this.swingUI = swingUI;
putValue(AbstractAction.NAME, "Save As"); putValue(AbstractAction.NAME, "Save As");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | ActionEvent.SHIFT_MASK)); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx() | ActionEvent.SHIFT_MASK));
putValue(AbstractAction.SMALL_ICON, IconLoader.DiskBlue.getIcon()); putValue(AbstractAction.SMALL_ICON, IconLoader.DiskBlue.getIcon());
} }
@@ -22,6 +22,7 @@ import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager; import org.diylc.appframework.miscutils.ConfigurationManager;
@@ -174,23 +175,24 @@ public class ConfigPlugin implements IPlugIn {
ActionFactory.getInstance() ActionFactory.getInstance()
.createConfigAction(plugInPort, "Sticky Points", IPlugInPort.STICKY_POINTS_KEY, true), CONFIG_MENU); .createConfigAction(plugInPort, "Sticky Points", IPlugInPort.STICKY_POINTS_KEY, true), CONFIG_MENU);
List<File> themeFiles = ResourceUtils.getResourceFiles(THEMES_DIR); Map<String, String> themeContents = ResourceUtils.getResourceContents(THEMES_DIR);
if (!themeFiles.isEmpty()) { if (!themeContents.isEmpty()) {
XStream xStream = new XStream(new DomDriver()); XStream xStream = new XStream(new DomDriver());
xStream.addPermission(AnyTypePermission.ANY); xStream.addPermission(AnyTypePermission.ANY);
swingUI.injectSubmenu(THEME_MENU, IconLoader.Pens.getIcon(), CONFIG_MENU); swingUI.injectSubmenu(THEME_MENU, IconLoader.Pens.getIcon(), CONFIG_MENU);
for (File file : themeFiles) { themeContents.entrySet().stream()
if (file.getName().toLowerCase().endsWith(".xml")) { .sorted(Map.Entry.comparingByKey())
.forEach(entry -> {
if (entry.getKey().toLowerCase().endsWith(".xml")) {
try { try {
InputStream in = new FileInputStream(file); Theme theme = (Theme) xStream.fromXML(entry.getValue());
Theme theme = (Theme) xStream.fromXML(in);
LOG.debug("Found theme: " + theme.getName()); LOG.debug("Found theme: " + theme.getName());
swingUI.injectMenuAction(ActionFactory.getInstance().createThemeAction(plugInPort, theme), THEME_MENU); swingUI.injectMenuAction(ActionFactory.getInstance().createThemeAction(plugInPort, theme), THEME_MENU);
} catch (Exception e) { } catch (Exception e) {
LOG.error("Could not load theme file " + file.getName(), e); LOG.error("Could not load theme file " + entry.getKey(), e);
}
} }
} }
});
} }
swingUI.injectSubmenu(COMPONENT_BROWSER_MENU, IconLoader.Hammer.getIcon(), CONFIG_MENU); swingUI.injectSubmenu(COMPONENT_BROWSER_MENU, IconLoader.Hammer.getIcon(), CONFIG_MENU);
@@ -90,8 +90,7 @@ public class ExplorerPlugin implements IPlugIn {
@Override @Override
public boolean dispatchKeyEvent(KeyEvent e) { public boolean dispatchKeyEvent(KeyEvent e) {
if ((canvasPanel.hasFocus() || explorerPane.hasFocus()) if (e.getKeyChar() == 'x' && e.getModifiersEx() == 0
&& e.getKeyChar() == 'x'
&& ConfigurationManager.getInstance() && ConfigurationManager.getInstance()
.readBoolean(ConfigPlugin.PROJECT_EXPLORER, true)) { .readBoolean(ConfigPlugin.PROJECT_EXPLORER, true)) {
explorerPane.getSearchField().requestFocusInWindow(); explorerPane.getSearchField().requestFocusInWindow();
@@ -86,7 +86,7 @@ public class FileMenuPlugin implements IPlugIn, IDynamicSubmenuHandler {
swingUI.injectMenuAction( swingUI.injectMenuAction(
actionFactory.createExportGerberAction(plugInPort, swingUI), EXPORT_TITLE); actionFactory.createExportGerberAction(plugInPort, swingUI), EXPORT_TITLE);
swingUI.injectMenuAction(actionFactory.createPrintAction(drawingProvider, swingUI, swingUI.injectMenuAction(actionFactory.createPrintAction(drawingProvider, swingUI,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), FILE_TITLE); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()), FILE_TITLE);
swingUI.injectSubmenu(TRACE_MASK_TITLE, IconLoader.TraceMask.getIcon(), FILE_TITLE); swingUI.injectSubmenu(TRACE_MASK_TITLE, IconLoader.TraceMask.getIcon(), FILE_TITLE);
swingUI.injectMenuAction(actionFactory.createExportPDFAction(plugInPort, swingUI.injectMenuAction(actionFactory.createExportPDFAction(plugInPort,
traceMaskDrawingProvider, swingUI, " (mask)"), TRACE_MASK_TITLE); traceMaskDrawingProvider, swingUI, " (mask)"), TRACE_MASK_TITLE);
@@ -94,7 +94,7 @@ public class FileMenuPlugin implements IPlugIn, IDynamicSubmenuHandler {
traceMaskDrawingProvider, swingUI, " (mask)"), TRACE_MASK_TITLE); traceMaskDrawingProvider, swingUI, " (mask)"), TRACE_MASK_TITLE);
swingUI.injectMenuAction( swingUI.injectMenuAction(
actionFactory.createPrintAction(traceMaskDrawingProvider, swingUI, actionFactory.createPrintAction(traceMaskDrawingProvider, swingUI,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | KeyEvent.SHIFT_DOWN_MASK), Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx() | KeyEvent.SHIFT_DOWN_MASK),
TRACE_MASK_TITLE); TRACE_MASK_TITLE);
swingUI.injectSubmenu(ANALYZE_TITLE, IconLoader.Scientist.getIcon(), FILE_TITLE); swingUI.injectSubmenu(ANALYZE_TITLE, IconLoader.Scientist.getIcon(), FILE_TITLE);
@@ -79,7 +79,7 @@ public class LayersMenuPlugin implements IPlugIn {
}; };
visibleAction.putValue(IView.CHECK_BOX_MENU_ITEM, true); visibleAction.putValue(IView.CHECK_BOX_MENU_ITEM, true);
visibleAction.putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_0 + zOrder, visibleAction.putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_0 + zOrder,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
visibleActionMap.put(layer, visibleAction); visibleActionMap.put(layer, visibleAction);
AbstractAction selectAllAction = new AbstractAction("Select All") { AbstractAction selectAllAction = new AbstractAction("Select All") {
+2 -2
View File
@@ -23,7 +23,7 @@
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>
<log4j.version>1.2.15</log4j.version> <log4j.version>1.2.15</log4j.version>
<xstream.version>1.4.19</xstream.version> <xstream.version>1.4.21</xstream.version>
</properties> </properties>
<!-- Build configuration will be defined below --> <!-- Build configuration will be defined below -->
@@ -61,7 +61,7 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.7</version> <version>4.13.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>