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
+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 g2d
* @param componentState
* @param theme
* @param drawingObserver
*/
protected abstract void drawCurve(Path2D curve, Graphics2D g2d, ComponentState componentState,
IDrawingObserver drawingObserver);
@@ -29,10 +29,13 @@ public abstract class AbstractTransparentComponent<T> extends AbstractComponent<
public static byte MAX_ALPHA = 127;
protected byte alpha = MAX_ALPHA;
protected Byte alpha = MAX_ALPHA;
@EditableProperty
public Byte getAlpha() {
if (alpha == null) {
alpha = MAX_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 org.diylc.core.ComponentState;
import org.diylc.core.IBoard;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IView;
import org.diylc.core.Project;
@@ -30,44 +31,47 @@ public class GerberExporter {
private static final Logger LOG = Logger.getLogger(GerberExporter.class);
public static void exportGerber(String fileNameBase, Project currentProject, IView view,
Graphics2D graphics2d, String diylcVersion) {
List<IGerberBoard> gerberBoards =
currentProject.getComponents().stream().filter(c -> c instanceof IGerberBoard)
.map(x -> (IGerberBoard) x).collect(Collectors.toList());
Graphics2D graphics2d, String diylcVersion) {
Map<IGerberBoard, List<IDIYComponent<?>>> boardComponentMap =
new HashMap<IGerberBoard, List<IDIYComponent<?>>>();
List<IBoard> gerberBoards =
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();
List<IDIYComponent<?>> componentsWithoutBoard = new ArrayList<IDIYComponent<?>>();
currentProject.getComponents().stream().filter(c -> c instanceof IGerberComponent)
.forEach(c -> {
Point2D firstPoint = c.getControlPoint(0);
IGerberBoard board = gerberBoards.stream()
.filter(b -> b.getBoardRectangle().contains(firstPoint)).findFirst().orElse(null);
if (board == null) {
componentsWithoutBoard.add(c);
} else {
boardComponentMap.computeIfAbsent(board, k -> new ArrayList<IDIYComponent<?>>()).add(c);
}
});
.forEach(c -> {
Point2D firstPoint = c.getControlPoint(0);
IBoard board = gerberBoards.stream()
.filter(b -> b.getBoardRectangle().contains(firstPoint)).findFirst().orElse(null);
if (board == null) {
componentsWithoutBoard.add(c);
} else {
boardComponentMap.computeIfAbsent(board, k -> new ArrayList<IDIYComponent<?>>()).add(c);
}
});
// defaultGerberBoard.setComponents(boardComponentMap.get(defaultGerberBoard));
if (boardComponentMap.isEmpty()) {
view.showMessage(LangUtil.translate("Nothing to export."),
LangUtil.translate("Gerber Export"), IView.WARNING_MESSAGE);
LangUtil.translate("Gerber Export"), IView.WARNING_MESSAGE);
return;
}
if (componentsWithoutBoard.size() > 0) {
if (view.showConfirmDialog(String.format(
LangUtil.translate("There are some components that are outside of the bounds of boards.%s"
+ "They will be ignored unless you add a board component underneath them.%sDo you want to continue?"),
"\n", "\n"), LangUtil.translate("Gerber Export"), IView.YES_NO_OPTION,
IView.WARNING_MESSAGE) != IView.YES_OPTION) {
LangUtil.translate("There are some components that are outside of the bounds of boards.%s"
+ "They will be ignored unless you add a board component underneath them.%sDo you want to continue?"),
"\n", "\n"), LangUtil.translate("Gerber Export"), IView.YES_NO_OPTION,
IView.WARNING_MESSAGE) != IView.YES_OPTION) {
return;
}
}
@@ -88,15 +92,15 @@ public class GerberExporter {
String fileNameOutline = GerberLayer.Outline.formatFileName(fileNameBase, boardComponent.getName());
try {
LOG.info(String.format(LangUtil.translate("Exporting outline for board %s to file %s"),
boardComponent.getName(), fileNameOutline));
boardComponent.getName(), fileNameOutline));
outlineLayer.dumpGerberToFile(fileNameOutline);
generatedFiles.add(fileNameOutline);
} catch (IOException e) {
LOG.error("Error writing gerber file: " + e.getMessage());
view.showMessage(
LangUtil.translate(
"Failed to export the project to gerber. Please check the log for details"),
LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE);
LangUtil.translate(
"Failed to export the project to gerber. Please check the log for details"),
LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE);
return;
}
@@ -119,30 +123,30 @@ public class GerberExporter {
try {
String fileName = layer.formatFileName(fileNameBase, boardComponent.getName());
LOG.info("Exporting layer: " + layer + " for board " + boardComponent.getName()
+ " to file: " + fileName);
+ " to file: " + fileName);
dataLayer.dumpGerberToFile(fileName);
generatedFiles.add(fileName);
} catch (IOException e) {
LOG.error("Error writing gerber file: " + e.getMessage());
view.showMessage(
LangUtil.translate(
"Failed to export the project to gerber. Please check the log for details"),
LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE);
LangUtil.translate(
"Failed to export the project to gerber. Please check the log for details"),
LangUtil.translate("Gerber Export"), IView.ERROR_MESSAGE);
return;
}
});
});
view.showMessage(
String.format(
LangUtil.translate(
"Gerber export completed successfully. The following files were created:%s"),
"\n\n" + String.join("\n", generatedFiles)),
LangUtil.translate("Gerber Export"), IView.INFORMATION_MESSAGE);
String.format(
LangUtil.translate(
"Gerber export completed successfully. The following files were created:%s"),
"\n\n" + String.join("\n", generatedFiles)),
LangUtil.translate("Gerber Export"), IView.INFORMATION_MESSAGE);
LOG.info("Completed export to gerber");
}
private static void drawComponent(Project currentProject, GerberG2DWrapper g2d,
IDIYComponent<?> c, boolean outlineMode) {
IDIYComponent<?> c, boolean outlineMode) {
IGerberComponent gerberComponent = (IGerberComponent) c;
g2d.startedDrawingComponent();
if (gerberComponent instanceof IGerberComponentCustom) {
@@ -151,9 +155,9 @@ public class GerberExporter {
} else if (gerberComponent instanceof IGerberComponentSimple) {
IGerberComponentSimple gerberComponentSimple = (IGerberComponentSimple) gerberComponent;
g2d.startGerberOutput(gerberComponentSimple.getGerberLayer(),
gerberComponentSimple.getGerberFunction(), gerberComponentSimple.isGerberNegative());
gerberComponentSimple.getGerberFunction(), gerberComponentSimple.isGerberNegative());
c.draw(g2d, ComponentState.NORMAL, outlineMode, currentProject, g2d);
g2d.stopGerberOutput();
}
}
}
}
@@ -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() {
List<Language> res = new ArrayList<Language>();
List<File> files = ResourceUtils.getResourceFiles(LANG_DIR);
Map<String, String> langContents = ResourceUtils.getResourceContents(LANG_DIR);
try {
for (File file : files) {
String key = file.getName().replaceFirst("[.][^.]+$", "");
Map<String, String> details = new HashMap<String, String>();
try (Stream<String> stream = Files.lines(
Paths.get(file.getAbsolutePath()), StandardCharsets.UTF_8)) {
stream.forEach(s -> {
if (s.contains("=")) {
String[] parts = s.split("=");
if (parts.length == 2)
details.put(parts[0].toLowerCase().trim(), parts[1].trim());
langContents.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> {
String key = entry.getKey().replaceFirst("[.][^.]+$", "");
Map<String, String> details = new HashMap<String, String>();
try {
String content = entry.getValue();
String[] lines = content.split("\n");
for (String line : lines) {
if (line.contains("=")) {
String[] parts = line.split("=");
if (parts.length == 2)
details.put(parts[0].toLowerCase().trim(), parts[1].trim());
}
}
} catch (Exception e) {
LOG.error("Error loading language file", e);
}
res.add(new Language(key, details));
});
} catch (IOException e) {
LOG.error("Error loading language file", e);
}
res.add(new Language(key, details));
}
Collections.sort(res);
return res;
} catch (Exception e) {
@@ -18,7 +18,6 @@
package org.diylc.presenter;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -42,7 +41,7 @@ import org.diylc.serialization.ProjectFileManager;
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);
@@ -26,12 +26,8 @@ import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.reflect.Modifier;
import java.util.*;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import org.apache.log4j.Logger;
@@ -52,6 +48,11 @@ import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.KeywordPolicy;
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.
@@ -68,6 +69,7 @@ public class ComponentProcessor {
private Map<String, IPropertyValidator> propertyValidatorCache;
private Map<String, ComponentType> componentTypeMap;
private Map<String, IComponentTransformer> componentTransformerMap;
private Map<String, List<ComponentType>> componentTypes;
public static ComponentProcessor getInstance() {
if (instance == null) {
@@ -138,6 +140,10 @@ public class ComponentProcessor {
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
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,
// RenderingHints.VALUE_STROKE_PURE);
componentInstance.drawIcon(g2d, Presenter.ICON_SIZE, Presenter.ICON_SIZE);
@@ -225,6 +231,50 @@ public class ComponentProcessor {
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.
*
@@ -17,10 +17,7 @@
*/
package org.diylc.presenter;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.*;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
@@ -55,16 +52,15 @@ public class DatasheetService {
private DatasheetService() {}
public List<String[]> loadDatasheet(Class<?> clazz) {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
return datasheetCache.computeIfAbsent(clazz.getCanonicalName(), key -> {
String fileName = clazz.getSimpleName() + ".datasheet";
LOG.info("Loading datasheet file for " + fileName);
URL resource = classloader.getResource(fileName);
if (resource == null) {
InputStream inputStream = clazz.getResourceAsStream("/datasheets/" + fileName);
if (inputStream == null) {
LOG.warn("Datasheet file not found: " + fileName);
return null;
}
try (BufferedInputStream in = new BufferedInputStream(resource.openStream())) {
try (BufferedInputStream in = new BufferedInputStream(inputStream)) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
List<String[]> types =
@@ -49,20 +49,9 @@ import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.IConfigurationManager;
import org.diylc.appframework.simplemq.MessageDispatcher;
import org.diylc.common.DrawOption;
import org.diylc.common.EventType;
import org.diylc.common.GridType;
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.common.*;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.core.*;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.diylc.netlist.ContinuityGraph;
@@ -78,6 +67,7 @@ import org.diylc.utils.Constants;
public class DrawingManager {
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 double EXTRA_SPACE = 0.25;
@@ -195,38 +185,35 @@ public class DrawingManager {
G2DWrapper g2dWrapper = new G2DWrapper(g2d, zoom);
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);
configureRenderingHints(g2d, drawOptions);
// group components with boards that contain them
Map<IBoard, List<IDIYComponent<?>>> boardMap = project.getComponents().stream()
.filter(IBoard.class::isInstance)
.map(IBoard.class::cast)
.filter(b -> b.getBoardUndersideDisplay() != BoardUndersideDisplay.NONE)
.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();
Dimension canvasDimension =
@@ -297,7 +284,7 @@ public class DrawingManager {
// drawn in the same state.
boolean trackArea = lastDrawnStateMap.get(component) != state;
synchronized (g2d) {
synchronized (this) {
g2dWrapper.startedDrawingComponent(i);
if (!trackArea) {
g2dWrapper.stopTracking();
@@ -312,11 +299,7 @@ public class DrawingManager {
long componentStart = System.nanoTime();
try {
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);
drawComponent(project, drawOptions, scaleFactor, visibleRect, component, g2dWrapper, state, zoom, i, outlineMode);
if (g2dWrapper.isTrackingContinuityArea()) {
LOG.info("Component " + component.getName() + " of type "
@@ -349,6 +332,29 @@ public class DrawingManager {
componentAreaMap.put(component, area);
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;
}
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 Dimension canvasDimensionCached;
private double extraSpaceCached;
@@ -78,7 +78,6 @@ import org.diylc.core.Project;
import org.diylc.core.Template;
import org.diylc.core.Theme;
import org.diylc.core.VisibilityPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.IAutoCreator;
import org.diylc.core.gerber.GerberExporter;
import org.diylc.core.measures.Size;
@@ -94,11 +93,6 @@ import org.diylc.test.DIYTest;
import org.diylc.test.Snapshot;
import org.diylc.utils.Constants;
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.
@@ -135,6 +129,9 @@ public class Presenter implements IPlugInPort, IConfigListener {
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;
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 Project currentProject;
private Map<String, List<ComponentType>> componentTypes;
// Maps component class names to ComponentType objects.
private List<IPlugIn> plugIns;
@@ -242,7 +238,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
@Override
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
@@ -424,47 +420,7 @@ public class Presenter implements IPlugInPort, IConfigListener {
@SuppressWarnings("unchecked")
@Override
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;
return ComponentProcessor.getInstance().getComponentTypes();
}
@SuppressWarnings({"unchecked"})
@@ -2559,7 +2515,8 @@ public class Presenter implements IPlugInPort, IConfigListener {
}
}
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.addPermission(AnyTypePermission.ANY);
ProjectFileManager.xStreamSerializer.toXML(defaultVariantMap, out);
@@ -21,7 +21,6 @@ import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
@@ -46,7 +45,7 @@ import org.diylc.serialization.ProjectFileManager;
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);
@@ -24,36 +24,78 @@ package org.diylc.utils;
import org.apache.log4j.Logger;
import org.diylc.lang.LangUtil;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ResourceUtils {
private static final Logger LOG = Logger.getLogger(LangUtil.class);
private static final Logger LOG = Logger.getLogger(ResourceUtils.class);
public static List<File> getResourceFiles(String dir) {
List<File> files = new ArrayList<>();
URL url = LangUtil.class.getResource("/" + dir);
Path path = null;
public static Map<String, String> getResourceContents(String dir) {
Map<String, String> contents = new HashMap<>();
try {
path = Paths.get(url.toURI());
Files.walk(path, 5).forEach(p -> {
if (!p.toFile().isDirectory()) {
files.add(p.toFile());
// Get all resources in the directory
URL dirUrl = ResourceUtils.class.getClassLoader().getResource(dir);
if (dirUrl != null) {
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);
}
});
} finally {
try {
jarFile.close();
} catch (IOException e) {
LOG.warn("Could not close JAR file", e);
}
}
} 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 (URISyntaxException e) {
LOG.error("Error loading language file", e);
} catch (IOException e) {
LOG.error("Error loading language file", e);
}
} catch (Exception e) {
LOG.error("Error loading resources from directory: " + dir, e);
}
return files;
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>
<build>0</build>
</versionNumber>
<releaseDate>2025-03-09 00:00:00.000 CET</releaseDate>
<releaseDate>2025-03-24 00:00:00.000 CET</releaseDate>
<name></name>
<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>
<changeType>NEW_FEATURE</changeType>
<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>
<description>Significantly improved rendering performance</description>
</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>
<changeType>IMPROVEMENT</changeType>
<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>
<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>
<changeType>BUG_FIX</changeType>
@@ -281,6 +289,10 @@
<changeType>BUG_FIX</changeType>
<description>Rotating selected components sometimes wacks the alignment off the grid</description>
</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>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
@@ -1,266 +1,80 @@
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.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 {
private DatasheetService service;
@Mock
private ClassLoader mockClassLoader;
private static final Class<?> TEST_CLASS = DatasheetServiceTest.class;
@Before
public void setUp() {
service = DatasheetService.getInstance();
service.clearCache(); // Clear cache before each test
Thread.currentThread().setContextClassLoader(mockClassLoader);
service.clearCache();
}
@Test
public void testLoadDatasheet() throws Exception {
// Create a mock datasheet content
String datasheetContent =
"1N4001,50V,1A,1.1V\n" +
"1N4002,100V,1A,1.1V\n" +
"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]);
public void testLoadDatasheet() {
List<String[]> result = service.loadDatasheet(TEST_CLASS);
assertNotNull(result);
assertEquals(4, result.size());
assertArrayEquals(new String[]{"TEST", "KEY", "10.0", "20.0"}, result.get(0));
}
@Test
public void testLoadDatasheetFileNotFound() {
// Setup the mock ClassLoader to return null (file not found)
when(mockClassLoader.getResource("TestComponent.datasheet"))
.thenReturn(null);
List<String[]> result = service.loadDatasheet(TestComponent.class);
assertNull("Result should be null when file is not found", result);
List<String[]> result = service.loadDatasheet(String.class);
assertNull(result);
}
@Test
public void testLookupExactMatch() throws Exception {
// Create a mock datasheet content
String datasheetContent =
"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]);
public void testLookupExactMatch() {
String[] result = service.lookup(TEST_CLASS, 0.0, "TEST|KEY", 10.0);
assertNotNull(result);
assertEquals("10.0", result[2]);
}
@Test
public void testLookupWithinTolerance() throws Exception {
// Create a mock datasheet content
String datasheetContent =
"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);
public void testLookupWithinTolerance() {
String[] result = service.lookup(TEST_CLASS, 5.0, "TEST|KEY", 10.5);
assertNotNull(result);
assertEquals("10.0", result[2]);
}
@Test
public void testLookupNoMatch() throws Exception {
// Create a mock datasheet content
String datasheetContent =
"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);
public void testLookupOutsideTolerance() {
String[] result = service.lookup(TEST_CLASS, 5.0, "TEST|KEY", 12.0);
assertNull(result);
}
@Test
public void testLookupNonexistentKey() throws Exception {
// Create a mock datasheet content
String datasheetContent =
"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);
public void testLookupNoMatch() {
String[] result = service.lookup(TEST_CLASS, 0.0, "TEST,KEY", 30.0);
assertNull(result);
}
@Test
public void testLookupWithTolerance() throws Exception {
// Create a mock datasheet content with resistor values
String datasheetContent =
"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]);
public void testLookupNonexistentKey() {
String[] result = service.lookup(TEST_CLASS, 0.0, "NONEXISTENT,KEY", 10.0);
assertNull(result);
}
@Test
public void testLookupOutsideTolerance() throws Exception {
// Create a mock datasheet content
String datasheetContent =
"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 value outside tolerance
String[] result = service.lookup(TestComponent.class, 1.0, "0805|1%", 250.0);
assertNull("Should not find matching entry outside tolerance", result);
public void testLookupWithTolerance() {
String[] result = service.lookup(TEST_CLASS, 50.0, "TEST|KEY", 15.0);
assertNotNull(result);
assertEquals("10.0", result[2]);
}
@Test
public void testLookupMultipleValues() throws Exception {
// Create a mock datasheet content with multiple value matches
String datasheetContent =
"TO220,NPN,50,5,0.7\n" + // Vce, Ic, Vbe
"TO220,NPN,60,8,0.7\n" +
"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]);
public void testLookupMultipleValues() {
String[] result = service.lookup(TEST_CLASS, 0.0, "TEST|KEY", 10.0, 20.0);
assertNotNull(result);
assertEquals("10.0", result[2]);
assertEquals("20.0", result[3]);
}
// 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>
@@ -441,7 +441,11 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
stroke = ObjectCache.getInstance().fetchStroke(thickness, new float[] {thickness / 4, thickness * 4}, 0, BasicStroke.CAP_ROUND);
break;
}
Composite oldComposite = g2d.getComposite();
if (getAlpha() < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * getAlpha() / MAX_ALPHA));
}
if (shouldShadeLeads()) {
Shape lineShape = stroke.createStrokedShape(line);
@@ -463,6 +467,7 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
if (isCopperArea)
observer.stopTrackingContinuityArea();
}
g2d.setComposite(oldComposite);
}
protected LineStyle getStyle() {
@@ -35,7 +35,9 @@ import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache;
import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.core.BoardUndersideDisplay;
import org.diylc.core.ComponentState;
import org.diylc.core.IBoard;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
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.SizeUnit;
public abstract class AbstractBoard extends AbstractTransparentComponent<String> {
public abstract class AbstractBoard extends AbstractTransparentComponent<String> implements IBoard {
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 COORDINATE_COLOR = Color.gray.brighter();
@@ -56,7 +59,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
protected String value = "";
// two control points used for controlling the position
protected Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0),
new Point2D.Double(DEFAULT_WIDTH.convertToPixels(), DEFAULT_HEIGHT.convertToPixels())};
new Point2D.Double(DEFAULT_WIDTH.convertToPixels(), DEFAULT_HEIGHT.convertToPixels())};
// top-left and bottom-right points
protected Point2D.Double firstPoint = new Point2D.Double();
protected Point2D.Double secondPoint = new Point2D.Double();
@@ -69,17 +72,20 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
protected CoordinateOrigin coordinateOrigin = CoordinateOrigin.Top_Left;
protected CoordinateDisplay coordinateDisplay = CoordinateDisplay.One_Side;
protected CoordinateType yType = CoordinateType.Letters;
protected Size length;
protected Size width;
protected BoardSizingMode mode = BoardSizingMode.TwoPoints;
protected BoardUndersideDisplay boardUndersideDisplay = BoardUndersideDisplay.NONE;
protected Size undersideOffset = DEFAULT_UNDERSIDE_OFFSET;
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) {
IDrawingObserver drawingObserver) {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
Point2D finalSecondPoint = getFinalSecondPoint();
Point2D finalSecondPoint = getFinalSecondPoint();
Composite oldComposite = g2d.getComposite();
// render as transparent when dragging
@@ -90,64 +96,64 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
g2d.setColor(boardColor);
g2d.fillRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY()));
g2d.setComposite(oldComposite);
// Do not track any changes that follow because the whole board has been
// tracked so far.
drawingObserver.stopTracking();
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: borderColor);
: borderColor);
g2d.drawRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY()));
}
protected Point2D getFinalSecondPoint() {
Point2D finalSecondPoint;
if (getMode() == BoardSizingMode.TwoPoints)
finalSecondPoint = secondPoint;
else
finalSecondPoint = new Point2D.Double(firstPoint.getX() + getLength().convertToPixels(),
firstPoint.getY() + getWidth().convertToPixels());
finalSecondPoint = new Point2D.Double(firstPoint.getX() + getLength().convertToPixels(),
firstPoint.getY() + getWidth().convertToPixels());
return finalSecondPoint;
}
protected void drawCoordinates(Graphics2D g2d, double spacing, Project project) {
g2d.setColor(coordinateColor);
g2d.setFont(project.getFont().deriveFont(COORDINATE_FONT_SIZE));
// The half space is used to do rounding when calculating the range.
double halfSpace = spacing / 2;
CoordinateOrigin origin = getCoordinateOrigin();
Point2D finalSecondPoint = getFinalSecondPoint();
if (getCoordinateDisplay() != CoordinateDisplay.None) {
int range;
double yOffset;
CoordinateType yType = getyType();
double y = firstPoint.getY();
if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Top_Right) {
range = (int) ((finalSecondPoint.getY() - firstPoint.getY() + halfSpace) / spacing);
yOffset = spacing;
range = (int) ((finalSecondPoint.getY() - firstPoint.getY() + halfSpace) / spacing);
yOffset = spacing;
} else {
range = (int) ((finalSecondPoint.getY() - firstPoint.getY() + halfSpace) / spacing);
yOffset = -spacing;
y = finalSecondPoint.getY();
range = (int) ((finalSecondPoint.getY() - firstPoint.getY() + halfSpace) / spacing);
yOffset = -spacing;
y = finalSecondPoint.getY();
}
for (int c = 1; c < range; c++) {
int xOffset = (yType == CoordinateType.Numbers && c >= 10) || (yType == CoordinateType.Letters && c >= 27) ? 0 : 2;
String label = yType == CoordinateType.Letters ? getCoordinateLabel(c) : Integer.toString(c);
y += yOffset;
StringUtils.drawCenteredText(g2d, label,
firstPoint.getX() + xOffset, y,
HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) {
StringUtils.drawCenteredText(g2d, label,
finalSecondPoint.getX() - xOffset, y,
HorizontalAlignment.RIGHT, VerticalAlignment.CENTER);
}
int xOffset = (yType == CoordinateType.Numbers && c >= 10) || (yType == CoordinateType.Letters && c >= 27) ? 0 : 2;
String label = yType == CoordinateType.Letters ? getCoordinateLabel(c) : Integer.toString(c);
y += yOffset;
StringUtils.drawCenteredText(g2d, label,
firstPoint.getX() + xOffset, y,
HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) {
StringUtils.drawCenteredText(g2d, label,
finalSecondPoint.getX() - xOffset, y,
HorizontalAlignment.RIGHT, VerticalAlignment.CENTER);
}
}
}
@@ -155,8 +161,8 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
int range;
double xOffset;
CoordinateType xType = getxType();
double x = firstPoint.getX();
double x = firstPoint.getX();
if (origin == CoordinateOrigin.Top_Left || origin == CoordinateOrigin.Bottom_Left) {
range = (int) ((finalSecondPoint.getX() - firstPoint.getX() + halfSpace) / spacing);
xOffset = spacing;
@@ -165,19 +171,19 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
xOffset = -spacing;
x = finalSecondPoint.getX();
}
for (int c = 1; c < range; c++) {
String label = xType == CoordinateType.Letters ? getCoordinateLabel(c) : Integer.toString(c);
x += xOffset;
StringUtils.drawCenteredText(g2d, label,
x, firstPoint.getY() + 2,
HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
StringUtils.drawCenteredText(g2d, label,
x, firstPoint.getY() + 2,
HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
if (getCoordinateDisplay() == CoordinateDisplay.Both_Sides) {
StringUtils.drawCenteredText(g2d, label,
x, (int) (finalSecondPoint.getY() - COORDINATE_FONT_SIZE),
HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
StringUtils.drawCenteredText(g2d, label,
x, (int) (finalSecondPoint.getY() - COORDINATE_FONT_SIZE),
HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);
}
}
}
@@ -225,7 +231,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
public void setBorderColor(Color borderColor) {
this.borderColor = borderColor;
}
@EditableProperty(name = "X")
public CoordinateType getxType() {
if (xType == null)
@@ -250,15 +256,15 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
@EditableProperty(name = "Coordinate Origin")
public CoordinateOrigin getCoordinateOrigin() {
if (coordinateOrigin == null)
coordinateOrigin = CoordinateOrigin.Top_Left;
return coordinateOrigin;
if (coordinateOrigin == null)
coordinateOrigin = CoordinateOrigin.Top_Left;
return coordinateOrigin;
}
public void setCoordinateOrigin(CoordinateOrigin coordinateOrigin) {
this.coordinateOrigin = coordinateOrigin;
this.coordinateOrigin = coordinateOrigin;
}
@EditableProperty(name = "Y")
public CoordinateType getyType() {
if (yType == null)
@@ -294,9 +300,9 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
public void setControlPoint(Point2D point, int index) {
controlPoints[index].setLocation(point);
firstPoint.setLocation(Math.min(controlPoints[0].getX(), controlPoints[1].getX()),
Math.min(controlPoints[0].getY(), controlPoints[1].getY()));
Math.min(controlPoints[0].getY(), controlPoints[1].getY()));
secondPoint.setLocation(Math.max(controlPoints[0].getX(), controlPoints[1].getX()),
Math.max(controlPoints[0].getY(), controlPoints[1].getY()));
Math.max(controlPoints[0].getY(), controlPoints[1].getY()));
}
@EditableProperty
@@ -309,13 +315,13 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
public void setValue(String value) {
this.value = value;
}
private SizeUnit getDefaultUnit() {
if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.METRIC_KEY, true))
return SizeUnit.mm;
return SizeUnit.in;
return SizeUnit.in;
}
@EditableProperty(name = "Explicit Length", validatorClass = BoardModeValidator.class)
public Size getLength() {
if (getMode() == BoardSizingMode.TwoPoints) {
@@ -327,12 +333,12 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
public void setLength(Size length) {
if (getMode() == BoardSizingMode.Explicit && length != null && width != null) {
setControlPoint(firstPoint, 0);
setControlPoint(firstPoint, 0);
Point2D second = new Point2D.Double(firstPoint.getX() + length.convertToPixels(),
firstPoint.getY() + width.convertToPixels());
setControlPoint(second, 1);
firstPoint.getY() + width.convertToPixels());
setControlPoint(second, 1);
}
this.length = length;
this.length = length;
}
@EditableProperty(name = "Explicit Width", validatorClass = BoardModeValidator.class)
@@ -352,7 +358,7 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
}
this.width = width;
}
@EditableProperty(name = "Dimension Mode")
public BoardSizingMode getMode() {
if (mode == null)
@@ -363,27 +369,66 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
public void setMode(BoardSizingMode 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
public Rectangle2D getCachingBounds() {
Point2D finalSecondPoint = getFinalSecondPoint();
return new Rectangle2D.Double(Math.min(firstPoint.getX(), finalSecondPoint.getX()) - 2, Math.min(firstPoint.getY(), finalSecondPoint.getY()) - 2,
Math.abs(finalSecondPoint.getX() - firstPoint.getX()) + 4, Math.abs(finalSecondPoint.getY() - firstPoint.getY()) + 4);
Point2D finalSecondPoint = getFinalSecondPoint();
return new Rectangle2D.Double(Math.min(firstPoint.getX(), finalSecondPoint.getX()) - 2, Math.min(firstPoint.getY(), finalSecondPoint.getY()) - 2,
Math.abs(finalSecondPoint.getX() - firstPoint.getX()) + 4, Math.abs(finalSecondPoint.getY() - firstPoint.getY()) + 4);
}
public static enum CoordinateType {
Letters, Numbers
}
public static enum CoordinateDisplay {
None, One_Side, Both_Sides;
@Override
public String toString() {
return super.toString().replace('_', ' ');
};
}
public static enum CoordinateOrigin {
Top_Left, Top_Right, Bottom_Right, Bottom_Left;
@@ -392,19 +437,19 @@ public abstract class AbstractBoard extends AbstractTransparentComponent<String>
return super.toString().replace('_', ' ');
};
}
public static enum BoardSizingMode {
TwoPoints("Opposing Points"), Explicit("Explicit Dimensions");
private String label;
private BoardSizingMode(String label) {
this.label = label;
}
@Override
public String toString() {
return label;
}
}
}
}
}
@@ -38,12 +38,11 @@ import org.diylc.core.Project;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.gerber.IGerberBoard;
@ComponentDescriptor(name = "Blank Board", category = "Boards", author = "Branislav Stojkovic",
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board",
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, transformer = SimpleComponentTransformer.class)
public class BlankBoard extends AbstractBoard implements IGerberBoard {
zOrder = IDIYComponent.BOARD, instanceNamePrefix = "Board", description = "Blank circuit board",
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, autoEdit = false, transformer = SimpleComponentTransformer.class)
public class BlankBoard extends AbstractBoard {
private static final long serialVersionUID = 1L;
@@ -60,14 +59,14 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard {
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) {
Point2D finalSecondPoint = getFinalSecondPoint();
IDrawingObserver drawingObserver) {
Point2D finalSecondPoint = getFinalSecondPoint();
Shape clip = g2d.getClip();
if (checkPointsClipped(clip) && !clip.contains(firstPoint.getX(), finalSecondPoint.getY())
&& !clip.contains(finalSecondPoint.getX(), firstPoint.getY())) {
&& !clip.contains(finalSecondPoint.getX(), firstPoint.getY())) {
return;
}
}
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
if (componentState != ComponentState.DRAGGING) {
@@ -86,13 +85,13 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard {
// tracked so far.
drawingObserver.stopTracking();
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: borderColor);
: borderColor);
if (getType() == Type.SQUARE)
g2d.drawRect((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY()));
else
g2d.drawOval((int)firstPoint.getX(), (int)firstPoint.getY(), (int)(finalSecondPoint.getX() - firstPoint.getX()), (int)(finalSecondPoint.getY() - firstPoint.getY()));
}
@Override
public CoordinateType getxType() {
// Override to prevent editing.
@@ -128,12 +127,17 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard {
public void setType(Type type) {
this.type = type;
}
@Override
public String getControlPointNodeName(int index) {
return null;
}
@Override
public boolean shouldExportToGerber() {
return true;
}
static enum Type {
ROUND, SQUARE;
@@ -142,12 +146,4 @@ public class BlankBoard extends AbstractBoard implements IGerberBoard {
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();
}
@Override
public Byte getAlpha() {
return super.getAlpha();
}
@Override
public Size getLength() {
return super.getLength();
@@ -111,11 +111,6 @@ public class CurvedTrace extends AbstractCurvedComponent<Void> implements ILayer
@Override
public void setValue(Void value) {}
@Override
public Byte getAlpha() {
return super.getAlpha();
}
@Override
public void setAlpha(Byte alpha) {
super.setAlpha(alpha);
@@ -21,13 +21,13 @@
*/
package org.diylc.components.connectivity;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.common.ObjectCache;
import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.ComponentState;
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,
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class,
enableCache = true)
public class Eyelet extends AbstractComponent<String> {
public class Eyelet extends AbstractTransparentComponent<String> {
private static final long serialVersionUID = 1L;
@@ -71,6 +71,12 @@ public class Eyelet extends AbstractComponent<String> {
}
int diameter = getClosestOdd((int) size.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.setColor(color);
drawingObserver.startTrackingContinuityArea(true);
@@ -84,6 +90,8 @@ public class Eyelet extends AbstractComponent<String> {
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: color.darker());
g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter);
g2d.setComposite(oldComposite);
}
@Override
@@ -21,8 +21,7 @@
*/
package org.diylc.components.connectivity;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.geom.Point2D;
import java.util.Arrays;
import java.util.EnumSet;
@@ -33,6 +32,7 @@ import com.bancika.gerberwriter.GerberFunctions;
import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
@@ -52,7 +52,8 @@ import org.diylc.core.measures.SizeUnit;
@ComponentDescriptor(name = "Ground Fill", author = "Branislav Stojkovic", category = "Connectivity",
instanceNamePrefix = "GF", description = "Polygonal ground fill area", zOrder = IDIYComponent.TRACE,
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;
@@ -83,7 +84,12 @@ public class GroundFill extends AbstractComponent<Void> implements ILayeredCompo
yPoints[i] = (int)controlPoints[i].getY();
}
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.setComposite(oldComposite);
drawingObserver.stopTrackingContinuityArea();
// Do not track any changes that follow because the whole board has been
// tracked so far.
@@ -103,11 +103,6 @@ public class Jumper extends AbstractLeadedComponent<Void> implements IContinuity
return super.getBorderColor();
}
@Override
public Byte getAlpha() {
return super.getAlpha();
}
@Override
public Size getLength() {
return super.getLength();
@@ -233,11 +233,6 @@ public class Line extends AbstractLeadedComponent<Void> {
return super.getBorderColor();
}
@Override
public Byte getAlpha() {
return super.getAlpha();
}
@Override
public Size getLength() {
return super.getLength();
@@ -17,8 +17,7 @@
*/
package org.diylc.components.connectivity;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
@@ -29,6 +28,7 @@ import com.bancika.gerberwriter.GerberFunctions;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.ComponentState;
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,
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "PCB",
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;
@@ -90,6 +91,11 @@ public class SolderPad extends AbstractComponent<Void> implements ILayeredCompon
gerberDrawingObserver.startGerberOutput(gerberCopperLayer, GerberFunctions.CONNECTOR_PAD, 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) {
g2d.fill(new Ellipse2D.Double(point.getX() - diameter / 2, point.getY() - diameter / 2,
diameter, diameter));
@@ -116,6 +122,7 @@ public class SolderPad extends AbstractComponent<Void> implements ILayeredCompon
g2d.fill(new Ellipse2D.Double(point.getX() - holeDiameter / 2,
point.getY() - holeDiameter / 2, holeDiameter, holeDiameter));
}
g2d.setComposite(oldComposite);
if (gerberDrawingObserver != null)
gerberDrawingObserver.stopGerberOutput();
}
@@ -21,14 +21,14 @@
*/
package org.diylc.components.connectivity;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.common.ObjectCache;
import org.diylc.common.OrientationHV;
import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.boards.AbstractBoard;
import org.diylc.components.boards.VeroBoard;
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",
zOrder = IDIYComponent.BOARD + 1, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
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;
@@ -79,6 +79,10 @@ public class TraceCut extends AbstractComponent<Void> implements ILayeredCompone
if (checkPointsClipped(g2d.getClip())) {
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));
int size = getClosestOdd((int) this.size.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.drawOval((int)(point.getX() - holeSize / 2), (int)(point.getY() - holeSize / 2), holeSize, holeSize);
}
g2d.setComposite(oldComposite);
}
@Override
@@ -21,13 +21,13 @@
*/
package org.diylc.components.connectivity;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.common.ObjectCache;
import org.diylc.components.AbstractComponent;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.transform.SimpleComponentTransformer;
import org.diylc.core.ComponentState;
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,
keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME, transformer = SimpleComponentTransformer.class,
enableCache = true)
public class Turret extends AbstractComponent<String> {
public class Turret extends AbstractTransparentComponent<String> {
private static final long serialVersionUID = 1L;
@@ -67,6 +67,10 @@ public class Turret extends AbstractComponent<String> {
if (checkPointsClipped(g2d.getClip())) {
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 holeDiameter = getClosestOdd((int) holeSize.convertToPixels());
g2d.setColor(color);
@@ -82,6 +86,7 @@ public class Turret extends AbstractComponent<String> {
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: color.darker());
g2d.drawOval((int)(point.getX() - holeDiameter / 2), (int)(point.getY() - holeDiameter / 2), holeDiameter, holeDiameter);
g2d.setComposite(oldComposite);
}
@Override
@@ -304,7 +304,8 @@ public class Freeway3x3_03 extends AbstractTransparentComponent<Void> implements
if (svgDiagram == null) {
try {
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);
SVGUniverse universe = new SVGUniverse();
URI url = universe.loadSVG(bis,
@@ -40,7 +40,6 @@ import org.diylc.awt.ImageUtils;
import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation;
import org.diylc.components.AbstractTransparentComponent;
import org.diylc.components.boards.AbstractBoard;
import org.diylc.components.transform.ImageTransformer;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
@@ -72,7 +71,7 @@ public class Image extends AbstractTransparentComponent<Void> {
private Orientation orientation;
static {
String name = "/image.png";
String name = "/diylc-library-images/image.png";
try (InputStream inputStream = Image.class.getResourceAsStream(name)) {
if (inputStream != null) {
ICON = new ImageIcon(inputStream.readAllBytes(), name);
@@ -99,7 +98,7 @@ public class Image extends AbstractTransparentComponent<Void> {
public Image() {
try {
data = IOUtils.toByteArray(Image.class.getResourceAsStream("/image.png"));
data = IOUtils.toByteArray(Image.class.getResourceAsStream("/diylc-library-images/image.png"));
} catch (IOException e) {
e.printStackTrace();
}
@@ -81,7 +81,8 @@ public class SVGImage extends AbstractTransparentComponent<Void> {
public SVGImage() {
try {
data = IOUtils.toByteArray(SVGImage.class.getResourceAsStream("/diylc.svg"));
data = IOUtils.toByteArray(SVGImage.class.getResourceAsStream(
"/diylc-library-images/diylc.svg"));
} catch (IOException e) {
e.printStackTrace();
}
@@ -43,7 +43,7 @@ public class CliffJackTransformer implements IComponentTransformer {
@Override
public boolean mirroringChangesCircuit() {
return true;
return false;
}
@Override
@@ -48,14 +48,26 @@ public class MiniToggleSwitchTransformer implements IComponentTransformer {
@Override
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;
// 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();
int oValue = o.ordinal();
oValue += direction;
@@ -65,6 +77,29 @@ public class MiniToggleSwitchTransformer implements IComponentTransformer {
oValue = 0;
o = OrientationHV.values()[oValue];
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

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
#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"
# Check if Java is available
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)"
echo "diylc.sh: Using system Java: $JAVA"
fi
# Debug: Check Java existence
if [ ! -x "$JAVA" ]; then
echo "diylc.sh: ERROR - Java binary not found or not executable!"
# Use system Java
JAVA="$(which java)"
if [ -z "$JAVA" ] || [ ! -x "$JAVA" ]; then
echo "diylc.sh: ERROR - System Java not found or not executable!"
echo "diylc.sh: Please install Java 17 or later"
exit 1
fi
echo "diylc.sh: Using system Java: $JAVA"
cd "$HERE"
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"
exec "$JAVA" \
-Xms512m \
-Xms1024m \
-Xmx4096m \
-cp "$HERE/../lib/diylc.jar" \
--add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED \
--add-exports java.desktop/com.apple.eio=ALL-UNNAMED \
-cp "$APPDIR/usr/lib/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 \
+16 -1
View File
@@ -2,4 +2,19 @@
JAVA_BIN="$(which java)"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
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>
<minVersion>17</minVersion>
<maxVersion></maxVersion>
<initialHeapSize>512</initialHeapSize>
<initialHeapSize>1024</initialHeapSize>
<maxHeapSize>4096</maxHeapSize>
<opt>-Dorg.diylc.scriptRun=true</opt>
<opt>-Dfile.encoding=UTF-8</opt>
+5
View File
@@ -74,6 +74,7 @@ And
Angle
Angle Offset
Anti-Aliasing
Apply Model
Arrow Size
Author
Auto-Create Pads
@@ -85,6 +86,8 @@ Below
Board
Board Color
Board Width
Board1
Board2
Boards
Bobbin 1
Bobbin 2
@@ -588,6 +591,8 @@ Tubular Beveled
Two
Type
Ultra-miniature
Underside Display
Underside Offset
Underside Pad Color
Underside Trace Color
Undo
+113 -93
View File
@@ -260,47 +260,6 @@
</target>
</configuration>
</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>
</plugin>
</plugins>
@@ -328,7 +287,7 @@
<goal>single</goal>
</goals>
<configuration>
<finalName>diylc-${project.version}</finalName>
<finalName>diylc-${project.version}-universal</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
@@ -391,39 +350,6 @@
<copy file="${project.basedir}/deploy/linux/appimage/com.diy_fever.DIYLayoutCreator.metainfo.xml"
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}" />
</target>
</configuration>
@@ -539,9 +465,17 @@
<fileset dir="${appdir.dir}" />
</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">
<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>
<!-- Copy the AppImage to the build directory -->
@@ -703,6 +637,49 @@
</configuration>
</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 -->
<execution>
<id>create-mac-bundle</id>
@@ -740,7 +717,7 @@
<runtime dir="${jre.dest.osx}/Contents/Home" />
<arch name="x86_64"/>
<classpath file="${project.build.directory}/diylc.jar" />
<option value="-Xms512m" />
<option value="-Xms1024m" />
<option value="-Xmx4096m" />
<option value="--add-exports=java.desktop/com.apple.eawt.event=ALL-UNNAMED" />
<option value="--add-exports=java.desktop/com.apple.eio=ALL-UNNAMED" />
@@ -760,13 +737,6 @@
<option value="-Xdock:name=DIY Layout Creator"/>
<option value="-Xdock:icon=Contents/Resources/diylc.icns"/>
</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..."/>
<!-- Create unsigned zip for distribution -->
@@ -776,6 +746,13 @@
</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 -->
<echo message="Signing complete app bundle..."/>
<exec executable="codesign" failonerror="true">
@@ -973,6 +950,49 @@
</configuration>
</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 -->
<execution>
<id>create-mac-bundle</id>
@@ -1011,7 +1031,7 @@
<arch name="arm64"/>
<arch name="arm64e"/>
<classpath file="${project.build.directory}/diylc.jar" />
<option value="-Xms512m" />
<option value="-Xms1024m" />
<option value="-Xmx4096m" />
<option value="--add-exports=java.desktop/com.apple.eawt.event=ALL-UNNAMED" />
<option value="--add-exports=java.desktop/com.apple.eio=ALL-UNNAMED" />
@@ -1031,13 +1051,6 @@
<option value="-Xdock:name=DIY Layout Creator"/>
<option value="-Xdock:icon=Contents/Resources/diylc.icns"/>
</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..."/>
<!-- Create unsigned zip for distribution -->
@@ -1047,6 +1060,13 @@
</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 -->
<echo message="Signing complete app bundle..."/>
<exec executable="codesign" failonerror="true">
@@ -28,7 +28,7 @@ public class CopyAction extends AbstractAction {
this.clipboardOwner = clipboardOwner;
putValue(AbstractAction.NAME, "Copy");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Copy.getIcon());
}
@@ -28,7 +28,7 @@ public class CutAction extends AbstractAction {
this.clipboardOwner = clipboardOwner;
putValue(AbstractAction.NAME, "Cut");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_X,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Cut.getIcon());
}
@@ -40,4 +40,4 @@ public class CutAction extends AbstractAction {
clipboardOwner);
plugInPort.deleteSelectedComponents();
}
}
}
@@ -21,7 +21,7 @@ public class DuplicateAction extends AbstractAction {
this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Duplicate");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_D,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.DocumentsGear.getIcon());
}
@@ -34,4 +34,4 @@ public class DuplicateAction extends AbstractAction {
ActionFactory.LOG.error("Coule not duplicate.", ex);
}
}
}
}
@@ -23,7 +23,7 @@ public class EditSelectionAction extends AbstractAction {
this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Edit Selection");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_E,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.EditComponent.getIcon());
}
@@ -21,7 +21,7 @@ public class GroupAction extends AbstractAction {
this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Group Selection");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_G,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Group.getIcon());
}
@@ -30,4 +30,4 @@ public class GroupAction extends AbstractAction {
ActionFactory.LOG.info("Group Selection triggered");
plugInPort.groupSelectedComponents();
}
}
}
@@ -32,7 +32,7 @@ public class NudgeAction extends AbstractAction {
putValue(AbstractAction.NAME, "Nudge");
putValue(AbstractAction.SMALL_ICON, IconLoader.FitToSize.getIcon());
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Q,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
}
@Override
@@ -56,4 +56,4 @@ public class NudgeAction extends AbstractAction {
plugInPort.nudgeSelection(n.getxOffset(), n.getyOffset(), n.getAffectStuckComponents());
}
}
}
}
@@ -27,7 +27,7 @@ public class PasteAction extends AbstractAction {
this.clipboard = clipboard;
putValue(AbstractAction.NAME, "Paste");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_V,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Paste.getIcon());
}
@@ -43,4 +43,4 @@ public class PasteAction extends AbstractAction {
ActionFactory.LOG.error("Coule not paste.", ex);
}
}
}
}
@@ -21,7 +21,7 @@ public class SelectAllAction extends AbstractAction {
this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Select All");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Selection.getIcon());
}
@@ -30,4 +30,4 @@ public class SelectAllAction extends AbstractAction {
ActionFactory.LOG.info("Select All triggered");
plugInPort.selectAll(0);
}
}
}
@@ -21,7 +21,7 @@ public class UngroupAction extends AbstractAction {
this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "Ungroup Selection");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_U,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.Ungroup.getIcon());
}
@@ -66,7 +66,7 @@ public class ImportAction extends AbstractAction {
}, InMemoryConfigurationManager.getInstance());
putValue(AbstractAction.NAME, "Import");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.ElementInto.getIcon());
}
@@ -107,4 +107,4 @@ public class ImportAction extends AbstractAction {
}, true);
}
}
}
}
@@ -28,7 +28,7 @@ public class NewAction extends AbstractAction {
this.plugInPort = plugInPort;
putValue(AbstractAction.NAME, "New");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.DocumentPlain.getIcon());
}
@@ -54,4 +54,4 @@ public class NewAction extends AbstractAction {
}
}
}
}
}
@@ -28,7 +28,7 @@ public class OpenAction extends AbstractAction {
this.swingUI = swingUI;
putValue(AbstractAction.NAME, "Open");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.FolderOut.getIcon());
}
@@ -28,7 +28,7 @@ public class SaveAction extends AbstractAction {
this.swingUI = swingUI;
putValue(AbstractAction.NAME, "Save");
putValue(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
putValue(AbstractAction.SMALL_ICON, IconLoader.DiskBlue.getIcon());
}
@@ -79,4 +79,4 @@ public class SaveAction extends AbstractAction {
}, true);
}
}
}
}
@@ -29,7 +29,7 @@ public class SaveAsAction extends AbstractAction {
this.swingUI = swingUI;
putValue(AbstractAction.NAME, "Save As");
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());
}
@@ -63,4 +63,4 @@ public class SaveAsAction extends AbstractAction {
}, true);
}
}
}
}
@@ -22,6 +22,7 @@ import java.io.FileInputStream;
import java.io.InputStream;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import javax.swing.Icon;
import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager;
@@ -174,23 +175,24 @@ public class ConfigPlugin implements IPlugIn {
ActionFactory.getInstance()
.createConfigAction(plugInPort, "Sticky Points", IPlugInPort.STICKY_POINTS_KEY, true), CONFIG_MENU);
List<File> themeFiles = ResourceUtils.getResourceFiles(THEMES_DIR);
if (!themeFiles.isEmpty()) {
Map<String, String> themeContents = ResourceUtils.getResourceContents(THEMES_DIR);
if (!themeContents.isEmpty()) {
XStream xStream = new XStream(new DomDriver());
xStream.addPermission(AnyTypePermission.ANY);
swingUI.injectSubmenu(THEME_MENU, IconLoader.Pens.getIcon(), CONFIG_MENU);
for (File file : themeFiles) {
if (file.getName().toLowerCase().endsWith(".xml")) {
try {
InputStream in = new FileInputStream(file);
Theme theme = (Theme) xStream.fromXML(in);
LOG.debug("Found theme: " + theme.getName());
swingUI.injectMenuAction(ActionFactory.getInstance().createThemeAction(plugInPort, theme), THEME_MENU);
} catch (Exception e) {
LOG.error("Could not load theme file " + file.getName(), e);
}
}
}
themeContents.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> {
if (entry.getKey().toLowerCase().endsWith(".xml")) {
try {
Theme theme = (Theme) xStream.fromXML(entry.getValue());
LOG.debug("Found theme: " + theme.getName());
swingUI.injectMenuAction(ActionFactory.getInstance().createThemeAction(plugInPort, theme), THEME_MENU);
} catch (Exception e) {
LOG.error("Could not load theme file " + entry.getKey(), e);
}
}
});
}
swingUI.injectSubmenu(COMPONENT_BROWSER_MENU, IconLoader.Hammer.getIcon(), CONFIG_MENU);
@@ -90,8 +90,7 @@ public class ExplorerPlugin implements IPlugIn {
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if ((canvasPanel.hasFocus() || explorerPane.hasFocus())
&& e.getKeyChar() == 'x'
if (e.getKeyChar() == 'x' && e.getModifiersEx() == 0
&& ConfigurationManager.getInstance()
.readBoolean(ConfigPlugin.PROJECT_EXPLORER, true)) {
explorerPane.getSearchField().requestFocusInWindow();
@@ -86,7 +86,7 @@ public class FileMenuPlugin implements IPlugIn, IDynamicSubmenuHandler {
swingUI.injectMenuAction(
actionFactory.createExportGerberAction(plugInPort, swingUI), EXPORT_TITLE);
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.injectMenuAction(actionFactory.createExportPDFAction(plugInPort,
traceMaskDrawingProvider, swingUI, " (mask)"), TRACE_MASK_TITLE);
@@ -94,7 +94,7 @@ public class FileMenuPlugin implements IPlugIn, IDynamicSubmenuHandler {
traceMaskDrawingProvider, swingUI, " (mask)"), TRACE_MASK_TITLE);
swingUI.injectMenuAction(
actionFactory.createPrintAction(traceMaskDrawingProvider, swingUI,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | KeyEvent.SHIFT_DOWN_MASK),
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx() | KeyEvent.SHIFT_DOWN_MASK),
TRACE_MASK_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(AbstractAction.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_0 + zOrder,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()));
visibleActionMap.put(layer, visibleAction);
AbstractAction selectAllAction = new AbstractAction("Select All") {
+2 -2
View File
@@ -23,7 +23,7 @@
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<log4j.version>1.2.15</log4j.version>
<xstream.version>1.4.19</xstream.version>
<xstream.version>1.4.21</xstream.version>
</properties>
<!-- Build configuration will be defined below -->
@@ -61,7 +61,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>