mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-07 12:24:58 +10:00
Merge branch 'master' into ui-theme
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
name: Sign Windows Launcher
|
||||
|
||||
# Signs the committed launch4j launcher that the installer embeds. Run it only after launch4j
|
||||
# regenerates the launcher, then commit the signed diylc-x64.exe from the artifact over
|
||||
# diylc/diylc-swing/deploy/win/diylc-x64.exe so Sign Windows Artifacts packs it.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
signing-policy-slug:
|
||||
description: 'SignPath signing policy'
|
||||
type: choice
|
||||
default: test-signing
|
||||
options:
|
||||
- test-signing
|
||||
- release-signing
|
||||
|
||||
permissions:
|
||||
# write is needed only to delete the unsigned launcher once SignPath has fetched it
|
||||
actions: write
|
||||
contents: read
|
||||
|
||||
env:
|
||||
SIGNPATH_ORGANIZATION_ID: 95470a00-59e6-430c-9c81-7393ad16d4e8
|
||||
SIGNPATH_PROJECT_SLUG: diy-layout-creator
|
||||
|
||||
jobs:
|
||||
launcher:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
# re-signing would stack a second signature on top of the committed one
|
||||
- name: Check the committed launcher is unsigned
|
||||
run: |
|
||||
if python3 diylc/diylc-swing/deploy/win/signpath/is-signed.py \
|
||||
diylc/diylc-swing/deploy/win/diylc-x64.exe; then
|
||||
echo "::error::deploy/win/diylc-x64.exe is already signed. Commit an unsigned launcher from launch4j first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Upload unsigned launcher
|
||||
id: upload-unsigned-launcher
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: unsigned-launcher
|
||||
path: diylc/diylc-swing/deploy/win/diylc-x64.exe
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
- name: Sign launcher
|
||||
uses: signpath/github-action-submit-signing-request@v3
|
||||
with:
|
||||
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||
organization-id: ${{ env.SIGNPATH_ORGANIZATION_ID }}
|
||||
project-slug: ${{ env.SIGNPATH_PROJECT_SLUG }}
|
||||
signing-policy-slug: ${{ inputs.signing-policy-slug }}
|
||||
artifact-configuration-slug: windows-launcher
|
||||
github-artifact-id: ${{ steps.upload-unsigned-launcher.outputs.artifact-id }}
|
||||
wait-for-completion: true
|
||||
output-artifact-directory: signed
|
||||
|
||||
- name: Delete unsigned launcher artifact
|
||||
if: always() && steps.upload-unsigned-launcher.outputs.artifact-id != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
ARTIFACT_ID: ${{ steps.upload-unsigned-launcher.outputs.artifact-id }}
|
||||
run: gh api -X DELETE "repos/${GITHUB_REPOSITORY}/actions/artifacts/${ARTIFACT_ID}"
|
||||
|
||||
- name: Verify signed launcher
|
||||
run: |
|
||||
python3 diylc/diylc-swing/deploy/win/signpath/is-signed.py signed/diylc-x64.exe
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y osslsigncode
|
||||
# chain validation fails against the self-signed test certificate by design; what
|
||||
# matters is that a signature is present and names the expected subject
|
||||
osslsigncode verify -in signed/diylc-x64.exe || true
|
||||
|
||||
- name: Upload signed launcher
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: diylc-windows-launcher-signed
|
||||
path: signed/diylc-x64.exe
|
||||
if-no-files-found: error
|
||||
@@ -0,0 +1,133 @@
|
||||
name: Sign Windows Artifacts
|
||||
|
||||
# Builds and signs the Inno Setup installer; the zip package is not built or signed here. The
|
||||
# launcher the installer embeds is signed separately and committed by the Sign Windows Launcher
|
||||
# workflow, because Inno Setup cannot sign its payload after the fact and the launcher changes
|
||||
# only when launch4j regenerates it.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
signing-policy-slug:
|
||||
description: 'SignPath signing policy'
|
||||
type: choice
|
||||
default: test-signing
|
||||
options:
|
||||
- test-signing
|
||||
- release-signing
|
||||
|
||||
permissions:
|
||||
# write is needed only to delete the unsigned installer once SignPath has fetched it
|
||||
actions: write
|
||||
contents: read
|
||||
|
||||
env:
|
||||
SIGNPATH_ORGANIZATION_ID: 95470a00-59e6-430c-9c81-7393ad16d4e8
|
||||
SIGNPATH_PROJECT_SLUG: diy-layout-creator
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v6
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
cache: maven
|
||||
|
||||
# Nothing downstream fails when the committed launcher is unsigned: the installed
|
||||
# application would just silently ship an unsigned executable.
|
||||
- name: Check the committed launcher carries a signature
|
||||
env:
|
||||
POLICY: ${{ inputs.signing-policy-slug }}
|
||||
run: |
|
||||
if python3 diylc/diylc-swing/deploy/win/signpath/is-signed.py \
|
||||
diylc/diylc-swing/deploy/win/diylc-x64.exe; then
|
||||
exit 0
|
||||
fi
|
||||
if [ "$POLICY" = "release-signing" ]; then
|
||||
echo "::error::deploy/win/diylc-x64.exe is unsigned. Run the Sign Windows Launcher workflow with the release policy, commit the signed launcher, then re-run this workflow."
|
||||
exit 1
|
||||
fi
|
||||
echo "::warning::deploy/win/diylc-x64.exe is unsigned; the installed application will ship an unsigned launcher."
|
||||
|
||||
- name: Resolve project version
|
||||
working-directory: diylc
|
||||
run: |
|
||||
echo "DIYLC_VERSION=$(mvn -q -N help:evaluate -Dexpression=project.version -DforceStdout)" >> "$GITHUB_ENV"
|
||||
|
||||
# amake/innosetup runs Inno Setup under wine as its own user (uid 1000), not as the runner
|
||||
# (uid 1001), so it cannot write its output into a target directory the runner owns. Docker
|
||||
# Desktop hides this on a developer machine; on a Linux runner it surfaces as "Error 5:
|
||||
# Access denied" copying Setup.e32.
|
||||
- name: Build Windows installer
|
||||
working-directory: diylc
|
||||
run: |
|
||||
mkdir -p diylc-swing/target
|
||||
chmod a+rwx diylc-swing/target
|
||||
mvn -B -DskipTests -P win64-installer package
|
||||
|
||||
# upload-artifact zips the staged installer and SignPath signs the exe inside that zip; the
|
||||
# action then downloads and unpacks the signed zip into signed/. The artifact configuration
|
||||
# matches a fixed path, so the versioned installer travels under a stable name and is
|
||||
# renamed back afterwards.
|
||||
- name: Stage installer for signing
|
||||
run: |
|
||||
mkdir -p staging
|
||||
cp "diylc/diylc-swing/target/diylc-${DIYLC_VERSION}-win64.exe" staging/diylc-setup.exe
|
||||
|
||||
- name: Upload unsigned installer
|
||||
id: upload-unsigned-installer
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: unsigned-installer
|
||||
path: staging/diylc-setup.exe
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
- name: Sign installer
|
||||
uses: signpath/github-action-submit-signing-request@v3
|
||||
with:
|
||||
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||
organization-id: ${{ env.SIGNPATH_ORGANIZATION_ID }}
|
||||
project-slug: ${{ env.SIGNPATH_PROJECT_SLUG }}
|
||||
signing-policy-slug: ${{ inputs.signing-policy-slug }}
|
||||
artifact-configuration-slug: windows-installer
|
||||
github-artifact-id: ${{ steps.upload-unsigned-installer.outputs.artifact-id }}
|
||||
wait-for-completion: true
|
||||
output-artifact-directory: signed
|
||||
|
||||
# SignPath can only fetch the installer from a GitHub artifact, so the unsigned upload cannot
|
||||
# be skipped; it is deleted as soon as signing is over, whether or not signing succeeded.
|
||||
- name: Delete unsigned installer artifact
|
||||
if: always() && steps.upload-unsigned-installer.outputs.artifact-id != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
ARTIFACT_ID: ${{ steps.upload-unsigned-installer.outputs.artifact-id }}
|
||||
run: gh api -X DELETE "repos/${GITHUB_REPOSITORY}/actions/artifacts/${ARTIFACT_ID}"
|
||||
|
||||
- name: Verify signed installer
|
||||
run: |
|
||||
python3 diylc/diylc-swing/deploy/win/signpath/is-signed.py signed/diylc-setup.exe
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y osslsigncode
|
||||
# chain validation fails against the self-signed test certificate by design; what
|
||||
# matters is that a signature is present and names the expected subject
|
||||
osslsigncode verify -in signed/diylc-setup.exe || true
|
||||
|
||||
- name: Restore signed installer under its release name
|
||||
run: |
|
||||
mkdir -p release
|
||||
cp signed/diylc-setup.exe "release/diylc-${DIYLC_VERSION}-win64.exe"
|
||||
|
||||
- name: Upload signed installer
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: diylc-windows-installer-signed
|
||||
path: release/diylc-${{ env.DIYLC_VERSION }}-win64.exe
|
||||
if-no-files-found: error
|
||||
@@ -35,6 +35,7 @@ Thumbs.db
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
!lib/*.jar
|
||||
*.war
|
||||
*.ear
|
||||
*.zip
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>6.8.0</version>
|
||||
<version>6.9.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-core</artifactId>
|
||||
@@ -97,10 +97,10 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc.local</groupId>
|
||||
<artifactId>gerber-writer-api-1.0.0</artifactId>
|
||||
<artifactId>gerber-writer-api-1.1.0</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.0.0.jar</systemPath>
|
||||
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.1.0.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc.local</groupId>
|
||||
|
||||
@@ -2,16 +2,26 @@ package org.diylc.netlist;
|
||||
|
||||
import org.diylc.common.ComponentType;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.measures.AbstractMeasure;
|
||||
import org.diylc.presenter.ComponentProcessor;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.Format;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.diylc.netlist.AbstractNetlistAnalyzer.find;
|
||||
|
||||
public class SpiceSumarizer {
|
||||
|
||||
// measures format with the user's locale for display, but SPICE only accepts '.' as the decimal
|
||||
// separator
|
||||
private static final Format VALUE_FORMAT =
|
||||
new DecimalFormat("0.####", DecimalFormatSymbols.getInstance(Locale.ROOT));
|
||||
|
||||
public static String summarize(Netlist netlist, boolean useHTML) throws TreeException {
|
||||
|
||||
// grab all components that are in the netlist
|
||||
@@ -119,14 +129,23 @@ public class SpiceSumarizer {
|
||||
sb.append(typeName);
|
||||
}
|
||||
} else {
|
||||
if (c.getValue().toString().contains(" ")) {
|
||||
sb.append("\"").append(c.getValue()).append("\"");
|
||||
String value = formatValue(c.getValue());
|
||||
if (value.contains(" ")) {
|
||||
sb.append("\"").append(value).append("\"");
|
||||
} else {
|
||||
sb.append(c.getValue());
|
||||
sb.append(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatValue(Object value) {
|
||||
if (value instanceof AbstractMeasure) {
|
||||
AbstractMeasure<?> measure = (AbstractMeasure<?>) value;
|
||||
return VALUE_FORMAT.format(measure.getValue()) + measure.getUnit();
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
private static String formatSpiceNode(int i) {
|
||||
return String.format("N%03d" , i);
|
||||
}
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.serialization;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
|
||||
import org.diylc.core.annotations.Indexed;
|
||||
|
||||
/**
|
||||
* Registers XStream aliases for classes and fields that were renamed after they shipped, so that
|
||||
* the old names keep resolving. Implementations live next to the classes they alias and are
|
||||
* applied to every {@link XStream} instance prepared by {@link ProjectFileManager#configure(XStream)}.
|
||||
*
|
||||
* @author Branislav Stojkovic
|
||||
*/
|
||||
@Indexed
|
||||
public interface ISerializationAliasProvider {
|
||||
|
||||
/**
|
||||
* Registers aliases on the provided {@link XStream} instance.
|
||||
*
|
||||
* @param xStream
|
||||
*/
|
||||
void registerAliases(XStream xStream);
|
||||
}
|
||||
@@ -133,6 +133,14 @@ public class ProjectFileManager {
|
||||
xStream.addImmutableType(org.diylc.core.measures.Inductance.class, true);
|
||||
xStream.addImmutableType(org.diylc.core.measures.Size.class, true);
|
||||
xStream.addPermission(AnyTypePermission.ANY);
|
||||
try {
|
||||
for (ISerializationAliasProvider provider : ReflectionUtils
|
||||
.getIndexedInstances(ISerializationAliasProvider.class)) {
|
||||
provider.registerAliases(xStream);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
LOG.error("Could not register serialization aliases", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void startNewFile() {
|
||||
|
||||
@@ -582,7 +582,7 @@
|
||||
<minor>8</minor>
|
||||
<build>0</build>
|
||||
</versionNumber>
|
||||
<releaseDate>2026-10-09 00:00:00.000 CET</releaseDate>
|
||||
<releaseDate>2026-10-16 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
@@ -593,6 +593,14 @@
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Holding 'Shift' when starting to drag components or control points keeps the whole drag strictly horizontal or vertical, in the direction of the initial gesture. Holding 'Shift' while drawing a new wire or two-point component does the same</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added Rectangular shape to LED component in addition to Round; added ability to set LED lead spacing</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Upgraded AI Models to the latest GPT-6 generation across all tiers</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>'S1 Switch' can now be rotated to match the orientation of the potentiometer it is mounted on, so the switching matrix stays correct relative to the pot lugs</description>
|
||||
@@ -648,5 +656,25 @@
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
<org.diylc.appframework.update.Version>
|
||||
<versionNumber>
|
||||
<major>6</major>
|
||||
<minor>9</minor>
|
||||
<build>0</build>
|
||||
</versionNumber>
|
||||
<releaseDate>2026-10-17 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Gerber export on computers set to a language that uses a decimal comma (e.g. German, French, Serbian) produced files in which drill holes, pads and traces had the wrong size - a 0.8mm hole came out as 0mm and traces and the board outline had no width, so the files could not be used for fabrication</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Zooming out until the drawing is smaller than the window made the toolbar above the canvas grow taller and squeeze the canvas; the toolbar now keeps its height at every zoom level</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
</changes>
|
||||
<url>https://github.com/bancika/diy-layout-creator/releases</url>
|
||||
</org.diylc.appframework.update.Version>
|
||||
</a>
|
||||
</java.util.Arrays_-ArrayList>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>6.8.0</version>
|
||||
<version>6.9.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-library</artifactId>
|
||||
@@ -73,10 +73,10 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc.local</groupId>
|
||||
<artifactId>gerber-writer-api-1.0.0</artifactId>
|
||||
<artifactId>gerber-writer-api-1.1.0</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.0.0.jar</systemPath>
|
||||
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.1.0.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc.local</groupId>
|
||||
|
||||
+19
-11
@@ -79,7 +79,9 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
|
||||
protected Color leadColor = LEAD_COLOR;
|
||||
protected Display display = Display.NAME;
|
||||
private boolean flipStanding = false;
|
||||
private LabelOriantation labelOriantation = LabelOriantation.Directional;
|
||||
@Deprecated
|
||||
private LabelOrientation labelOriantation;
|
||||
private LabelOrientation labelOrientation = LabelOrientation.Directional;
|
||||
protected boolean moveLabel = false;
|
||||
|
||||
// parameters for adjusting the label control point
|
||||
@@ -361,13 +363,13 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
|
||||
if (getMoveLabel()) {
|
||||
g2d.setTransform(oldTransform);
|
||||
g2d.translate(getPoints()[2].getX(), getPoints()[2].getY());
|
||||
if (getLabelOriantation() != LabelOriantation.Horizontal) {
|
||||
if (getLabelOrientation() != LabelOrientation.Horizontal) {
|
||||
g2d.rotate(theta);
|
||||
}
|
||||
StringUtils.drawCenteredText(g2d, label, offset, 0, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
g2d.setTransform(oldTransform);
|
||||
} else {
|
||||
if (isStanding() || getLabelOriantation() == LabelOriantation.Horizontal) {
|
||||
if (isStanding() || getLabelOrientation() == LabelOrientation.Horizontal) {
|
||||
g2d.setTransform(oldTransform);
|
||||
double x = (getPoints()[0].getX() + getPoints()[1].getX() - length) / 2.0;
|
||||
double y = (getPoints()[0].getY() + getPoints()[1].getY() - width) / 2.0;
|
||||
@@ -381,7 +383,7 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
|
||||
}
|
||||
drawingObserver.stopTracking();
|
||||
}
|
||||
// if (getLabelOriantation() == LabelOriantation.Horizontal) {
|
||||
// if (getLabelOrientation() == LabelOrientation.Horizontal) {
|
||||
//
|
||||
// drawCenteredText(g2d, label, getNewPoints()[2].getX(), getNewPoints()[2].getX(), HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
|
||||
// g2d.drawString(label, (int) (x + (length - textRect.getWidth()) / 2 + offset),
|
||||
@@ -698,14 +700,20 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Label Orientation")
|
||||
public LabelOriantation getLabelOriantation() {
|
||||
if (labelOriantation == null)
|
||||
labelOriantation = LabelOriantation.Directional;
|
||||
return labelOriantation;
|
||||
public LabelOrientation getLabelOrientation() {
|
||||
if (labelOrientation == null) {
|
||||
if (labelOriantation != null) {
|
||||
labelOrientation = labelOriantation;
|
||||
labelOriantation = null;
|
||||
} else {
|
||||
labelOrientation = LabelOrientation.Directional;
|
||||
}
|
||||
}
|
||||
return labelOrientation;
|
||||
}
|
||||
|
||||
public void setLabelOriantation(LabelOriantation labelOriantation) {
|
||||
this.labelOriantation = labelOriantation;
|
||||
public void setLabelOrientation(LabelOrientation labelOrientation) {
|
||||
this.labelOrientation = labelOrientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -785,7 +793,7 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
|
||||
this.hideShortLeads = hideShortLeads;
|
||||
}
|
||||
|
||||
public enum LabelOriantation {
|
||||
public enum LabelOrientation {
|
||||
Directional, Horizontal
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -187,9 +187,9 @@ public class CopperTrace extends AbstractLeadedComponent<Void> implements ILayer
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public LabelOriantation getLabelOriantation() {
|
||||
public LabelOrientation getLabelOrientation() {
|
||||
// TODO Auto-generated method stub
|
||||
return super.getLabelOriantation();
|
||||
return super.getLabelOrientation();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
||||
@@ -163,9 +163,9 @@ public class Jumper extends AbstractLeadedComponent<Void> implements IContinuity
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public LabelOriantation getLabelOriantation() {
|
||||
public LabelOrientation getLabelOrientation() {
|
||||
// TODO Auto-generated method stub
|
||||
return super.getLabelOriantation();
|
||||
return super.getLabelOrientation();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -291,7 +291,7 @@ public class Line extends AbstractLeadedComponent<Void> {
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public org.diylc.components.AbstractLeadedComponent.LabelOriantation getLabelOriantation() {
|
||||
return super.getLabelOriantation();
|
||||
public org.diylc.components.AbstractLeadedComponent.LabelOrientation getLabelOrientation() {
|
||||
return super.getLabelOrientation();
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -20,8 +20,10 @@ package org.diylc.components.passive;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -37,7 +39,10 @@ public class CapacitorDatasheetService {
|
||||
|
||||
private static CapacitorDatasheetService instance;
|
||||
|
||||
private static NumberFormat format = new DecimalFormat("##.###");
|
||||
// lookup keys are matched against the datasheet files, which always use '.' as the decimal
|
||||
// separator
|
||||
private static NumberFormat format =
|
||||
new DecimalFormat("##.###", DecimalFormatSymbols.getInstance(Locale.ROOT));
|
||||
|
||||
private Map<String, CapacitorDatasheet> cache = new HashMap<String, CapacitorDatasheet>();
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ public class Resistor extends AbstractLeadedComponent<Resistance> implements IGe
|
||||
|
||||
@Override
|
||||
protected int getLabelOffset(int bodyLength, int bodyWidth, int labelLength) {
|
||||
if (value == null || getColorCode() == ResistorColorCode.NONE || getLabelOriantation() != AbstractLeadedComponent.LabelOriantation.Directional)
|
||||
if (value == null || getColorCode() == ResistorColorCode.NONE || getLabelOrientation() != AbstractLeadedComponent.LabelOrientation.Directional)
|
||||
return 0;
|
||||
Color[] bands = value.getColorCode(colorCode);
|
||||
|
||||
|
||||
+17
-9
@@ -37,7 +37,7 @@ import org.diylc.awt.StringUtils;
|
||||
import org.diylc.common.*;
|
||||
import org.diylc.components.AbstractLabeledComponent;
|
||||
import org.diylc.components.RoundedPolygon;
|
||||
import org.diylc.components.AbstractLeadedComponent.LabelOriantation;
|
||||
import org.diylc.components.AbstractLeadedComponent.LabelOrientation;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
@@ -107,7 +107,9 @@ public class BridgeRectifier extends AbstractLabeledComponent<String> implements
|
||||
private Voltage voltage;
|
||||
private Current current;
|
||||
transient private Area[] body;
|
||||
private LabelOriantation labelOriantation = LabelOriantation.Directional;
|
||||
@Deprecated
|
||||
private LabelOrientation labelOriantation;
|
||||
private LabelOrientation labelOrientation = LabelOrientation.Directional;
|
||||
|
||||
public BridgeRectifier() {
|
||||
super();
|
||||
@@ -457,7 +459,7 @@ public class BridgeRectifier extends AbstractLabeledComponent<String> implements
|
||||
|
||||
AffineTransform oldTransform = g2d.getTransform();
|
||||
|
||||
if (getLabelOriantation() == LabelOriantation.Directional
|
||||
if (getLabelOrientation() == LabelOrientation.Directional
|
||||
&& (getOrientation() == Orientation.DEFAULT || getOrientation() == Orientation._180)) {
|
||||
double centerX = bounds.getX() + bounds.width / 2;
|
||||
double centerY = bounds.getY() + bounds.height / 2;
|
||||
@@ -671,14 +673,20 @@ public class BridgeRectifier extends AbstractLabeledComponent<String> implements
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Label Orientation")
|
||||
public LabelOriantation getLabelOriantation() {
|
||||
if (labelOriantation == null)
|
||||
labelOriantation = LabelOriantation.Directional;
|
||||
return labelOriantation;
|
||||
public LabelOrientation getLabelOrientation() {
|
||||
if (labelOrientation == null) {
|
||||
if (labelOriantation != null) {
|
||||
labelOrientation = labelOriantation;
|
||||
labelOriantation = null;
|
||||
} else {
|
||||
labelOrientation = LabelOrientation.Directional;
|
||||
}
|
||||
}
|
||||
return labelOrientation;
|
||||
}
|
||||
|
||||
public void setLabelOriantation(LabelOriantation labelOriantation) {
|
||||
this.labelOriantation = labelOriantation;
|
||||
public void setLabelOrientation(LabelOrientation labelOrientation) {
|
||||
this.labelOrientation = labelOrientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,7 @@ package org.diylc.components.semiconductors;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
@@ -35,6 +36,7 @@ import org.diylc.core.CreationMethod;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.gerber.IGerberComponentSimple;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
@@ -47,10 +49,14 @@ public class LED extends AbstractLeadedComponent<String> implements IGerberCompo
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static Size DEFAULT_SIZE = new Size(5d, SizeUnit.mm);
|
||||
public static Size DEFAULT_WIDTH = new Size(2d, SizeUnit.mm);
|
||||
public static Size PIN_SPACING = new Size(2.54d, SizeUnit.mm);
|
||||
public static Color BODY_COLOR = Color.decode("#5DFC0A");
|
||||
public static Color BORDER_COLOR = BODY_COLOR.darker();
|
||||
|
||||
private String value = "";
|
||||
private BodyShape shape = BodyShape.ROUND;
|
||||
private Size pinSpacing = PIN_SPACING;
|
||||
|
||||
public LED() {
|
||||
super();
|
||||
@@ -67,6 +73,35 @@ public class LED extends AbstractLeadedComponent<String> implements IGerberCompo
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public BodyShape getShape() {
|
||||
if (shape == null) {
|
||||
shape = BodyShape.ROUND;
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
public void setShape(BodyShape shape) {
|
||||
this.shape = shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int calculatePinSpacing(Rectangle shapeRect) {
|
||||
return (int) getPinSpacing().convertToPixels();
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Lead Spacing")
|
||||
public Size getPinSpacing() {
|
||||
if (pinSpacing == null) {
|
||||
pinSpacing = PIN_SPACING;
|
||||
}
|
||||
return pinSpacing;
|
||||
}
|
||||
|
||||
public void setPinSpacing(Size pinSpacing) {
|
||||
this.pinSpacing = pinSpacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
switch (index) {
|
||||
@@ -97,7 +132,7 @@ public class LED extends AbstractLeadedComponent<String> implements IGerberCompo
|
||||
|
||||
@Override
|
||||
protected Size getDefaultWidth() {
|
||||
return DEFAULT_SIZE;
|
||||
return DEFAULT_WIDTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -107,6 +142,10 @@ public class LED extends AbstractLeadedComponent<String> implements IGerberCompo
|
||||
|
||||
@Override
|
||||
protected Shape getBodyShape() {
|
||||
if (getShape() == BodyShape.RECTANGLE) {
|
||||
return new Rectangle2D.Double(0, 0, getClosestOdd(getLength().convertToPixels()),
|
||||
getClosestOdd(getWidth().convertToPixels()));
|
||||
}
|
||||
int size = getClosestOdd((int) (getLength().convertToPixels() * 1.2));
|
||||
Area area = new Area(new Ellipse2D.Double(0, 0, size, size));
|
||||
area.intersect(new Area(new Rectangle2D.Double(0, 0, getLength().convertToPixels() * 1.15, size)));
|
||||
@@ -115,7 +154,7 @@ public class LED extends AbstractLeadedComponent<String> implements IGerberCompo
|
||||
|
||||
@Override
|
||||
protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) {
|
||||
if (!outlineMode) {
|
||||
if (!outlineMode && getShape() == BodyShape.ROUND) {
|
||||
int size = getClosestOdd((int) (getLength().convertToPixels() * 1.2));
|
||||
int innerSize = getClosestOdd(getLength().convertToPixels());
|
||||
int x = (size - innerSize) / 2;
|
||||
@@ -125,14 +164,47 @@ public class LED extends AbstractLeadedComponent<String> implements IGerberCompo
|
||||
}
|
||||
}
|
||||
|
||||
// the border always follows the body color; the inherited borderColor field stays only so
|
||||
// that older files and older builds keep reading it
|
||||
@Override
|
||||
public Color getBorderColor() {
|
||||
Color bodyColor = getBodyColor();
|
||||
return bodyColor == null ? null : bodyColor.darker();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void setBorderColor(Color borderColor) {
|
||||
super.setBorderColor(borderColor);
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Size")
|
||||
@Override
|
||||
public Size getLength() {
|
||||
return super.getLength();
|
||||
}
|
||||
|
||||
// only rectangular LEDs use the width; a round body is sized by its diameter alone
|
||||
@EditableProperty(name = "Width", validatorClass = PositiveNonZeroMeasureValidator.class,
|
||||
sortOrder = 102)
|
||||
@Override
|
||||
public Size getWidth() {
|
||||
return super.getWidth();
|
||||
}
|
||||
|
||||
public enum BodyShape {
|
||||
|
||||
ROUND("Round"), RECTANGLE("Rectangle");
|
||||
|
||||
private String label;
|
||||
|
||||
private BodyShape(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,8 +344,8 @@ public class TapeMeasure extends AbstractLeadedComponent<String> {
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public org.diylc.components.AbstractLeadedComponent.LabelOriantation getLabelOriantation() {
|
||||
return org.diylc.components.AbstractLeadedComponent.LabelOriantation.Directional;
|
||||
public org.diylc.components.AbstractLeadedComponent.LabelOrientation getLabelOrientation() {
|
||||
return org.diylc.components.AbstractLeadedComponent.LabelOrientation.Directional;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.serialization;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
|
||||
import org.diylc.components.AbstractLeadedComponent;
|
||||
|
||||
public class ComponentAliasProvider implements ISerializationAliasProvider {
|
||||
|
||||
@Override
|
||||
public void registerAliases(XStream xStream) {
|
||||
// the enum shipped misspelled and its class name is saved wherever the value is held as an
|
||||
// Object (variants, defaults in config.xml); configs from before the package alias carry the
|
||||
// full name. The alias registered last is also the one written, so files stay readable by
|
||||
// older builds
|
||||
xStream.alias("org.diylc.components.AbstractLeadedComponent$LabelOriantation",
|
||||
AbstractLeadedComponent.LabelOrientation.class);
|
||||
xStream.alias("diylc.AbstractLeadedComponent$LabelOriantation",
|
||||
AbstractLeadedComponent.LabelOrientation.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.netlist;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.diylc.components.passive.Resistor;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.measures.Resistance;
|
||||
import org.diylc.core.measures.ResistanceUnit;
|
||||
|
||||
public class SpiceSumarizerTests {
|
||||
|
||||
private Locale defaultLocale;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
defaultLocale = Locale.getDefault();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Locale.setDefault(defaultLocale);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecimalValueIgnoresLocale() throws TreeException {
|
||||
Locale.setDefault(Locale.GERMANY);
|
||||
|
||||
Resistor resistor = new Resistor();
|
||||
resistor.setName("R1");
|
||||
resistor.setValue(new Resistance(4.7d, ResistanceUnit.K));
|
||||
|
||||
Netlist netlist = new Netlist(Arrays.<IDIYComponent<?>>asList(resistor));
|
||||
netlist.add(new Group(new Node(resistor, 0), new Node(resistor, 1)));
|
||||
|
||||
String spice = SpiceSumarizer.summarize(netlist, false);
|
||||
Assert.assertTrue(spice, spice.contains(" 4.7K "));
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.serialization;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import com.thoughtworks.xstream.io.xml.DomDriver;
|
||||
|
||||
import org.diylc.components.AbstractLeadedComponent.LabelOrientation;
|
||||
import org.diylc.components.passive.Resistor;
|
||||
import org.diylc.components.semiconductors.BridgeRectifier;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Files saved before {@code LabelOriantation} was renamed must keep loading. The field is migrated
|
||||
* and saved under its new name; the enum keeps its shipped class name on disk, because older builds
|
||||
* discard a whole config file that names a class they cannot resolve.
|
||||
*/
|
||||
public class ComponentAliasProviderTest {
|
||||
|
||||
private static final String OLD_ENUM_NAME = "diylc.AbstractLeadedComponent_-LabelOriantation";
|
||||
private static final String OLD_FULL_ENUM_NAME =
|
||||
"org.diylc.components.AbstractLeadedComponent_-LabelOriantation";
|
||||
|
||||
// a fresh instance has not seen any class yet, which is the state it is in while reading
|
||||
// config.xml at startup
|
||||
private static XStream createXStream() {
|
||||
XStream xStream = new XStream(new DomDriver("UTF-8"));
|
||||
ProjectFileManager.configure(xStream);
|
||||
return xStream;
|
||||
}
|
||||
|
||||
// files saved before the rename carry only the misspelled field
|
||||
private static String toOldFieldName(String xml) {
|
||||
Assert.assertTrue(xml.contains("labelOrientation"));
|
||||
return xml.replace("labelOrientation", "labelOriantation");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void leadedComponentMigratesOldFieldName() {
|
||||
Resistor resistor = new Resistor();
|
||||
resistor.setLabelOrientation(LabelOrientation.Horizontal);
|
||||
String oldXml = toOldFieldName(createXStream().toXML(resistor));
|
||||
|
||||
Resistor loaded = (Resistor) createXStream().fromXML(oldXml);
|
||||
Assert.assertEquals(LabelOrientation.Horizontal, loaded.getLabelOrientation());
|
||||
|
||||
String savedXml = createXStream().toXML(loaded);
|
||||
Assert.assertTrue(savedXml.contains("<labelOrientation>Horizontal</labelOrientation>"));
|
||||
Assert.assertFalse(savedXml.contains("labelOriantation"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bridgeRectifierMigratesOldFieldName() {
|
||||
BridgeRectifier rectifier = new BridgeRectifier();
|
||||
rectifier.setLabelOrientation(LabelOrientation.Horizontal);
|
||||
String oldXml = toOldFieldName(createXStream().toXML(rectifier));
|
||||
|
||||
BridgeRectifier loaded = (BridgeRectifier) createXStream().fromXML(oldXml);
|
||||
Assert.assertEquals(LabelOrientation.Horizontal, loaded.getLabelOrientation());
|
||||
|
||||
String savedXml = createXStream().toXML(loaded);
|
||||
Assert.assertTrue(savedXml.contains("<labelOrientation>Horizontal</labelOrientation>"));
|
||||
Assert.assertFalse(savedXml.contains("labelOriantation"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enumValueHeldAsObjectReadsOldClassName() {
|
||||
String xml = "<map><entry><string>Label Orientation</string><" + OLD_ENUM_NAME
|
||||
+ ">Horizontal</" + OLD_ENUM_NAME + "></entry></map>";
|
||||
|
||||
Map<?, ?> loaded = (Map<?, ?>) createXStream().fromXML(xml);
|
||||
Assert.assertEquals(LabelOrientation.Horizontal, loaded.get("Label Orientation"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enumValueHeldAsObjectReadsOldFullClassName() {
|
||||
String xml = "<map><entry><string>Label Orientation</string><" + OLD_FULL_ENUM_NAME
|
||||
+ ">Horizontal</" + OLD_FULL_ENUM_NAME + "></entry></map>";
|
||||
|
||||
Map<?, ?> loaded = (Map<?, ?>) createXStream().fromXML(xml);
|
||||
Assert.assertEquals(LabelOrientation.Horizontal, loaded.get("Label Orientation"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enumValueHeldAsObjectWritesOldClassName() {
|
||||
Map<String, Object> values = new HashMap<String, Object>();
|
||||
values.put("Label Orientation", LabelOrientation.Horizontal);
|
||||
|
||||
String xml = createXStream().toXML(values);
|
||||
Assert.assertTrue(xml.contains("<" + OLD_ENUM_NAME + ">Horizontal</" + OLD_ENUM_NAME + ">"));
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>6.8.0</version>
|
||||
<version>6.9.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-processor</artifactId>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Exits 0 if the given PE file carries an Authenticode signature, 1 if it does not.
|
||||
|
||||
`osslsigncode verify` also fails on an untrusted chain, which is the normal result for the
|
||||
SignPath test certificate, so it cannot answer this question on its own. This reads the PE
|
||||
Certificate Table data directory instead, which says whether a signature is present without
|
||||
making any claim about its validity.
|
||||
"""
|
||||
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def has_signature(path):
|
||||
with open(path, "rb") as f:
|
||||
data = f.read()
|
||||
|
||||
pe = struct.unpack_from("<I", data, 0x3C)[0]
|
||||
if data[pe:pe + 4] != b"PE\0\0":
|
||||
raise ValueError("not a PE file: %s" % path)
|
||||
|
||||
optional_header = pe + 24
|
||||
magic = struct.unpack_from("<H", data, optional_header)[0]
|
||||
if magic == 0x10B:
|
||||
directories = optional_header + 96
|
||||
elif magic == 0x20B:
|
||||
directories = optional_header + 112
|
||||
else:
|
||||
raise ValueError("unknown optional header magic 0x%x in %s" % (magic, path))
|
||||
|
||||
# data directory entry 4 is the Certificate Table
|
||||
_, size = struct.unpack_from("<II", data, directories + 4 * 8)
|
||||
return size > 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
signed = has_signature(sys.argv[1])
|
||||
print("signed" if signed else "unsigned")
|
||||
sys.exit(0 if signed else 1)
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>6.8.0</version>
|
||||
<version>6.9.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>diylc-swing</artifactId>
|
||||
@@ -145,10 +145,10 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc.local</groupId>
|
||||
<artifactId>gerber-writer-api-1.0.0</artifactId>
|
||||
<artifactId>gerber-writer-api-1.1.0</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.0.0.jar</systemPath>
|
||||
<systemPath>${project.basedir}/../lib/gerber-writer-api-1.1.0.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.diylc.local</groupId>
|
||||
|
||||
@@ -93,7 +93,17 @@ public class ActionBarPlugin implements IPlugIn {
|
||||
|
||||
public JPanel getActionPanel() {
|
||||
if (actionPanel == null) {
|
||||
actionPanel = new JPanel();
|
||||
actionPanel = new JPanel() {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// shares a vertical BoxLayout with the canvas on Mac; without a height cap it absorbs
|
||||
// half of the spare space whenever the zoomed-out canvas is smaller than the viewport
|
||||
@Override
|
||||
public Dimension getMaximumSize() {
|
||||
return new Dimension(Integer.MAX_VALUE, getPreferredSize().height);
|
||||
}
|
||||
};
|
||||
actionPanel.setOpaque(false);
|
||||
actionPanel.setLayout(new GridBagLayout());
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.diylc</groupId>
|
||||
<artifactId>diylc-parent</artifactId>
|
||||
<version>6.8.0</version>
|
||||
<version>6.9.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>DIY Layout Creator</name>
|
||||
|
||||
Reference in New Issue
Block a user