Compare commits
11 Commits
5cf7e1f1e5
...
6b1a5f0ab6
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b1a5f0ab6 | |||
| 13009aa15e | |||
| 136a571aea | |||
| 8b1c2b5b1b | |||
| f68bddac93 | |||
| de4847b834 | |||
| cbfb9190c5 | |||
| 9b1fbd9fad | |||
| 51bf3b00dd | |||
| a32bbfa5d9 | |||
| 84f0196c97 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -242,3 +242,6 @@ ModelManifest.xml
|
||||
.fake/
|
||||
|
||||
.pfx
|
||||
|
||||
# Test documents
|
||||
TestDocs/
|
||||
|
||||
70
AGENTS.md
70
AGENTS.md
@@ -1,70 +0,0 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
- Root solution: `ExportDXF.sln`.
|
||||
- WinForms app: `ExportDXF/ExportDXF/` (.NET Framework 4.8; SolidWorks automation). Key folders: `Forms/`, `Services/`, `Models/`, `Utilities/`, `Templates/`, `Resources/`, `ItemExtractors/`, `ViewFlipDeciders/`, `Extensions/`, `Properties/`.
|
||||
- Companion utilities: `EtchBendLines/` (standalone solution for DXF processing; includes vendored `netDxf`).
|
||||
- Sample docs: `TestDocs/` contains drawings/fixtures useful for local validation.
|
||||
- Tests: none yet; add new test projects under `tests/` (e.g., `tests/ExportDXF.Tests/`).
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
- Restore: `msbuild ExportDXF.sln /t:Restore` (or `nuget restore ExportDXF.sln`).
|
||||
- Build (Release): `msbuild ExportDXF.sln /p:Configuration=Release`.
|
||||
- Build single project: `msbuild ExportDXF/ExportDXF/ExportDXF.csproj /p:Configuration=Release`.
|
||||
- Run app: `ExportDXF/ExportDXF/bin/Release/ExportDXF.exe` (or `bin/Debug/ExportDXF.exe` after a Debug build).
|
||||
- Prereqs: Visual Studio 2019/2022 or Build Tools with .NET Framework 4.8 targeting pack; SolidWorks installed for automation features (app starts without SW but SW-dependent actions require it).
|
||||
- Format: `dotnet format` from repo root if .NET SDK is installed; otherwise use VS “Format Document”.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
- C#: 4-space indent, braces on new lines, nullable where supported.
|
||||
- Naming: PascalCase for types/methods; camelCase for locals/fields; `Async` suffix for async methods.
|
||||
- Structure: Keep UI in `Forms/` thin; delegate work to `Services/` and `Utilities/`. One class per file; filename matches type (e.g., `DxfExportService.cs`).
|
||||
- Interop: Isolate SolidWorks COM/interop behind interfaces for testability; prefer dependency injection where practical.
|
||||
|
||||
## Testing Guidelines
|
||||
- Framework: xUnit recommended. Name files `*Tests.cs` and methods `MethodName_Should_DoThing`.
|
||||
- Location: `tests/ExportDXF.Tests/` with reference to the app or extracted class libraries.
|
||||
- Scope: Favor service- and utility-level tests; avoid UI surface. Mock/abstract SolidWorks interop.
|
||||
- Run: `dotnet test` (add when tests exist).
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
- Messages: imperative, present tense with optional scope (e.g., `ExportDXF: improve DXF export options`). Provide rationale in body and any breaking changes.
|
||||
- PRs include: clear description, linked issues (`Closes #123`), screenshots/GIFs for UI, migration notes, and local run steps.
|
||||
|
||||
## Security & Configuration Tips
|
||||
- Do not commit secrets or license keys.
|
||||
- App configuration resides in `app.config`; user/machine-specific settings should stay in user config and not be committed.
|
||||
- Keep SolidWorks version/paths configurable where possible.
|
||||
|
||||
## Agent Tools: Roslyn Bridge (C# Analysis)
|
||||
- Purpose: Use for C# code analysis, symbol queries, diagnostics, and semantic navigation via a local WebAPI bridge to Roslyn.
|
||||
- Golden rules:
|
||||
- Always use this tool first for any C#/Roslyn analysis; do not guess.
|
||||
- Always check service health/instances before querying.
|
||||
- Default to `solutionName=ExportDXF` for this repo. If you intentionally open and analyze `EtchBendLines.sln`, use `solutionName=EtchBendLines`.
|
||||
- Service assumptions:
|
||||
- WebAPI listens on `http://localhost:5001` when installed and running.
|
||||
- Visual Studio must have the target solution open for the instance to appear.
|
||||
- Quick workflow (ExportDXF):
|
||||
- List VS instances: `curl http://localhost:5001/api/instances`
|
||||
- Health check: `curl http://localhost:5001/api/health`
|
||||
- Diagnostics summary: `curl "http://localhost:5001/api/roslyn/diagnostics/summary?solutionName=ExportDXF"`
|
||||
- Errors only: `curl "http://localhost:5001/api/roslyn/diagnostics?solutionName=ExportDXF&severity=error"`
|
||||
- Warnings only: `curl "http://localhost:5001/api/roslyn/diagnostics?solutionName=ExportDXF&severity=warning"`
|
||||
- All diagnostics: `curl "http://localhost:5001/api/roslyn/diagnostics?solutionName=ExportDXF"`
|
||||
- List projects: `curl "http://localhost:5001/api/roslyn/projects?solutionName=ExportDXF"`
|
||||
- Solution overview: `curl "http://localhost:5001/api/roslyn/solution/overview?solutionName=ExportDXF"`
|
||||
- Find symbol by name: `curl "http://localhost:5001/api/roslyn/symbol/search?solutionName=ExportDXF&symbolName=TypeOrMember"`
|
||||
- Symbol at file/position: `curl "http://localhost:5001/api/roslyn/symbol?solutionName=ExportDXF&filePath=C:/full/path/File.cs&line=10&column=5"`
|
||||
- Find references: `curl "http://localhost:5001/api/roslyn/references?solutionName=ExportDXF&filePath=C:/full/path/File.cs&line=10&column=5"`
|
||||
- Notes:
|
||||
- Lines are 1-based; columns are 0-based. Use absolute file paths.
|
||||
- Get canonical file paths from the `projects` endpoint responses.
|
||||
- Prefer this tool over manual grepping for symbols/references/diagnostics.
|
||||
- Troubleshooting:
|
||||
- No instances listed: ensure Visual Studio is running with the solution open; wait up to 60s for discovery.
|
||||
- Service not reachable: verify the Roslyn Bridge WebAPI service is installed and running on port 5001.
|
||||
|
||||
- Helper script:
|
||||
- `scripts/rb.ps1` provides short commands with defaults for this repo (defaults to `-SolutionName ExportDXF`).
|
||||
- Examples: `./scripts/rb.ps1 summary`, `./scripts/rb.ps1 projects`, `./scripts/rb.ps1 symbol -SymbolName Program`.
|
||||
@@ -103,6 +103,12 @@
|
||||
<Compile Include="Extensions\TimeSpanExtensions.cs" />
|
||||
<Compile Include="Extensions\UIExtensions.cs" />
|
||||
<Compile Include="Extensions\UnitConversionExtensions.cs" />
|
||||
<Compile Include="Forms\DrawingSelectionForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Forms\DrawingSelectionForm.Designer.cs">
|
||||
<DependentUpon>DrawingSelectionForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Forms\MainForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -116,11 +122,11 @@
|
||||
<Compile Include="Forms\ViewFlipDeciderComboboxItem.cs" />
|
||||
<Compile Include="Models\DocumentType.cs" />
|
||||
<Compile Include="Models\ExportContext.cs" />
|
||||
<Compile Include="Models\BomItem.cs" />
|
||||
<Compile Include="Models\Item.cs" />
|
||||
<Compile Include="Models\LogEvent.cs" />
|
||||
<Compile Include="Models\SolidWorksDocument.cs" />
|
||||
<Compile Include="Services\BomExcelExporter.cs" />
|
||||
<Compile Include="Services\BomExtractor.cs" />
|
||||
<Compile Include="Services\BomExcelSettings.cs" />
|
||||
<Compile Include="Services\DrawingExporter.cs" />
|
||||
<Compile Include="Services\DxfExportService.cs" />
|
||||
<Compile Include="Services\CutFabApiClient.cs" />
|
||||
@@ -137,6 +143,9 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ViewFlipDeciders\PreferUpViewFlipDecider.cs" />
|
||||
<Compile Include="ViewFlipDeciders\ViewFlipDeciderFactory.cs" />
|
||||
<EmbeddedResource Include="Forms\DrawingSelectionForm.resx">
|
||||
<DependentUpon>DrawingSelectionForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Forms\MainForm.resx">
|
||||
<DependentUpon>MainForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
@@ -163,9 +172,6 @@
|
||||
<Content Include="Templates\Blank.drwdot">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Templates\BomTemplate.xlsx">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\edit_alt.png" />
|
||||
@@ -193,18 +199,31 @@
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EPPlus">
|
||||
<Version>4.5.3.1</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EtchBendLines\EtchBendLines\EtchBendLines.csproj">
|
||||
<Project>{229c2fb9-6ad6-4a5d-b83a-d1146573d6f9}</Project>
|
||||
<Name>EtchBendLines</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<COMReference Include="AcroPDFLib">
|
||||
<Guid>{05BFD3F1-6319-4F30-B752-C7A22889BCC4}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="AxAcroPDFLib">
|
||||
<Guid>{05BFD3F1-6319-4F30-B752-C7A22889BCC4}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>aximp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
283
ExportDXF/Forms/DrawingSelectionForm.Designer.cs
generated
Normal file
283
ExportDXF/Forms/DrawingSelectionForm.Designer.cs
generated
Normal file
@@ -0,0 +1,283 @@
|
||||
namespace ExportDXF.Forms
|
||||
{
|
||||
partial class DrawingSelectionForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.equipmentLabel = new System.Windows.Forms.Label();
|
||||
this.equipmentComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.drawingLabel = new System.Windows.Forms.Label();
|
||||
this.drawingComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.newDrawingButton = new System.Windows.Forms.Button();
|
||||
this.newDrawingPanel = new System.Windows.Forms.Panel();
|
||||
this.qtyNumericUpDown = new System.Windows.Forms.NumericUpDown();
|
||||
this.qtyLabel = new System.Windows.Forms.Label();
|
||||
this.descriptionTextBox = new System.Windows.Forms.TextBox();
|
||||
this.descriptionLabel = new System.Windows.Forms.Label();
|
||||
this.drawingNumberTextBox = new System.Windows.Forms.TextBox();
|
||||
this.drawingNumberLabel = new System.Windows.Forms.Label();
|
||||
this.currentDrawingLabel = new System.Windows.Forms.Label();
|
||||
this.okButton = new System.Windows.Forms.Button();
|
||||
this.cancelButton = new System.Windows.Forms.Button();
|
||||
this.statusLabel = new System.Windows.Forms.Label();
|
||||
this.newDrawingPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.qtyNumericUpDown)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// equipmentLabel
|
||||
//
|
||||
this.equipmentLabel.AutoSize = true;
|
||||
this.equipmentLabel.Location = new System.Drawing.Point(12, 15);
|
||||
this.equipmentLabel.Name = "equipmentLabel";
|
||||
this.equipmentLabel.Size = new System.Drawing.Size(82, 17);
|
||||
this.equipmentLabel.TabIndex = 0;
|
||||
this.equipmentLabel.Text = "Equipment #";
|
||||
//
|
||||
// equipmentComboBox
|
||||
//
|
||||
this.equipmentComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.equipmentComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.equipmentComboBox.FormattingEnabled = true;
|
||||
this.equipmentComboBox.Location = new System.Drawing.Point(100, 12);
|
||||
this.equipmentComboBox.Name = "equipmentComboBox";
|
||||
this.equipmentComboBox.Size = new System.Drawing.Size(470, 25);
|
||||
this.equipmentComboBox.TabIndex = 1;
|
||||
this.equipmentComboBox.SelectedIndexChanged += new System.EventHandler(this.equipmentComboBox_SelectedIndexChanged);
|
||||
//
|
||||
// drawingLabel
|
||||
//
|
||||
this.drawingLabel.AutoSize = true;
|
||||
this.drawingLabel.Location = new System.Drawing.Point(12, 48);
|
||||
this.drawingLabel.Name = "drawingLabel";
|
||||
this.drawingLabel.Size = new System.Drawing.Size(68, 17);
|
||||
this.drawingLabel.TabIndex = 2;
|
||||
this.drawingLabel.Text = "Drawing #";
|
||||
//
|
||||
// drawingComboBox
|
||||
//
|
||||
this.drawingComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.drawingComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.drawingComboBox.FormattingEnabled = true;
|
||||
this.drawingComboBox.Location = new System.Drawing.Point(100, 45);
|
||||
this.drawingComboBox.Name = "drawingComboBox";
|
||||
this.drawingComboBox.Size = new System.Drawing.Size(370, 25);
|
||||
this.drawingComboBox.TabIndex = 3;
|
||||
//
|
||||
// newDrawingButton
|
||||
//
|
||||
this.newDrawingButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.newDrawingButton.Location = new System.Drawing.Point(476, 43);
|
||||
this.newDrawingButton.Name = "newDrawingButton";
|
||||
this.newDrawingButton.Size = new System.Drawing.Size(94, 27);
|
||||
this.newDrawingButton.TabIndex = 4;
|
||||
this.newDrawingButton.Text = "New Drawing";
|
||||
this.newDrawingButton.UseVisualStyleBackColor = true;
|
||||
this.newDrawingButton.Click += new System.EventHandler(this.newDrawingButton_Click);
|
||||
//
|
||||
// newDrawingPanel
|
||||
//
|
||||
this.newDrawingPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.newDrawingPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.newDrawingPanel.Controls.Add(this.qtyNumericUpDown);
|
||||
this.newDrawingPanel.Controls.Add(this.qtyLabel);
|
||||
this.newDrawingPanel.Controls.Add(this.descriptionTextBox);
|
||||
this.newDrawingPanel.Controls.Add(this.descriptionLabel);
|
||||
this.newDrawingPanel.Controls.Add(this.drawingNumberTextBox);
|
||||
this.newDrawingPanel.Controls.Add(this.drawingNumberLabel);
|
||||
this.newDrawingPanel.Location = new System.Drawing.Point(15, 85);
|
||||
this.newDrawingPanel.Name = "newDrawingPanel";
|
||||
this.newDrawingPanel.Size = new System.Drawing.Size(555, 120);
|
||||
this.newDrawingPanel.TabIndex = 5;
|
||||
this.newDrawingPanel.Visible = false;
|
||||
//
|
||||
// qtyNumericUpDown
|
||||
//
|
||||
this.qtyNumericUpDown.Location = new System.Drawing.Point(124, 72);
|
||||
this.qtyNumericUpDown.Maximum = new decimal(new int[] {
|
||||
10000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.qtyNumericUpDown.Minimum = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.qtyNumericUpDown.Name = "qtyNumericUpDown";
|
||||
this.qtyNumericUpDown.Size = new System.Drawing.Size(100, 25);
|
||||
this.qtyNumericUpDown.TabIndex = 5;
|
||||
this.qtyNumericUpDown.Value = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
//
|
||||
// qtyLabel
|
||||
//
|
||||
this.qtyLabel.AutoSize = true;
|
||||
this.qtyLabel.Location = new System.Drawing.Point(10, 74);
|
||||
this.qtyLabel.Name = "qtyLabel";
|
||||
this.qtyLabel.Size = new System.Drawing.Size(56, 17);
|
||||
this.qtyLabel.TabIndex = 4;
|
||||
this.qtyLabel.Text = "Quantity";
|
||||
//
|
||||
// descriptionTextBox
|
||||
//
|
||||
this.descriptionTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.descriptionTextBox.Location = new System.Drawing.Point(124, 41);
|
||||
this.descriptionTextBox.Name = "descriptionTextBox";
|
||||
this.descriptionTextBox.Size = new System.Drawing.Size(411, 25);
|
||||
this.descriptionTextBox.TabIndex = 3;
|
||||
//
|
||||
// descriptionLabel
|
||||
//
|
||||
this.descriptionLabel.AutoSize = true;
|
||||
this.descriptionLabel.Location = new System.Drawing.Point(10, 44);
|
||||
this.descriptionLabel.Name = "descriptionLabel";
|
||||
this.descriptionLabel.Size = new System.Drawing.Size(74, 17);
|
||||
this.descriptionLabel.TabIndex = 2;
|
||||
this.descriptionLabel.Text = "Description";
|
||||
//
|
||||
// drawingNumberTextBox
|
||||
//
|
||||
this.drawingNumberTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.drawingNumberTextBox.Location = new System.Drawing.Point(124, 10);
|
||||
this.drawingNumberTextBox.Name = "drawingNumberTextBox";
|
||||
this.drawingNumberTextBox.Size = new System.Drawing.Size(411, 25);
|
||||
this.drawingNumberTextBox.TabIndex = 1;
|
||||
this.drawingNumberTextBox.TextChanged += new System.EventHandler(this.drawingNumberTextBox_TextChanged);
|
||||
//
|
||||
// drawingNumberLabel
|
||||
//
|
||||
this.drawingNumberLabel.AutoSize = true;
|
||||
this.drawingNumberLabel.Location = new System.Drawing.Point(10, 13);
|
||||
this.drawingNumberLabel.Name = "drawingNumberLabel";
|
||||
this.drawingNumberLabel.Size = new System.Drawing.Size(108, 17);
|
||||
this.drawingNumberLabel.TabIndex = 0;
|
||||
this.drawingNumberLabel.Text = "Drawing Number";
|
||||
//
|
||||
// currentDrawingLabel
|
||||
//
|
||||
this.currentDrawingLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.currentDrawingLabel.AutoEllipsis = true;
|
||||
this.currentDrawingLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.currentDrawingLabel.Location = new System.Drawing.Point(15, 217);
|
||||
this.currentDrawingLabel.Name = "currentDrawingLabel";
|
||||
this.currentDrawingLabel.Size = new System.Drawing.Size(557, 41);
|
||||
this.currentDrawingLabel.TabIndex = 9;
|
||||
this.currentDrawingLabel.Text = "Loading active drawing...";
|
||||
//
|
||||
// okButton
|
||||
//
|
||||
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.okButton.Enabled = false;
|
||||
this.okButton.Location = new System.Drawing.Point(414, 273);
|
||||
this.okButton.Name = "okButton";
|
||||
this.okButton.Size = new System.Drawing.Size(75, 30);
|
||||
this.okButton.TabIndex = 6;
|
||||
this.okButton.Text = "OK";
|
||||
this.okButton.UseVisualStyleBackColor = true;
|
||||
this.okButton.Click += new System.EventHandler(this.okButton_Click);
|
||||
//
|
||||
// cancelButton
|
||||
//
|
||||
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.cancelButton.Location = new System.Drawing.Point(495, 273);
|
||||
this.cancelButton.Name = "cancelButton";
|
||||
this.cancelButton.Size = new System.Drawing.Size(75, 30);
|
||||
this.cancelButton.TabIndex = 7;
|
||||
this.cancelButton.Text = "Cancel";
|
||||
this.cancelButton.UseVisualStyleBackColor = true;
|
||||
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
|
||||
//
|
||||
// statusLabel
|
||||
//
|
||||
this.statusLabel.AutoSize = true;
|
||||
this.statusLabel.Location = new System.Drawing.Point(15, 280);
|
||||
this.statusLabel.Name = "statusLabel";
|
||||
this.statusLabel.Size = new System.Drawing.Size(44, 17);
|
||||
this.statusLabel.TabIndex = 8;
|
||||
this.statusLabel.Text = "Ready";
|
||||
//
|
||||
// DrawingSelectionForm
|
||||
//
|
||||
this.AcceptButton = this.okButton;
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
|
||||
this.CancelButton = this.cancelButton;
|
||||
this.ClientSize = new System.Drawing.Size(584, 315);
|
||||
this.Controls.Add(this.currentDrawingLabel);
|
||||
this.Controls.Add(this.statusLabel);
|
||||
this.Controls.Add(this.cancelButton);
|
||||
this.Controls.Add(this.okButton);
|
||||
this.Controls.Add(this.newDrawingPanel);
|
||||
this.Controls.Add(this.newDrawingButton);
|
||||
this.Controls.Add(this.drawingComboBox);
|
||||
this.Controls.Add(this.drawingLabel);
|
||||
this.Controls.Add(this.equipmentComboBox);
|
||||
this.Controls.Add(this.equipmentLabel);
|
||||
this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "DrawingSelectionForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Select Drawing - ExportDXF";
|
||||
this.newDrawingPanel.ResumeLayout(false);
|
||||
this.newDrawingPanel.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.qtyNumericUpDown)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label equipmentLabel;
|
||||
private System.Windows.Forms.ComboBox equipmentComboBox;
|
||||
private System.Windows.Forms.Label drawingLabel;
|
||||
private System.Windows.Forms.ComboBox drawingComboBox;
|
||||
private System.Windows.Forms.Button newDrawingButton;
|
||||
private System.Windows.Forms.Panel newDrawingPanel;
|
||||
private System.Windows.Forms.TextBox drawingNumberTextBox;
|
||||
private System.Windows.Forms.Label drawingNumberLabel;
|
||||
private System.Windows.Forms.TextBox descriptionTextBox;
|
||||
private System.Windows.Forms.Label descriptionLabel;
|
||||
private System.Windows.Forms.NumericUpDown qtyNumericUpDown;
|
||||
private System.Windows.Forms.Label qtyLabel;
|
||||
private System.Windows.Forms.Label currentDrawingLabel;
|
||||
private System.Windows.Forms.Button okButton;
|
||||
private System.Windows.Forms.Button cancelButton;
|
||||
private System.Windows.Forms.Label statusLabel;
|
||||
}
|
||||
}
|
||||
260
ExportDXF/Forms/DrawingSelectionForm.cs
Normal file
260
ExportDXF/Forms/DrawingSelectionForm.cs
Normal file
@@ -0,0 +1,260 @@
|
||||
using ExportDXF.Services;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace ExportDXF.Forms
|
||||
{
|
||||
public partial class DrawingSelectionForm : Form
|
||||
{
|
||||
private readonly ICutFabApiClient _apiClient;
|
||||
private readonly ISolidWorksService _solidWorksService;
|
||||
|
||||
public int? SelectedDrawingId { get; private set; }
|
||||
public string SelectedDrawingNumber { get; private set; }
|
||||
|
||||
public DrawingSelectionForm(ICutFabApiClient apiClient, ISolidWorksService solidWorksService)
|
||||
{
|
||||
_apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
|
||||
_solidWorksService = solidWorksService ?? throw new ArgumentNullException(nameof(solidWorksService));
|
||||
_solidWorksService.ActiveDocumentChanged += (s, e) => DisplayActiveDrawing();
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override async void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
DisplayActiveDrawing();
|
||||
await LoadEquipmentAsync();
|
||||
}
|
||||
|
||||
private void DisplayActiveDrawing()
|
||||
{
|
||||
try
|
||||
{
|
||||
var activeDoc = _solidWorksService.GetActiveDocument();
|
||||
if (activeDoc != null && activeDoc.DocumentType == Models.DocumentType.Drawing)
|
||||
{
|
||||
currentDrawingLabel.Text = $"Active Drawing: {activeDoc.Title}";
|
||||
currentDrawingLabel.ForeColor = Color.Green;
|
||||
}
|
||||
else if (activeDoc != null)
|
||||
{
|
||||
currentDrawingLabel.Text = $"Active Document: {activeDoc.Title} (Not a Drawing)";
|
||||
currentDrawingLabel.ForeColor = Color.Orange;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentDrawingLabel.Text = "No active SolidWorks document";
|
||||
currentDrawingLabel.ForeColor = Color.Gray;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
currentDrawingLabel.Text = $"Error getting active document: {ex.Message}";
|
||||
currentDrawingLabel.ForeColor = Color.Red;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadEquipmentAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
statusLabel.Text = "Loading equipment...";
|
||||
statusLabel.ForeColor = Color.Black;
|
||||
|
||||
var equipment = await _apiClient.GetEquipmentAsync();
|
||||
|
||||
equipmentComboBox.DisplayMember = nameof(CutFabApiClient.ApiEquipment.EquipmentNumber);
|
||||
equipmentComboBox.ValueMember = nameof(CutFabApiClient.ApiEquipment.ID);
|
||||
equipmentComboBox.DataSource = equipment;
|
||||
|
||||
if (equipment.Count > 0)
|
||||
{
|
||||
equipmentComboBox.SelectedIndex = 0;
|
||||
statusLabel.Text = $"Loaded {equipment.Count} equipment record(s)";
|
||||
statusLabel.ForeColor = Color.Green;
|
||||
}
|
||||
else
|
||||
{
|
||||
statusLabel.Text = "No equipment found";
|
||||
statusLabel.ForeColor = Color.Red;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusLabel.Text = $"Error loading equipment: {ex.Message}";
|
||||
statusLabel.ForeColor = Color.Red;
|
||||
MessageBox.Show($"Failed to load equipment: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void equipmentComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
await LoadDrawingsAsync();
|
||||
}
|
||||
|
||||
private async Task LoadDrawingsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var selectedEquipment = equipmentComboBox.SelectedItem as CutFabApiClient.ApiEquipment;
|
||||
if (selectedEquipment == null)
|
||||
{
|
||||
drawingComboBox.DataSource = null;
|
||||
return;
|
||||
}
|
||||
|
||||
statusLabel.Text = "Loading drawings...";
|
||||
statusLabel.ForeColor = Color.Black;
|
||||
|
||||
var drawings = await _apiClient.GetDrawingsForEquipmentAsync(selectedEquipment.ID);
|
||||
|
||||
drawingComboBox.DisplayMember = nameof(CutFabApiClient.ApiDrawingSummary.DrawingNumber);
|
||||
drawingComboBox.ValueMember = nameof(CutFabApiClient.ApiDrawingSummary.ID);
|
||||
drawingComboBox.DataSource = drawings;
|
||||
|
||||
if (drawings.Count > 0)
|
||||
{
|
||||
statusLabel.Text = $"Loaded {drawings.Count} drawing(s)";
|
||||
statusLabel.ForeColor = Color.Green;
|
||||
drawingComboBox.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
statusLabel.Text = "No drawings found for this equipment";
|
||||
statusLabel.ForeColor = Color.DarkBlue;
|
||||
drawingComboBox.Enabled = false;
|
||||
}
|
||||
|
||||
UpdateOkButtonState();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusLabel.Text = $"Error loading drawings: {ex.Message}";
|
||||
statusLabel.ForeColor = Color.Red;
|
||||
}
|
||||
}
|
||||
|
||||
private void newDrawingButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
ToggleNewDrawingMode(!newDrawingPanel.Visible);
|
||||
}
|
||||
|
||||
private void ToggleNewDrawingMode(bool enabled)
|
||||
{
|
||||
newDrawingPanel.Visible = enabled;
|
||||
drawingComboBox.Enabled = !enabled;
|
||||
newDrawingButton.Text = enabled ? "Cancel New" : "New Drawing";
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
drawingNumberTextBox.Focus();
|
||||
}
|
||||
|
||||
UpdateOkButtonState();
|
||||
}
|
||||
|
||||
private void drawingNumberTextBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateOkButtonState();
|
||||
}
|
||||
|
||||
private void UpdateOkButtonState()
|
||||
{
|
||||
if (newDrawingPanel.Visible)
|
||||
{
|
||||
// Creating new drawing - require drawing number
|
||||
okButton.Enabled = !string.IsNullOrWhiteSpace(drawingNumberTextBox.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Selecting existing drawing
|
||||
okButton.Enabled = drawingComboBox.SelectedItem != null;
|
||||
}
|
||||
}
|
||||
|
||||
private async void okButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
okButton.Enabled = false;
|
||||
statusLabel.Text = "Processing...";
|
||||
statusLabel.ForeColor = Color.Black;
|
||||
|
||||
if (newDrawingPanel.Visible)
|
||||
{
|
||||
// Create new drawing
|
||||
await CreateNewDrawingAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use existing drawing
|
||||
var selectedDrawing = drawingComboBox.SelectedItem as CutFabApiClient.ApiDrawingSummary;
|
||||
if (selectedDrawing != null)
|
||||
{
|
||||
SelectedDrawingId = selectedDrawing.ID;
|
||||
SelectedDrawingNumber = selectedDrawing.DrawingNumber;
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusLabel.Text = $"Error: {ex.Message}";
|
||||
statusLabel.ForeColor = Color.Red;
|
||||
MessageBox.Show($"Operation failed: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
okButton.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateNewDrawingAsync()
|
||||
{
|
||||
var selectedEquipment = equipmentComboBox.SelectedItem as CutFabApiClient.ApiEquipment;
|
||||
if (selectedEquipment == null)
|
||||
{
|
||||
MessageBox.Show("Please select equipment first.", "Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
var drawingNumber = drawingNumberTextBox.Text.Trim();
|
||||
if (string.IsNullOrWhiteSpace(drawingNumber))
|
||||
{
|
||||
MessageBox.Show("Please enter a drawing number.", "Validation Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
statusLabel.Text = "Creating new drawing...";
|
||||
statusLabel.ForeColor = Color.Black;
|
||||
|
||||
var response = await _apiClient.CreateDrawingWithInfoAsync(selectedEquipment.ID, drawingNumber);
|
||||
|
||||
if (response.Success && response.Data.HasValue)
|
||||
{
|
||||
SelectedDrawingId = response.Data.Value;
|
||||
SelectedDrawingNumber = drawingNumber;
|
||||
statusLabel.Text = "Drawing created successfully";
|
||||
statusLabel.ForeColor = Color.Green;
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
var errorMsg = response.Error ?? "Unknown error occurred";
|
||||
statusLabel.Text = $"Failed to create drawing: {errorMsg}";
|
||||
statusLabel.ForeColor = Color.Red;
|
||||
MessageBox.Show($"Failed to create drawing: {errorMsg}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
okButton.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.Cancel;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
ExportDXF/Forms/DrawingSelectionForm.resx
Normal file
120
ExportDXF/Forms/DrawingSelectionForm.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
231
ExportDXF/Forms/MainForm.Designer.cs
generated
231
ExportDXF/Forms/MainForm.Designer.cs
generated
@@ -28,68 +28,46 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.activeDocTitleBox = new System.Windows.Forms.TextBox();
|
||||
this.logTextBox = new System.Windows.Forms.RichTextBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
this.runButton = new System.Windows.Forms.Button();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.viewFlipDeciderBox = new System.Windows.Forms.ComboBox();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.equipmentNoBox = new System.Windows.Forms.ComboBox();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
this.drawingNoBox = new System.Windows.Forms.ComboBox();
|
||||
this.mainTabControl = new System.Windows.Forms.TabControl();
|
||||
this.logEventsTab = new System.Windows.Forms.TabPage();
|
||||
this.logEventsDataGrid = new System.Windows.Forms.DataGridView();
|
||||
this.bomTab = new System.Windows.Forms.TabPage();
|
||||
this.bomDataGrid = new System.Windows.Forms.DataGridView();
|
||||
this.cutTemplatesTab = new System.Windows.Forms.TabPage();
|
||||
this.cutTemplatesDataGrid = new System.Windows.Forms.DataGridView();
|
||||
this.dwgDetailsTab = new System.Windows.Forms.TabPage();
|
||||
this.drawingPdfViewer = new AxAcroPDFLib.AxAcroPDF();
|
||||
this.mainTabControl.SuspendLayout();
|
||||
this.logEventsTab.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.logEventsDataGrid)).BeginInit();
|
||||
this.bomTab.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.bomDataGrid)).BeginInit();
|
||||
this.cutTemplatesTab.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.cutTemplatesDataGrid)).BeginInit();
|
||||
this.dwgDetailsTab.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.drawingPdfViewer)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// activeDocTitleBox
|
||||
//
|
||||
this.activeDocTitleBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.activeDocTitleBox.BackColor = System.Drawing.Color.White;
|
||||
this.activeDocTitleBox.Location = new System.Drawing.Point(130, 13);
|
||||
this.activeDocTitleBox.Name = "activeDocTitleBox";
|
||||
this.activeDocTitleBox.ReadOnly = true;
|
||||
this.activeDocTitleBox.Size = new System.Drawing.Size(748, 25);
|
||||
this.activeDocTitleBox.TabIndex = 1;
|
||||
this.activeDocTitleBox.TextChanged += new System.EventHandler(this.activeDocTitleBox_TextChanged);
|
||||
//
|
||||
// logTextBox
|
||||
//
|
||||
this.logTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.logTextBox.BackColor = System.Drawing.Color.White;
|
||||
this.logTextBox.Location = new System.Drawing.Point(12, 106);
|
||||
this.logTextBox.Name = "logTextBox";
|
||||
this.logTextBox.ReadOnly = true;
|
||||
this.logTextBox.Size = new System.Drawing.Size(866, 556);
|
||||
this.logTextBox.TabIndex = 10;
|
||||
this.logTextBox.Text = "";
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(13, 16);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(111, 17);
|
||||
this.label1.TabIndex = 0;
|
||||
this.label1.Text = "Active document :";
|
||||
//
|
||||
// runButton
|
||||
//
|
||||
this.runButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.runButton.Image = global::ExportDXF.Properties.Resources.play;
|
||||
this.runButton.Location = new System.Drawing.Point(884, 13);
|
||||
this.runButton.Location = new System.Drawing.Point(790, 13);
|
||||
this.runButton.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.runButton.Name = "runButton";
|
||||
this.runButton.Size = new System.Drawing.Size(46, 56);
|
||||
this.runButton.Size = new System.Drawing.Size(100, 30);
|
||||
this.runButton.TabIndex = 11;
|
||||
this.runButton.Text = "Start";
|
||||
this.runButton.UseVisualStyleBackColor = true;
|
||||
this.runButton.Click += new System.EventHandler(this.button1_Click);
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Location = new System.Drawing.Point(12, 47);
|
||||
this.label3.Location = new System.Drawing.Point(12, 20);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(112, 17);
|
||||
this.label3.TabIndex = 2;
|
||||
@@ -99,59 +77,123 @@
|
||||
//
|
||||
this.viewFlipDeciderBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.viewFlipDeciderBox.FormattingEnabled = true;
|
||||
this.viewFlipDeciderBox.Location = new System.Drawing.Point(130, 44);
|
||||
this.viewFlipDeciderBox.Location = new System.Drawing.Point(130, 17);
|
||||
this.viewFlipDeciderBox.Name = "viewFlipDeciderBox";
|
||||
this.viewFlipDeciderBox.Size = new System.Drawing.Size(432, 25);
|
||||
this.viewFlipDeciderBox.Size = new System.Drawing.Size(375, 25);
|
||||
this.viewFlipDeciderBox.TabIndex = 3;
|
||||
//
|
||||
// label4
|
||||
// mainTabControl
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(42, 78);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(82, 17);
|
||||
this.label4.TabIndex = 4;
|
||||
this.label4.Text = "Equipment #";
|
||||
this.mainTabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.mainTabControl.Controls.Add(this.logEventsTab);
|
||||
this.mainTabControl.Controls.Add(this.bomTab);
|
||||
this.mainTabControl.Controls.Add(this.cutTemplatesTab);
|
||||
this.mainTabControl.Controls.Add(this.dwgDetailsTab);
|
||||
this.mainTabControl.Location = new System.Drawing.Point(15, 50);
|
||||
this.mainTabControl.Name = "mainTabControl";
|
||||
this.mainTabControl.Padding = new System.Drawing.Point(20, 5);
|
||||
this.mainTabControl.SelectedIndex = 0;
|
||||
this.mainTabControl.Size = new System.Drawing.Size(879, 594);
|
||||
this.mainTabControl.TabIndex = 12;
|
||||
//
|
||||
// equipmentNoBox
|
||||
// logEventsTab
|
||||
//
|
||||
this.equipmentNoBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.equipmentNoBox.FormattingEnabled = true;
|
||||
this.equipmentNoBox.Location = new System.Drawing.Point(130, 75);
|
||||
this.equipmentNoBox.Name = "equipmentNoBox";
|
||||
this.equipmentNoBox.Size = new System.Drawing.Size(138, 25);
|
||||
this.equipmentNoBox.TabIndex = 5;
|
||||
this.logEventsTab.Controls.Add(this.logEventsDataGrid);
|
||||
this.logEventsTab.Location = new System.Drawing.Point(4, 30);
|
||||
this.logEventsTab.Name = "logEventsTab";
|
||||
this.logEventsTab.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.logEventsTab.Size = new System.Drawing.Size(871, 560);
|
||||
this.logEventsTab.TabIndex = 0;
|
||||
this.logEventsTab.Text = "Log Events";
|
||||
this.logEventsTab.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// label5
|
||||
// logEventsDataGrid
|
||||
//
|
||||
this.label5.AutoSize = true;
|
||||
this.label5.Location = new System.Drawing.Point(314, 78);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(68, 17);
|
||||
this.label5.TabIndex = 6;
|
||||
this.label5.Text = "Drawing #";
|
||||
this.logEventsDataGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.logEventsDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.logEventsDataGrid.Location = new System.Drawing.Point(6, 6);
|
||||
this.logEventsDataGrid.Name = "logEventsDataGrid";
|
||||
this.logEventsDataGrid.Size = new System.Drawing.Size(859, 548);
|
||||
this.logEventsDataGrid.TabIndex = 0;
|
||||
//
|
||||
// drawingNoBox
|
||||
// bomTab
|
||||
//
|
||||
this.drawingNoBox.FormattingEnabled = true;
|
||||
this.drawingNoBox.Location = new System.Drawing.Point(388, 75);
|
||||
this.drawingNoBox.Name = "drawingNoBox";
|
||||
this.drawingNoBox.Size = new System.Drawing.Size(174, 25);
|
||||
this.drawingNoBox.TabIndex = 7;
|
||||
this.bomTab.Controls.Add(this.bomDataGrid);
|
||||
this.bomTab.Location = new System.Drawing.Point(4, 30);
|
||||
this.bomTab.Name = "bomTab";
|
||||
this.bomTab.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.bomTab.Size = new System.Drawing.Size(871, 560);
|
||||
this.bomTab.TabIndex = 1;
|
||||
this.bomTab.Text = "Bill Of Materials";
|
||||
this.bomTab.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// bomDataGrid
|
||||
//
|
||||
this.bomDataGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.bomDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.bomDataGrid.Location = new System.Drawing.Point(6, 6);
|
||||
this.bomDataGrid.Name = "bomDataGrid";
|
||||
this.bomDataGrid.Size = new System.Drawing.Size(859, 548);
|
||||
this.bomDataGrid.TabIndex = 1;
|
||||
//
|
||||
// cutTemplatesTab
|
||||
//
|
||||
this.cutTemplatesTab.Controls.Add(this.cutTemplatesDataGrid);
|
||||
this.cutTemplatesTab.Location = new System.Drawing.Point(4, 30);
|
||||
this.cutTemplatesTab.Name = "cutTemplatesTab";
|
||||
this.cutTemplatesTab.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.cutTemplatesTab.Size = new System.Drawing.Size(871, 560);
|
||||
this.cutTemplatesTab.TabIndex = 3;
|
||||
this.cutTemplatesTab.Text = "Cut Templates";
|
||||
this.cutTemplatesTab.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// cutTemplatesDataGrid
|
||||
//
|
||||
this.cutTemplatesDataGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cutTemplatesDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.cutTemplatesDataGrid.Location = new System.Drawing.Point(6, 6);
|
||||
this.cutTemplatesDataGrid.Name = "cutTemplatesDataGrid";
|
||||
this.cutTemplatesDataGrid.Size = new System.Drawing.Size(859, 548);
|
||||
this.cutTemplatesDataGrid.TabIndex = 2;
|
||||
//
|
||||
// dwgDetailsTab
|
||||
//
|
||||
this.dwgDetailsTab.Controls.Add(this.drawingPdfViewer);
|
||||
this.dwgDetailsTab.Location = new System.Drawing.Point(4, 30);
|
||||
this.dwgDetailsTab.Name = "dwgDetailsTab";
|
||||
this.dwgDetailsTab.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.dwgDetailsTab.Size = new System.Drawing.Size(871, 560);
|
||||
this.dwgDetailsTab.TabIndex = 2;
|
||||
this.dwgDetailsTab.Text = "Drawing Details";
|
||||
this.dwgDetailsTab.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// drawingPdfViewer
|
||||
//
|
||||
this.drawingPdfViewer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.drawingPdfViewer.Enabled = true;
|
||||
this.drawingPdfViewer.Location = new System.Drawing.Point(6, 6);
|
||||
this.drawingPdfViewer.Name = "drawingPdfViewer";
|
||||
this.drawingPdfViewer.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("drawingPdfViewer.OcxState")));
|
||||
this.drawingPdfViewer.Size = new System.Drawing.Size(859, 548);
|
||||
this.drawingPdfViewer.TabIndex = 0;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
|
||||
this.ClientSize = new System.Drawing.Size(942, 674);
|
||||
this.Controls.Add(this.drawingNoBox);
|
||||
this.Controls.Add(this.equipmentNoBox);
|
||||
this.Controls.Add(this.label5);
|
||||
this.ClientSize = new System.Drawing.Size(906, 656);
|
||||
this.Controls.Add(this.mainTabControl);
|
||||
this.Controls.Add(this.viewFlipDeciderBox);
|
||||
this.Controls.Add(this.label4);
|
||||
this.Controls.Add(this.label3);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.logTextBox);
|
||||
this.Controls.Add(this.activeDocTitleBox);
|
||||
this.Controls.Add(this.runButton);
|
||||
this.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
@@ -160,6 +202,15 @@
|
||||
this.Name = "MainForm";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "ExportDXF";
|
||||
this.mainTabControl.ResumeLayout(false);
|
||||
this.logEventsTab.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.logEventsDataGrid)).EndInit();
|
||||
this.bomTab.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.bomDataGrid)).EndInit();
|
||||
this.cutTemplatesTab.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.cutTemplatesDataGrid)).EndInit();
|
||||
this.dwgDetailsTab.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.drawingPdfViewer)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
@@ -168,15 +219,17 @@
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button runButton;
|
||||
private System.Windows.Forms.TextBox activeDocTitleBox;
|
||||
private System.Windows.Forms.RichTextBox logTextBox;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.ComboBox viewFlipDeciderBox;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.ComboBox equipmentNoBox;
|
||||
private System.Windows.Forms.Label label5;
|
||||
private System.Windows.Forms.ComboBox drawingNoBox;
|
||||
private System.Windows.Forms.TabControl mainTabControl;
|
||||
private System.Windows.Forms.TabPage logEventsTab;
|
||||
private System.Windows.Forms.TabPage bomTab;
|
||||
private System.Windows.Forms.TabPage dwgDetailsTab;
|
||||
private System.Windows.Forms.DataGridView logEventsDataGrid;
|
||||
private AxAcroPDFLib.AxAcroPDF drawingPdfViewer;
|
||||
private System.Windows.Forms.DataGridView bomDataGrid;
|
||||
private System.Windows.Forms.TabPage cutTemplatesTab;
|
||||
private System.Windows.Forms.DataGridView cutTemplatesDataGrid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ using ExportDXF.Extensions;
|
||||
using ExportDXF.Models;
|
||||
using ExportDXF.Services;
|
||||
using ExportDXF.ViewFlipDeciders;
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -17,7 +17,13 @@ namespace ExportDXF.Forms
|
||||
private readonly IDxfExportService _exportService;
|
||||
private readonly ICutFabApiClient _apiClient;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
public MainForm(ISolidWorksService solidWorksService, IDxfExportService exportService, ICutFabApiClient apiClient)
|
||||
private readonly BindingList<LogEvent> _logEvents;
|
||||
private readonly BindingList<BomItem> _bomItems;
|
||||
private readonly BindingList<CutFabApiClient.ApiCutTemplate> _cutTemplates;
|
||||
private readonly int _selectedDrawingId;
|
||||
private readonly string _selectedDrawingNumber;
|
||||
|
||||
public MainForm(ISolidWorksService solidWorksService, IDxfExportService exportService, ICutFabApiClient apiClient, int selectedDrawingId, string selectedDrawingNumber)
|
||||
{
|
||||
InitializeComponent();
|
||||
_solidWorksService = solidWorksService ??
|
||||
@@ -26,7 +32,15 @@ namespace ExportDXF.Forms
|
||||
throw new ArgumentNullException(nameof(exportService));
|
||||
_apiClient = apiClient ??
|
||||
throw new ArgumentNullException(nameof(apiClient));
|
||||
_selectedDrawingId = selectedDrawingId;
|
||||
_selectedDrawingNumber = selectedDrawingNumber ?? throw new ArgumentNullException(nameof(selectedDrawingNumber));
|
||||
_logEvents = new BindingList<LogEvent>();
|
||||
_bomItems = new BindingList<BomItem>();
|
||||
_cutTemplates = new BindingList<CutFabApiClient.ApiCutTemplate>();
|
||||
InitializeViewFlipDeciders();
|
||||
InitializeLogEventsGrid();
|
||||
InitializeBomGrid();
|
||||
InitializeCutTemplatesGrid();
|
||||
}
|
||||
~MainForm()
|
||||
{
|
||||
@@ -51,8 +65,13 @@ namespace ExportDXF.Forms
|
||||
LogMessage("Ready", Color.Green);
|
||||
UpdateActiveDocumentDisplay();
|
||||
runButton.Enabled = true;
|
||||
// Populate equipment and (initial) drawings
|
||||
await PopulateEquipmentAsync();
|
||||
|
||||
// Load the selected drawing's BOM items
|
||||
LogMessage($"Loading BOM items for drawing {_selectedDrawingNumber}...");
|
||||
await LoadBomItemsForDrawingAsync(_selectedDrawingId);
|
||||
|
||||
// Load cut templates
|
||||
await LoadCutTemplatesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -61,74 +80,70 @@ namespace ExportDXF.Forms
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
private async Task PopulateEquipmentAsync()
|
||||
private async Task LoadBomItemsForDrawingAsync(int drawingId)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogMessage($"Loading equipment from {_apiClient.BaseUrl} ...");
|
||||
var list = await _apiClient.GetEquipmentAsync();
|
||||
equipmentNoBox.DisplayMember = nameof(CutFabApiClient.ApiEquipment.EquipmentNumber);
|
||||
equipmentNoBox.ValueMember = nameof(CutFabApiClient.ApiEquipment.ID);
|
||||
equipmentNoBox.DataSource = list;
|
||||
equipmentNoBox.SelectedIndexChanged -= equipmentNoBox_SelectedIndexChanged;
|
||||
equipmentNoBox.SelectedIndexChanged += equipmentNoBox_SelectedIndexChanged;
|
||||
if (list != null && list.Count > 0)
|
||||
_bomItems.Clear();
|
||||
|
||||
var apiBomItems = await _apiClient.GetBomItemsForDrawingAsync(drawingId);
|
||||
|
||||
foreach (var apiItem in apiBomItems)
|
||||
{
|
||||
equipmentNoBox.SelectedIndex = 0;
|
||||
await PopulateDrawingsForSelectedEquipmentAsync();
|
||||
LogMessage($"Loaded {list.Count} equipment record(s)", Color.Green);
|
||||
}
|
||||
else
|
||||
var bomItem = new BomItem
|
||||
{
|
||||
LogMessage("No equipment returned by API", Color.DarkBlue);
|
||||
ID = apiItem.ID,
|
||||
ItemNo = apiItem.ItemNo ?? "",
|
||||
PartNo = apiItem.PartNo ?? "",
|
||||
SortOrder = apiItem.SortOrder,
|
||||
Qty = apiItem.Qty,
|
||||
TotalQty = apiItem.TotalQty,
|
||||
Description = apiItem.Description ?? "",
|
||||
PartName = apiItem.PartName ?? "",
|
||||
ConfigurationName = apiItem.ConfigurationName ?? "",
|
||||
Material = apiItem.Material ?? "",
|
||||
DrawingID = apiItem.DrawingID,
|
||||
CutTemplateID = apiItem.CutTemplateID,
|
||||
CutTemplateName = apiItem.CutTemplateName ?? "",
|
||||
Thickness = apiItem.Thickness,
|
||||
KFactor = apiItem.KFactor,
|
||||
DefaultBendRadius = apiItem.DefaultBendRadius
|
||||
};
|
||||
|
||||
_bomItems.Add(bomItem);
|
||||
}
|
||||
|
||||
LogMessage($"Loaded {apiBomItems.Count} BOM item(s)", Color.Green);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"Failed to load equipment: {ex.Message}", Color.Red);
|
||||
LogMessage($"Failed to load BOM items: {ex.Message}", Color.Red);
|
||||
}
|
||||
}
|
||||
private async void equipmentNoBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
await PopulateDrawingsForSelectedEquipmentAsync();
|
||||
}
|
||||
private async Task PopulateDrawingsForSelectedEquipmentAsync()
|
||||
|
||||
private async Task LoadCutTemplatesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var selected = equipmentNoBox.SelectedItem as CutFabApiClient.ApiEquipment;
|
||||
if (selected == null)
|
||||
_cutTemplates.Clear();
|
||||
|
||||
LogMessage("Loading cut templates...");
|
||||
|
||||
var apiCutTemplates = await _apiClient.GetCutTemplatesAsync();
|
||||
|
||||
foreach (var template in apiCutTemplates)
|
||||
{
|
||||
drawingNoBox.DataSource = null;
|
||||
return;
|
||||
_cutTemplates.Add(template);
|
||||
}
|
||||
|
||||
// Store the currently selected drawing number
|
||||
var currentSelectedDrawing = drawingNoBox.SelectedItem as CutFabApiClient.ApiDrawingSummary;
|
||||
var previousDrawingNumber = currentSelectedDrawing?.DrawingNumber;
|
||||
|
||||
var drawings = await _apiClient.GetDrawingsForEquipmentAsync(selected.ID);
|
||||
drawingNoBox.DisplayMember = nameof(CutFabApiClient.ApiDrawingSummary.DrawingNumber);
|
||||
drawingNoBox.ValueMember = nameof(CutFabApiClient.ApiDrawingSummary.ID);
|
||||
drawingNoBox.DataSource = drawings;
|
||||
|
||||
// Try to restore the previous selection if it exists in the new list
|
||||
if (!string.IsNullOrEmpty(previousDrawingNumber) && drawings.Count > 0)
|
||||
{
|
||||
var matchingDrawing = drawings.FirstOrDefault(d => d.DrawingNumber == previousDrawingNumber);
|
||||
if (matchingDrawing != null)
|
||||
{
|
||||
drawingNoBox.SelectedItem = matchingDrawing;
|
||||
}
|
||||
}
|
||||
|
||||
LogMessage($"Loaded {drawings.Count} drawing(s) for equipment {selected.EquipmentNumber}");
|
||||
LogMessage($"Loaded {apiCutTemplates.Count} cut template(s)", Color.Green);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogMessage($"Failed to load drawings: {ex.Message}", Color.Red);
|
||||
LogMessage($"Failed to load cut templates: {ex.Message}", Color.Red);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeViewFlipDeciders()
|
||||
{
|
||||
var items = ViewFlipDeciderFactory.GetAvailableDeciders()
|
||||
@@ -148,6 +163,187 @@ namespace ExportDXF.Forms
|
||||
viewFlipDeciderBox.DataSource = items;
|
||||
viewFlipDeciderBox.DisplayMember = "Name";
|
||||
}
|
||||
private void InitializeLogEventsGrid()
|
||||
{
|
||||
// Clear any existing columns first
|
||||
logEventsDataGrid.Columns.Clear();
|
||||
|
||||
// Configure grid settings
|
||||
logEventsDataGrid.AutoGenerateColumns = false;
|
||||
logEventsDataGrid.AllowUserToAddRows = false;
|
||||
logEventsDataGrid.AllowUserToDeleteRows = false;
|
||||
logEventsDataGrid.ReadOnly = true;
|
||||
logEventsDataGrid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
|
||||
// Add columns
|
||||
logEventsDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(LogEvent.Time),
|
||||
HeaderText = "Time",
|
||||
Width = 80,
|
||||
DefaultCellStyle = new DataGridViewCellStyle { Format = "HH:mm:ss" }
|
||||
});
|
||||
|
||||
logEventsDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(LogEvent.Level),
|
||||
HeaderText = "Level",
|
||||
Width = 70
|
||||
});
|
||||
|
||||
logEventsDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(LogEvent.Message),
|
||||
HeaderText = "Message",
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
|
||||
});
|
||||
|
||||
// Set the data source AFTER adding columns
|
||||
logEventsDataGrid.DataSource = _logEvents;
|
||||
}
|
||||
|
||||
private void InitializeBomGrid()
|
||||
{
|
||||
// Clear any existing columns first
|
||||
bomDataGrid.Columns.Clear();
|
||||
|
||||
// Configure grid settings
|
||||
bomDataGrid.AutoGenerateColumns = false;
|
||||
bomDataGrid.AllowUserToAddRows = false;
|
||||
bomDataGrid.AllowUserToDeleteRows = false;
|
||||
bomDataGrid.ReadOnly = true;
|
||||
bomDataGrid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
|
||||
// Add columns
|
||||
bomDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(BomItem.ItemNo),
|
||||
HeaderText = "Item #",
|
||||
Width = 60
|
||||
});
|
||||
|
||||
bomDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(BomItem.PartNo),
|
||||
HeaderText = "Part #",
|
||||
Width = 100
|
||||
});
|
||||
|
||||
bomDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(BomItem.Qty),
|
||||
HeaderText = "Qty",
|
||||
Width = 50
|
||||
});
|
||||
|
||||
bomDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(BomItem.Description),
|
||||
HeaderText = "Description",
|
||||
Width = 200
|
||||
});
|
||||
|
||||
bomDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(BomItem.PartName),
|
||||
HeaderText = "Part Name",
|
||||
Width = 150
|
||||
});
|
||||
|
||||
bomDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(BomItem.ConfigurationName),
|
||||
HeaderText = "Configuration",
|
||||
Width = 120
|
||||
});
|
||||
|
||||
bomDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(BomItem.Material),
|
||||
HeaderText = "Material",
|
||||
Width = 120
|
||||
});
|
||||
|
||||
bomDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(BomItem.CutTemplateName),
|
||||
HeaderText = "Cut Template",
|
||||
Width = 120
|
||||
});
|
||||
|
||||
// Set the data source AFTER adding columns
|
||||
bomDataGrid.DataSource = _bomItems;
|
||||
}
|
||||
|
||||
private void InitializeCutTemplatesGrid()
|
||||
{
|
||||
// Clear any existing columns first
|
||||
cutTemplatesDataGrid.Columns.Clear();
|
||||
|
||||
// Configure grid settings
|
||||
cutTemplatesDataGrid.AutoGenerateColumns = false;
|
||||
cutTemplatesDataGrid.AllowUserToAddRows = false;
|
||||
cutTemplatesDataGrid.AllowUserToDeleteRows = false;
|
||||
cutTemplatesDataGrid.ReadOnly = true;
|
||||
cutTemplatesDataGrid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
|
||||
// Add columns
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutFabApiClient.ApiCutTemplate.Name),
|
||||
HeaderText = "Name",
|
||||
Width = 200
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutFabApiClient.ApiCutTemplate.Material),
|
||||
HeaderText = "Material",
|
||||
Width = 120
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutFabApiClient.ApiCutTemplate.Thickness),
|
||||
HeaderText = "Thickness",
|
||||
Width = 80,
|
||||
DefaultCellStyle = new DataGridViewCellStyle { Format = "0.##" }
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutFabApiClient.ApiCutTemplate.KFactor),
|
||||
HeaderText = "K-Factor",
|
||||
Width = 80,
|
||||
DefaultCellStyle = new DataGridViewCellStyle { Format = "0.####" }
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutFabApiClient.ApiCutTemplate.DefaultBendRadius),
|
||||
HeaderText = "Bend Radius",
|
||||
Width = 90,
|
||||
DefaultCellStyle = new DataGridViewCellStyle { Format = "0.##" }
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutFabApiClient.ApiCutTemplate.Version),
|
||||
HeaderText = "Version",
|
||||
Width = 70
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutFabApiClient.ApiCutTemplate.Description),
|
||||
HeaderText = "Description",
|
||||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
|
||||
});
|
||||
|
||||
// Set the data source AFTER adding columns
|
||||
cutTemplatesDataGrid.DataSource = _cutTemplates;
|
||||
}
|
||||
|
||||
private async void button1_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_cancellationTokenSource != null)
|
||||
@@ -173,14 +369,12 @@ namespace ExportDXF.Forms
|
||||
return;
|
||||
}
|
||||
var viewFlipDecider = GetSelectedViewFlipDecider();
|
||||
var drawingNumberText = drawingNoBox.Text?.Trim();
|
||||
var selectedEquipment = equipmentNoBox.SelectedItem as CutFabApiClient.ApiEquipment;
|
||||
var exportContext = new ExportContext
|
||||
{
|
||||
ActiveDocument = activeDoc,
|
||||
ViewFlipDecider = viewFlipDecider,
|
||||
FilePrefix = drawingNumberText,
|
||||
EquipmentId = selectedEquipment?.ID,
|
||||
FilePrefix = _selectedDrawingNumber,
|
||||
EquipmentId = null, // Not needed for export
|
||||
CancellationToken = token,
|
||||
ProgressCallback = LogMessage
|
||||
};
|
||||
@@ -216,17 +410,11 @@ namespace ExportDXF.Forms
|
||||
}
|
||||
private void UpdateUIForExportStart()
|
||||
{
|
||||
activeDocTitleBox.Enabled = false;
|
||||
viewFlipDeciderBox.Enabled = false;
|
||||
runButton.Image = Properties.Resources.stop_alt;
|
||||
if (logTextBox.TextLength != 0)
|
||||
{
|
||||
logTextBox.AppendText("\n\n");
|
||||
}
|
||||
}
|
||||
private void UpdateUIForExportComplete()
|
||||
{
|
||||
activeDocTitleBox.Enabled = true;
|
||||
viewFlipDeciderBox.Enabled = true;
|
||||
runButton.Image = Properties.Resources.play;
|
||||
runButton.Enabled = true;
|
||||
@@ -239,50 +427,52 @@ namespace ExportDXF.Forms
|
||||
return;
|
||||
}
|
||||
UpdateActiveDocumentDisplay();
|
||||
UpdatePrefixFromActiveDocument();
|
||||
}
|
||||
private void UpdateActiveDocumentDisplay()
|
||||
{
|
||||
var activeDoc = _solidWorksService.GetActiveDocument();
|
||||
activeDocTitleBox.Text = activeDoc?.Title ?? "<No Document Open>";
|
||||
}
|
||||
private void UpdatePrefixFromActiveDocument()
|
||||
{
|
||||
var activeDoc = _solidWorksService.GetActiveDocument();
|
||||
|
||||
if (activeDoc == null)
|
||||
return;
|
||||
|
||||
if (activeDoc.DocumentType == DocumentType.Drawing)
|
||||
{
|
||||
var drawingInfo = DrawingInfo.Parse(activeDoc.Title);
|
||||
|
||||
if (drawingInfo != null)
|
||||
{
|
||||
drawingNoBox.Text = drawingInfo.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
private void activeDocTitleBox_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdatePrefixFromActiveDocument();
|
||||
var docTitle = activeDoc?.Title ?? "No Document Open";
|
||||
this.Text = $"ExportDXF - {docTitle}";
|
||||
}
|
||||
private void LogMessage(string message, Color? color = null)
|
||||
{
|
||||
var level = color.HasValue && color.Value == Color.Red ? LogLevel.Error :
|
||||
color.HasValue && color.Value == Color.Green ? LogLevel.Info :
|
||||
color.HasValue && color.Value == Color.DarkBlue ? LogLevel.Warning :
|
||||
LogLevel.Info;
|
||||
|
||||
AddLogEvent(level, LogAction.Start, message);
|
||||
}
|
||||
|
||||
private void AddLogEvent(LogLevel level, LogAction action, string message, string equipment = "", string drawing = "", string part = "", string target = "", string result = "OK", int durationMs = 0)
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
Invoke(new Action(() => LogMessage(message, color)));
|
||||
Invoke(new Action(() => AddLogEvent(level, action, message, equipment, drawing, part, target, result, durationMs)));
|
||||
return;
|
||||
}
|
||||
if (color.HasValue)
|
||||
|
||||
var logEvent = new LogEvent
|
||||
{
|
||||
logTextBox.AppendText(message + System.Environment.NewLine, color.Value);
|
||||
}
|
||||
else
|
||||
Time = DateTime.Now,
|
||||
Level = level,
|
||||
Action = action,
|
||||
Message = message,
|
||||
Equipment = equipment,
|
||||
Drawing = drawing,
|
||||
Part = part,
|
||||
Target = target,
|
||||
Result = result,
|
||||
DurationMs = durationMs
|
||||
};
|
||||
|
||||
_logEvents.Add(logEvent);
|
||||
|
||||
// Auto-scroll to the last row
|
||||
if (logEventsDataGrid.Rows.Count > 0)
|
||||
{
|
||||
logTextBox.AppendText(message + System.Environment.NewLine);
|
||||
logEventsDataGrid.FirstDisplayedScrollingRowIndex = logEventsDataGrid.Rows.Count - 1;
|
||||
}
|
||||
logTextBox.ScrollToCaret();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,4 +117,12 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="drawingPdfViewer.OcxState" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
|
||||
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACFTeXN0
|
||||
ZW0uV2luZG93cy5Gb3Jtcy5BeEhvc3QrU3RhdGUBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAIQAAAAIB
|
||||
AAAAAQAAAAAAAAAAAAAAAAwAAAAADgAASGsAANA3AAAL
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
32
ExportDXF/Models/BomItem.cs
Normal file
32
ExportDXF/Models/BomItem.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace ExportDXF.Models
|
||||
{
|
||||
public class BomItem
|
||||
{
|
||||
public int ID { get; set; }
|
||||
public string ItemNo { get; set; } = "";
|
||||
public string PartNo { get; set; } = "";
|
||||
public int SortOrder { get; set; }
|
||||
public int? Qty { get; set; }
|
||||
public int? TotalQty { get; set; }
|
||||
public string Description { get; set; } = "";
|
||||
public string PartName { get; set; } = "";
|
||||
public string ConfigurationName { get; set; } = "";
|
||||
public string Material { get; set; } = "";
|
||||
public int DrawingID { get; set; }
|
||||
public int? CutTemplateID { get; set; }
|
||||
public string CutTemplateName { get; set; } = "";
|
||||
|
||||
// Sheet metal properties from CutTemplate
|
||||
public double? Thickness { get; set; }
|
||||
public double? KFactor { get; set; }
|
||||
public double? DefaultBendRadius { get; set; }
|
||||
}
|
||||
|
||||
public struct Size
|
||||
{
|
||||
public double Width { get; set; }
|
||||
public double Height { get; set; }
|
||||
}
|
||||
}
|
||||
22
ExportDXF/Models/LogEvent.cs
Normal file
22
ExportDXF/Models/LogEvent.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace ExportDXF.Models
|
||||
{
|
||||
public enum LogLevel { Info, Warning, Error }
|
||||
|
||||
public enum LogAction { Start, FindBom, CreateFlat, FlipView, SavePdf, UploadPdf, UploadDxf, CreateBomItem }
|
||||
|
||||
public sealed class LogEvent
|
||||
{
|
||||
public DateTime Time { get; set; } = DateTime.Now;
|
||||
public LogLevel Level { get; set; }
|
||||
public string Equipment { get; set; } = "";
|
||||
public string Drawing { get; set; } = "";
|
||||
public string Part { get; set; } = "";
|
||||
public LogAction Action { get; set; }
|
||||
public string Target { get; set; } = "";
|
||||
public string Result { get; set; } = "OK";
|
||||
public int DurationMs { get; set; }
|
||||
public string Message { get; set; } = "";
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using ExportDXF.Services;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace ExportDXF
|
||||
@@ -20,10 +21,21 @@ namespace ExportDXF
|
||||
// Simple DI setup - could use a DI container like Microsoft.Extensions.DependencyInjection
|
||||
var container = new ServiceContainer();
|
||||
|
||||
var mainForm = container.Resolve<MainForm>();
|
||||
// Show drawing selection dialog first
|
||||
var drawingSelectionForm = container.ResolveDrawingSelectionAsync().GetAwaiter().GetResult();
|
||||
var result = drawingSelectionForm.ShowDialog();
|
||||
|
||||
if (result == DialogResult.OK && drawingSelectionForm.SelectedDrawingId.HasValue)
|
||||
{
|
||||
// User selected a drawing, proceed to main form
|
||||
var mainForm = container.Resolve<MainForm>(
|
||||
drawingSelectionForm.SelectedDrawingId.Value,
|
||||
drawingSelectionForm.SelectedDrawingNumber);
|
||||
|
||||
Application.Run(mainForm);
|
||||
}
|
||||
// If user cancelled, just exit
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -32,7 +44,36 @@ namespace ExportDXF
|
||||
/// </summary>
|
||||
public class ServiceContainer
|
||||
{
|
||||
public MainForm Resolve<T>() where T : MainForm
|
||||
private readonly string _baseUrl;
|
||||
private readonly CutFabApiClient _apiClient;
|
||||
|
||||
public ServiceContainer()
|
||||
{
|
||||
_baseUrl = ConfigurationManager.AppSettings["CutFab.ApiBaseUrl"] ?? "http://localhost:7027";
|
||||
_apiClient = new CutFabApiClient(_baseUrl);
|
||||
}
|
||||
|
||||
public async Task<DrawingSelectionForm> ResolveDrawingSelectionAsync()
|
||||
{
|
||||
// Connect to SolidWorks first
|
||||
var solidWorksService = new SolidWorksService();
|
||||
try
|
||||
{
|
||||
await solidWorksService.ConnectAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Windows.Forms.MessageBox.Show(
|
||||
$"Warning: Could not connect to SolidWorks: {ex.Message}\n\nYou can still select a drawing, but the active document will not be displayed.",
|
||||
"SolidWorks Connection Warning",
|
||||
System.Windows.Forms.MessageBoxButtons.OK,
|
||||
System.Windows.Forms.MessageBoxIcon.Warning);
|
||||
}
|
||||
|
||||
return new DrawingSelectionForm(_apiClient, solidWorksService);
|
||||
}
|
||||
|
||||
public MainForm Resolve<T>(int selectedDrawingId, string selectedDrawingNumber) where T : MainForm
|
||||
{
|
||||
// Create the dependency tree
|
||||
var solidWorksService = new SolidWorksService();
|
||||
@@ -40,17 +81,15 @@ namespace ExportDXF
|
||||
var bomExtractor = new BomExtractor();
|
||||
var partExporter = new PartExporter();
|
||||
var drawingExporter = new DrawingExporter();
|
||||
var baseUrl = ConfigurationManager.AppSettings["CutFab.ApiBaseUrl"] ?? "http://localhost:7027";
|
||||
var apiClient = new CutFabApiClient(baseUrl);
|
||||
|
||||
var exportService = new DxfExportService(
|
||||
solidWorksService,
|
||||
bomExtractor,
|
||||
partExporter,
|
||||
drawingExporter,
|
||||
apiClient);
|
||||
_apiClient);
|
||||
|
||||
return new MainForm(solidWorksService, exportService, apiClient);
|
||||
return new MainForm(solidWorksService, exportService, _apiClient, selectedDrawingId, selectedDrawingNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,408 +0,0 @@
|
||||
using ExportDXF.Utilities;
|
||||
using OfficeOpenXml;
|
||||
using OfficeOpenXml.Style;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace ExportDXF.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Service for creating BOM Excel files.
|
||||
/// </summary>
|
||||
public interface IBomExcelExporter
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an Excel file containing the Bill of Materials.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The full path where the Excel file will be saved.</param>
|
||||
/// <param name="items">The list of items to include in the BOM.</param>
|
||||
void CreateBOMExcelFile(string filepath, IList<Item> items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Service for creating Excel files containing Bill of Materials data.
|
||||
/// </summary>
|
||||
public class BomExcelExporter : IBomExcelExporter
|
||||
{
|
||||
private const string DEFAULT_TEMPLATE_FILENAME = "BomTemplate.xlsx";
|
||||
private const string DEFAULT_SHEET_NAME = "Parts";
|
||||
private const int HEADER_ROW = 1;
|
||||
private const int DATA_START_ROW = 2;
|
||||
private const double COLUMN_PADDING = 2.0;
|
||||
private const int MAX_COLUMN_WIDTH = 50;
|
||||
|
||||
private readonly string _templatePath;
|
||||
private readonly BomExcelSettings _settings;
|
||||
|
||||
public BomExcelExporter() : this(GetDefaultTemplatePath(), new BomExcelSettings())
|
||||
{
|
||||
}
|
||||
|
||||
public BomExcelExporter(string templatePath) : this(templatePath, new BomExcelSettings())
|
||||
{
|
||||
}
|
||||
|
||||
public BomExcelExporter(string templatePath, BomExcelSettings settings)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(templatePath))
|
||||
throw new ArgumentException("Template path cannot be null or empty.", nameof(templatePath));
|
||||
|
||||
_templatePath = templatePath;
|
||||
_settings = settings ?? new BomExcelSettings();
|
||||
|
||||
// Set EPPlus license context (required for newer versions)
|
||||
//ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an Excel file containing the Bill of Materials.
|
||||
/// </summary>
|
||||
public void CreateBOMExcelFile(string filepath, IList<Item> items)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(filepath))
|
||||
throw new ArgumentException("Filepath cannot be null or empty.", nameof(filepath));
|
||||
|
||||
if (items == null)
|
||||
throw new ArgumentNullException(nameof(items));
|
||||
|
||||
ValidateAndPrepareFile(filepath);
|
||||
|
||||
using (var package = new ExcelPackage(new FileInfo(filepath)))
|
||||
{
|
||||
var worksheet = GetOrCreateWorksheet(package);
|
||||
|
||||
PopulateWorksheet(worksheet, items);
|
||||
FormatWorksheet(worksheet);
|
||||
|
||||
package.Save();
|
||||
}
|
||||
}
|
||||
|
||||
#region Worksheet Management
|
||||
|
||||
private ExcelWorksheet GetOrCreateWorksheet(ExcelPackage package)
|
||||
{
|
||||
var worksheet = package.Workbook.Worksheets[DEFAULT_SHEET_NAME];
|
||||
|
||||
if (worksheet == null)
|
||||
{
|
||||
if (_settings.CreateWorksheetIfMissing)
|
||||
{
|
||||
worksheet = package.Workbook.Worksheets.Add(DEFAULT_SHEET_NAME);
|
||||
CreateDefaultHeaders(worksheet);
|
||||
}
|
||||
else
|
||||
{
|
||||
var availableSheets = string.Join(", ",
|
||||
package.Workbook.Worksheets.Select(ws => ws.Name));
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Worksheet '{DEFAULT_SHEET_NAME}' not found in template. " +
|
||||
$"Available sheets: {availableSheets}");
|
||||
}
|
||||
}
|
||||
|
||||
return worksheet;
|
||||
}
|
||||
|
||||
private void CreateDefaultHeaders(ExcelWorksheet worksheet)
|
||||
{
|
||||
var headers = new[]
|
||||
{
|
||||
"Item No", "File Name", "Qty", "Description", "Part Name",
|
||||
"Configuration", "Thickness", "Material", "K-Factor", "Bend Radius"
|
||||
};
|
||||
|
||||
for (int i = 0; i < headers.Length; i++)
|
||||
{
|
||||
var cell = worksheet.Cells[HEADER_ROW, i + 1];
|
||||
cell.Value = headers[i];
|
||||
|
||||
if (_settings.FormatHeaders)
|
||||
{
|
||||
cell.Style.Font.Bold = true;
|
||||
cell.Style.Fill.PatternType = ExcelFillStyle.Solid;
|
||||
cell.Style.Fill.BackgroundColor.SetColor(Color.LightGray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data Population
|
||||
|
||||
private void PopulateWorksheet(ExcelWorksheet worksheet, IList<Item> items)
|
||||
{
|
||||
var filteredItems = _settings.SkipItemsWithoutFiles
|
||||
? items.Where(i => !string.IsNullOrEmpty(i.FileName)).ToList()
|
||||
: items.ToList();
|
||||
|
||||
for (int i = 0; i < filteredItems.Count; i++)
|
||||
{
|
||||
var item = filteredItems[i];
|
||||
var row = DATA_START_ROW + i;
|
||||
|
||||
WriteItemToRow(worksheet, row, item);
|
||||
}
|
||||
|
||||
// Add summary information if enabled
|
||||
if (_settings.AddSummary && filteredItems.Count > 0)
|
||||
{
|
||||
AddSummarySection(worksheet, filteredItems, DATA_START_ROW + filteredItems.Count + 2);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteItemToRow(ExcelWorksheet worksheet, int row, Item item)
|
||||
{
|
||||
int col = 1;
|
||||
|
||||
// Item No
|
||||
worksheet.Cells[row, col++].Value = FormatItemNumber(item.ItemNo);
|
||||
|
||||
// File Name
|
||||
worksheet.Cells[row, col++].Value = item.FileName;
|
||||
|
||||
// Quantity
|
||||
worksheet.Cells[row, col++].Value = item.Quantity;
|
||||
|
||||
// Description
|
||||
worksheet.Cells[row, col++].Value = CleanDescription(item.Description);
|
||||
|
||||
// Part Name
|
||||
worksheet.Cells[row, col++].Value = item.PartName;
|
||||
|
||||
// Configuration
|
||||
worksheet.Cells[row, col++].Value = item.Configuration;
|
||||
|
||||
// Thickness (only if > 0)
|
||||
worksheet.Cells[row, col++].Value = GetFormattedNumericValue(item.Thickness, _settings.ThicknessDecimalPlaces);
|
||||
|
||||
// Material
|
||||
worksheet.Cells[row, col++].Value = item.Material;
|
||||
|
||||
// K-Factor (only if > 0)
|
||||
worksheet.Cells[row, col++].Value = GetFormattedNumericValue(item.KFactor, _settings.KFactorDecimalPlaces);
|
||||
|
||||
// Bend Radius (only if > 0)
|
||||
worksheet.Cells[row, col++].Value = GetFormattedNumericValue(item.BendRadius, _settings.BendRadiusDecimalPlaces);
|
||||
|
||||
// Apply row formatting
|
||||
if (_settings.AlternateRowColors && row % 2 == 0)
|
||||
{
|
||||
var rowRange = worksheet.Cells[row, 1, row, col - 1];
|
||||
rowRange.Style.Fill.PatternType = ExcelFillStyle.Solid;
|
||||
rowRange.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(240, 240, 240));
|
||||
}
|
||||
}
|
||||
|
||||
private void AddSummarySection(ExcelWorksheet worksheet, IList<Item> items, int startRow)
|
||||
{
|
||||
worksheet.Cells[startRow, 1].Value = "SUMMARY";
|
||||
worksheet.Cells[startRow, 1].Style.Font.Bold = true;
|
||||
worksheet.Cells[startRow, 1].Style.Font.Size = 12;
|
||||
|
||||
startRow += 2;
|
||||
|
||||
// Total items
|
||||
worksheet.Cells[startRow, 1].Value = "Total Items:";
|
||||
worksheet.Cells[startRow, 2].Value = items.Count;
|
||||
|
||||
// Total quantity
|
||||
var totalQty = items.Sum(i => i.Quantity);
|
||||
worksheet.Cells[startRow + 1, 1].Value = "Total Quantity:";
|
||||
worksheet.Cells[startRow + 1, 2].Value = totalQty;
|
||||
|
||||
// Unique materials
|
||||
var uniqueMaterials = items.Where(i => !string.IsNullOrEmpty(i.Material))
|
||||
.Select(i => i.Material)
|
||||
.Distinct()
|
||||
.Count();
|
||||
|
||||
worksheet.Cells[startRow + 2, 1].Value = "Unique Materials:";
|
||||
worksheet.Cells[startRow + 2, 2].Value = uniqueMaterials;
|
||||
|
||||
// Thickness range
|
||||
var thicknesses = items.Where(i => i.Thickness > 0).Select(i => i.Thickness).ToList();
|
||||
if (thicknesses.Any())
|
||||
{
|
||||
worksheet.Cells[startRow + 3, 1].Value = "Thickness Range:";
|
||||
worksheet.Cells[startRow + 3, 2].Value = $"{thicknesses.Min():F1} - {thicknesses.Max():F1} mm";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data Formatting
|
||||
|
||||
private string FormatItemNumber(string itemNo)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(itemNo))
|
||||
return string.Empty;
|
||||
|
||||
// Try to parse as number and pad with zeros if it's a simple number
|
||||
if (int.TryParse(itemNo, out int number))
|
||||
{
|
||||
return number.ToString().PadLeft(_settings.ItemNumberPadding, '0');
|
||||
}
|
||||
|
||||
return itemNo;
|
||||
}
|
||||
|
||||
private string CleanDescription(string description)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(description))
|
||||
return string.Empty;
|
||||
|
||||
// Remove any remaining XML tags that might have been missed
|
||||
description = TextHelper.RemoveXmlTags(description);
|
||||
|
||||
// Trim and normalize whitespace
|
||||
return System.Text.RegularExpressions.Regex.Replace(description.Trim(), @"\s+", " ");
|
||||
}
|
||||
|
||||
private object GetFormattedNumericValue(double value, int decimalPlaces)
|
||||
{
|
||||
if (value <= 0)
|
||||
return null;
|
||||
|
||||
return Math.Round(value, decimalPlaces);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Worksheet Formatting
|
||||
|
||||
private void FormatWorksheet(ExcelWorksheet worksheet)
|
||||
{
|
||||
if (worksheet.Dimension == null)
|
||||
return;
|
||||
|
||||
// Auto-fit columns with limits
|
||||
for (int col = 1; col <= worksheet.Dimension.Columns; col++)
|
||||
{
|
||||
worksheet.Column(col).AutoFit();
|
||||
|
||||
// Special handling for Description column (assuming it's column 4)
|
||||
if (col == 4) // Description column
|
||||
{
|
||||
worksheet.Column(col).Width = Math.Max(worksheet.Column(col).Width, 30); // Minimum 30 units
|
||||
|
||||
if (worksheet.Column(col).Width > 50) // Maximum 50 units
|
||||
worksheet.Column(col).Width = 50;
|
||||
}
|
||||
else if (worksheet.Column(col).Width > MAX_COLUMN_WIDTH)
|
||||
{
|
||||
worksheet.Column(col).Width = MAX_COLUMN_WIDTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
worksheet.Column(col).Width += COLUMN_PADDING;
|
||||
}
|
||||
}
|
||||
|
||||
// Add borders if enabled
|
||||
if (_settings.AddBorders)
|
||||
{
|
||||
var dataRange = worksheet.Cells[HEADER_ROW, 1, worksheet.Dimension.End.Row, worksheet.Dimension.End.Column];
|
||||
dataRange.Style.Border.Top.Style = ExcelBorderStyle.Thin;
|
||||
dataRange.Style.Border.Left.Style = ExcelBorderStyle.Thin;
|
||||
dataRange.Style.Border.Right.Style = ExcelBorderStyle.Thin;
|
||||
dataRange.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
|
||||
}
|
||||
|
||||
// Format numeric columns
|
||||
FormatNumericColumns(worksheet);
|
||||
|
||||
// Freeze header row if enabled
|
||||
if (_settings.FreezeHeaderRow)
|
||||
{
|
||||
worksheet.View.FreezePanes(DATA_START_ROW, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void FormatNumericColumns(ExcelWorksheet worksheet)
|
||||
{
|
||||
if (worksheet.Dimension == null)
|
||||
return;
|
||||
|
||||
var lastRow = worksheet.Dimension.End.Row;
|
||||
|
||||
// Format quantity column (assuming it's column 3)
|
||||
if (worksheet.Dimension.Columns >= 3)
|
||||
{
|
||||
var qtyRange = worksheet.Cells[DATA_START_ROW, 3, lastRow, 3];
|
||||
qtyRange.Style.Numberformat.Format = "0";
|
||||
qtyRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
||||
}
|
||||
|
||||
// Format thickness column (assuming it's column 7)
|
||||
if (worksheet.Dimension.Columns >= 7)
|
||||
{
|
||||
var thicknessRange = worksheet.Cells[DATA_START_ROW, 7, lastRow, 7];
|
||||
thicknessRange.Style.Numberformat.Format = $"0.{new string('0', _settings.ThicknessDecimalPlaces)}";
|
||||
thicknessRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region File Management
|
||||
|
||||
private void ValidateAndPrepareFile(string filepath)
|
||||
{
|
||||
var directory = Path.GetDirectoryName(filepath);
|
||||
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
if (UseTemplate())
|
||||
{
|
||||
CopyTemplateToDestination(filepath);
|
||||
}
|
||||
else if (File.Exists(filepath))
|
||||
{
|
||||
File.Delete(filepath); // Remove existing file to start fresh
|
||||
}
|
||||
}
|
||||
|
||||
private bool UseTemplate()
|
||||
{
|
||||
return !string.IsNullOrEmpty(_templatePath) && File.Exists(_templatePath);
|
||||
}
|
||||
|
||||
private void CopyTemplateToDestination(string filepath)
|
||||
{
|
||||
if (!File.Exists(_templatePath))
|
||||
{
|
||||
throw new FileNotFoundException(
|
||||
$"BOM template file not found at: {_templatePath}. " +
|
||||
"Either provide a valid template or enable CreateWorksheetIfMissing.",
|
||||
_templatePath);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File.Copy(_templatePath, filepath, overwrite: true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new IOException($"Failed to copy template to {filepath}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDefaultTemplatePath()
|
||||
{
|
||||
return Path.Combine(
|
||||
AppDomain.CurrentDomain.BaseDirectory,
|
||||
"Templates",
|
||||
DEFAULT_TEMPLATE_FILENAME);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
namespace ExportDXF.Services
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Configuration settings for BOM Excel export.
|
||||
/// </summary>
|
||||
public class BomExcelSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Create the worksheet if it doesn't exist in the template.
|
||||
/// </summary>
|
||||
public bool CreateWorksheetIfMissing { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Skip items that don't have an associated DXF file.
|
||||
/// </summary>
|
||||
public bool SkipItemsWithoutFiles { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Add summary section with totals and statistics.
|
||||
/// </summary>
|
||||
public bool AddSummary { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Format header row with bold text and background color.
|
||||
/// </summary>
|
||||
public bool FormatHeaders { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Add borders around all cells.
|
||||
/// </summary>
|
||||
public bool AddBorders { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Freeze the header row for easier scrolling.
|
||||
/// </summary>
|
||||
public bool FreezeHeaderRow { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Alternate row background colors for easier reading.
|
||||
/// </summary>
|
||||
public bool AlternateRowColors { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Number of decimal places for thickness values.
|
||||
/// </summary>
|
||||
public int ThicknessDecimalPlaces { get; set; } = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Number of decimal places for K-Factor values.
|
||||
/// </summary>
|
||||
public int KFactorDecimalPlaces { get; set; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Number of decimal places for bend radius values.
|
||||
/// </summary>
|
||||
public int BendRadiusDecimalPlaces { get; set; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum number of digits for item numbers (pad with zeros).
|
||||
/// </summary>
|
||||
public int ItemNumberPadding { get; set; } = 2;
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ namespace ExportDXF.Services
|
||||
Task<bool> AutoLinkTemplatesAsync(int drawingId);
|
||||
Task<List<ApiEquipment>> GetEquipmentAsync();
|
||||
Task<List<ApiDrawingSummary>> GetDrawingsForEquipmentAsync(int equipmentId);
|
||||
Task<List<ApiBomItem>> GetBomItemsForDrawingAsync(int drawingId);
|
||||
Task<List<ApiCutTemplate>> GetCutTemplatesAsync();
|
||||
}
|
||||
|
||||
public class CutFabApiClient : ICutFabApiClient, IDisposable
|
||||
@@ -227,6 +229,92 @@ namespace ExportDXF.Services
|
||||
return resp.IsSuccessStatusCode;
|
||||
}
|
||||
|
||||
public async Task<List<ApiBomItem>> GetBomItemsForDrawingAsync(int drawingId)
|
||||
{
|
||||
var url = $"{_baseUrl}/api/BomItems/drawing/{drawingId}";
|
||||
var resp = await _http.GetAsync(url).ConfigureAwait(false);
|
||||
if (!resp.IsSuccessStatusCode) return new List<ApiBomItem>();
|
||||
var json = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var raw = serializer.DeserializeObject(json);
|
||||
var result = new List<ApiBomItem>();
|
||||
|
||||
if (raw is System.Collections.IEnumerable enumerable && !(raw is string))
|
||||
{
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
var dict = item as Dictionary<string, object>;
|
||||
if (dict == null) continue;
|
||||
var bomItem = new ApiBomItem();
|
||||
object v;
|
||||
if (TryGetCI(dict, new[] { "ID", "id" }, out v)) bomItem.ID = ToInt(v);
|
||||
if (TryGetCI(dict, new[] { "ItemNo", "itemNo" }, out v)) bomItem.ItemNo = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "PartNo", "partNo" }, out v)) bomItem.PartNo = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "SortOrder", "sortOrder" }, out v)) bomItem.SortOrder = ToInt(v);
|
||||
if (TryGetCI(dict, new[] { "Qty", "qty" }, out v)) bomItem.Qty = v != null ? (int?)ToInt(v) : null;
|
||||
if (TryGetCI(dict, new[] { "TotalQty", "totalQty" }, out v)) bomItem.TotalQty = v != null ? (int?)ToInt(v) : null;
|
||||
if (TryGetCI(dict, new[] { "Description", "description" }, out v)) bomItem.Description = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "PartName", "partName" }, out v)) bomItem.PartName = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "ConfigurationName", "configurationName" }, out v)) bomItem.ConfigurationName = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "Material", "material" }, out v)) bomItem.Material = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "DrawingID", "drawingID", "drawingId" }, out v)) bomItem.DrawingID = ToInt(v);
|
||||
if (TryGetCI(dict, new[] { "CutTemplateID", "cutTemplateID", "cutTemplateId" }, out v)) bomItem.CutTemplateID = v != null ? (int?)ToInt(v) : null;
|
||||
|
||||
// Try to get CutTemplate info if available
|
||||
if (TryGetCI(dict, new[] { "CutTemplate", "cutTemplate" }, out v))
|
||||
{
|
||||
var templateDict = v as Dictionary<string, object>;
|
||||
if (templateDict != null)
|
||||
{
|
||||
object tv;
|
||||
if (TryGetCI(templateDict, new[] { "Name", "name" }, out tv)) bomItem.CutTemplateName = tv?.ToString();
|
||||
if (TryGetCI(templateDict, new[] { "Thickness", "thickness" }, out tv)) bomItem.Thickness = ToDouble(tv);
|
||||
if (TryGetCI(templateDict, new[] { "KFactor", "kFactor", "kfactor" }, out tv)) bomItem.KFactor = ToDouble(tv);
|
||||
if (TryGetCI(templateDict, new[] { "DefaultBendRadius", "defaultBendRadius" }, out tv)) bomItem.DefaultBendRadius = ToDouble(tv);
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(bomItem);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<ApiCutTemplate>> GetCutTemplatesAsync()
|
||||
{
|
||||
var url = $"{_baseUrl}/api/CutTemplates";
|
||||
var resp = await _http.GetAsync(url).ConfigureAwait(false);
|
||||
if (!resp.IsSuccessStatusCode) return new List<ApiCutTemplate>();
|
||||
var json = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var raw = serializer.DeserializeObject(json);
|
||||
var result = new List<ApiCutTemplate>();
|
||||
|
||||
if (raw is System.Collections.IEnumerable enumerable && !(raw is string))
|
||||
{
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
var dict = item as Dictionary<string, object>;
|
||||
if (dict == null) continue;
|
||||
var template = new ApiCutTemplate();
|
||||
object v;
|
||||
if (TryGetCI(dict, new[] { "ID", "id" }, out v)) template.ID = ToInt(v);
|
||||
if (TryGetCI(dict, new[] { "Name", "name" }, out v)) template.Name = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "FilePath", "filePath" }, out v)) template.FilePath = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "Description", "description" }, out v)) template.Description = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "Material", "material" }, out v)) template.Material = v?.ToString();
|
||||
if (TryGetCI(dict, new[] { "Thickness", "thickness" }, out v)) template.Thickness = ToDouble(v);
|
||||
if (TryGetCI(dict, new[] { "KFactor", "kFactor", "kfactor" }, out v)) template.KFactor = ToDouble(v);
|
||||
if (TryGetCI(dict, new[] { "DefaultBendRadius", "defaultBendRadius" }, out v)) template.DefaultBendRadius = ToDouble(v);
|
||||
if (TryGetCI(dict, new[] { "Version", "version" }, out v)) template.Version = ToInt(v);
|
||||
result.Add(template);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_http?.Dispose();
|
||||
@@ -249,6 +337,39 @@ namespace ExportDXF.Services
|
||||
public override string ToString() => DrawingNumber ?? base.ToString();
|
||||
}
|
||||
|
||||
public class ApiBomItem
|
||||
{
|
||||
public int ID { get; set; }
|
||||
public string ItemNo { get; set; }
|
||||
public string PartNo { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public int? Qty { get; set; }
|
||||
public int? TotalQty { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string PartName { get; set; }
|
||||
public string ConfigurationName { get; set; }
|
||||
public string Material { get; set; }
|
||||
public int DrawingID { get; set; }
|
||||
public int? CutTemplateID { get; set; }
|
||||
public string CutTemplateName { get; set; }
|
||||
public double? Thickness { get; set; }
|
||||
public double? KFactor { get; set; }
|
||||
public double? DefaultBendRadius { get; set; }
|
||||
}
|
||||
|
||||
public class ApiCutTemplate
|
||||
{
|
||||
public int ID { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Material { get; set; }
|
||||
public double? Thickness { get; set; }
|
||||
public double? KFactor { get; set; }
|
||||
public double? DefaultBendRadius { get; set; }
|
||||
public int Version { get; set; }
|
||||
}
|
||||
|
||||
public async Task<List<ApiEquipment>> GetEquipmentAsync()
|
||||
{
|
||||
var url = $"{_baseUrl}/api/Equipment";
|
||||
@@ -332,5 +453,16 @@ namespace ExportDXF.Services
|
||||
if (v is double d) return (int)d;
|
||||
int parsed; if (int.TryParse(v.ToString(), out parsed)) return parsed; return 0;
|
||||
}
|
||||
|
||||
private static double? ToDouble(object v)
|
||||
{
|
||||
if (v == null) return null;
|
||||
if (v is double d) return d;
|
||||
if (v is int i) return (double)i;
|
||||
if (v is long l) return (double)l;
|
||||
if (v is float f) return (double)f;
|
||||
double parsed; if (double.TryParse(v.ToString(), out parsed)) return parsed;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user