diff --git a/ExportDXF/Forms/MainForm.Designer.cs b/ExportDXF/Forms/MainForm.Designer.cs index bc17a3e..741eedf 100644 --- a/ExportDXF/Forms/MainForm.Designer.cs +++ b/ExportDXF/Forms/MainForm.Designer.cs @@ -38,12 +38,8 @@ namespace ExportDXF.Forms bomDataGrid = new System.Windows.Forms.DataGridView(); cutTemplatesTab = new System.Windows.Forms.TabPage(); cutTemplatesDataGrid = new System.Windows.Forms.DataGridView(); - equipmentBox = new System.Windows.Forms.ComboBox(); - label1 = new System.Windows.Forms.Label(); - label2 = new System.Windows.Forms.Label(); - drawingNoBox = new System.Windows.Forms.ComboBox(); - titleLabel = new System.Windows.Forms.Label(); - titleBox = new System.Windows.Forms.TextBox(); + templateLabel = new System.Windows.Forms.Label(); + txtFilenameTemplate = new System.Windows.Forms.TextBox(); mainTabControl.SuspendLayout(); logEventsTab.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)logEventsDataGrid).BeginInit(); @@ -52,175 +48,137 @@ namespace ExportDXF.Forms cutTemplatesTab.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)cutTemplatesDataGrid).BeginInit(); SuspendLayout(); - // + // // runButton - // + // runButton.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; runButton.Location = new System.Drawing.Point(508, 12); runButton.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); runButton.Name = "runButton"; - runButton.Size = new System.Drawing.Size(65, 87); + runButton.Size = new System.Drawing.Size(65, 57); runButton.TabIndex = 11; runButton.Text = "Start"; runButton.UseVisualStyleBackColor = true; runButton.Click += button1_Click; - // + // + // templateLabel + // + templateLabel.AutoSize = true; + templateLabel.Location = new System.Drawing.Point(15, 15); + templateLabel.Name = "templateLabel"; + templateLabel.Size = new System.Drawing.Size(116, 17); + templateLabel.TabIndex = 2; + templateLabel.Text = "Filename Template"; + // + // txtFilenameTemplate + // + txtFilenameTemplate.Location = new System.Drawing.Point(137, 12); + txtFilenameTemplate.Name = "txtFilenameTemplate"; + txtFilenameTemplate.Size = new System.Drawing.Size(365, 25); + txtFilenameTemplate.TabIndex = 1; + // // label3 - // + // label3.AutoSize = true; - label3.Location = new System.Drawing.Point(26, 77); + label3.Location = new System.Drawing.Point(26, 46); label3.Name = "label3"; label3.Size = new System.Drawing.Size(105, 17); label3.TabIndex = 2; label3.Text = "View flip decider"; - // + // // viewFlipDeciderBox - // + // viewFlipDeciderBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; viewFlipDeciderBox.FormattingEnabled = true; - viewFlipDeciderBox.Location = new System.Drawing.Point(137, 74); + viewFlipDeciderBox.Location = new System.Drawing.Point(137, 43); viewFlipDeciderBox.Name = "viewFlipDeciderBox"; viewFlipDeciderBox.Size = new System.Drawing.Size(365, 25); viewFlipDeciderBox.TabIndex = 3; - // + // // mainTabControl - // + // mainTabControl.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; mainTabControl.Controls.Add(logEventsTab); mainTabControl.Controls.Add(bomTab); mainTabControl.Controls.Add(cutTemplatesTab); - mainTabControl.Location = new System.Drawing.Point(15, 105); + mainTabControl.Location = new System.Drawing.Point(15, 75); mainTabControl.Name = "mainTabControl"; mainTabControl.Padding = new System.Drawing.Point(20, 5); mainTabControl.SelectedIndex = 0; - mainTabControl.Size = new System.Drawing.Size(910, 492); + mainTabControl.Size = new System.Drawing.Size(910, 522); mainTabControl.TabIndex = 12; - // + // // logEventsTab - // + // logEventsTab.Controls.Add(logEventsDataGrid); logEventsTab.Location = new System.Drawing.Point(4, 30); logEventsTab.Name = "logEventsTab"; logEventsTab.Padding = new System.Windows.Forms.Padding(3); - logEventsTab.Size = new System.Drawing.Size(902, 458); + logEventsTab.Size = new System.Drawing.Size(902, 488); logEventsTab.TabIndex = 0; logEventsTab.Text = "Log Events"; logEventsTab.UseVisualStyleBackColor = true; - // + // // logEventsDataGrid - // + // logEventsDataGrid.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; logEventsDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; logEventsDataGrid.GridColor = System.Drawing.Color.WhiteSmoke; logEventsDataGrid.Location = new System.Drawing.Point(6, 6); logEventsDataGrid.Name = "logEventsDataGrid"; - logEventsDataGrid.Size = new System.Drawing.Size(890, 440); + logEventsDataGrid.Size = new System.Drawing.Size(890, 476); logEventsDataGrid.TabIndex = 0; - // + // // bomTab - // + // bomTab.Controls.Add(bomDataGrid); bomTab.Location = new System.Drawing.Point(4, 28); bomTab.Name = "bomTab"; bomTab.Padding = new System.Windows.Forms.Padding(3); - bomTab.Size = new System.Drawing.Size(902, 409); + bomTab.Size = new System.Drawing.Size(902, 490); bomTab.TabIndex = 1; bomTab.Text = "Bill Of Materials"; bomTab.UseVisualStyleBackColor = true; - // + // // bomDataGrid - // + // bomDataGrid.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; bomDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; bomDataGrid.GridColor = System.Drawing.Color.WhiteSmoke; bomDataGrid.Location = new System.Drawing.Point(6, 6); bomDataGrid.Name = "bomDataGrid"; - bomDataGrid.Size = new System.Drawing.Size(1281, 644); + bomDataGrid.Size = new System.Drawing.Size(890, 478); bomDataGrid.TabIndex = 1; - // + // // cutTemplatesTab - // + // cutTemplatesTab.Controls.Add(cutTemplatesDataGrid); cutTemplatesTab.Location = new System.Drawing.Point(4, 28); cutTemplatesTab.Name = "cutTemplatesTab"; cutTemplatesTab.Padding = new System.Windows.Forms.Padding(3); - cutTemplatesTab.Size = new System.Drawing.Size(902, 409); + cutTemplatesTab.Size = new System.Drawing.Size(902, 490); cutTemplatesTab.TabIndex = 2; cutTemplatesTab.Text = "Cut Templates"; cutTemplatesTab.UseVisualStyleBackColor = true; - // + // // cutTemplatesDataGrid - // + // cutTemplatesDataGrid.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; cutTemplatesDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; cutTemplatesDataGrid.GridColor = System.Drawing.Color.WhiteSmoke; cutTemplatesDataGrid.Location = new System.Drawing.Point(6, 6); cutTemplatesDataGrid.Name = "cutTemplatesDataGrid"; - cutTemplatesDataGrid.Size = new System.Drawing.Size(1281, 644); + cutTemplatesDataGrid.Size = new System.Drawing.Size(890, 478); cutTemplatesDataGrid.TabIndex = 2; - // - // equipmentBox - // - equipmentBox.FormattingEnabled = true; - equipmentBox.Location = new System.Drawing.Point(137, 12); - equipmentBox.Name = "equipmentBox"; - equipmentBox.Size = new System.Drawing.Size(166, 25); - equipmentBox.TabIndex = 13; - // - // label1 - // - label1.AutoSize = true; - label1.Location = new System.Drawing.Point(61, 15); - label1.Name = "label1"; - label1.Size = new System.Drawing.Size(70, 17); - label1.TabIndex = 2; - label1.Text = "Equipment"; - // - // label2 - // - label2.AutoSize = true; - label2.Location = new System.Drawing.Point(321, 15); - label2.Name = "label2"; - label2.Size = new System.Drawing.Size(56, 17); - label2.TabIndex = 2; - label2.Text = "Drawing"; - // - // drawingNoBox - // - drawingNoBox.FormattingEnabled = true; - drawingNoBox.Location = new System.Drawing.Point(383, 12); - drawingNoBox.Name = "drawingNoBox"; - drawingNoBox.Size = new System.Drawing.Size(119, 25); - drawingNoBox.TabIndex = 13; - // - // titleLabel - // - titleLabel.AutoSize = true; - titleLabel.Location = new System.Drawing.Point(99, 46); - titleLabel.Name = "titleLabel"; - titleLabel.Size = new System.Drawing.Size(32, 17); - titleLabel.TabIndex = 14; - titleLabel.Text = "Title"; - // - // titleBox - // - titleBox.Location = new System.Drawing.Point(137, 43); - titleBox.Name = "titleBox"; - titleBox.Size = new System.Drawing.Size(365, 25); - titleBox.TabIndex = 15; - // + // // MainForm - // + // AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; ClientSize = new System.Drawing.Size(937, 609); - Controls.Add(titleBox); - Controls.Add(titleLabel); - Controls.Add(drawingNoBox); - Controls.Add(equipmentBox); + Controls.Add(txtFilenameTemplate); Controls.Add(mainTabControl); Controls.Add(viewFlipDeciderBox); - Controls.Add(label2); - Controls.Add(label1); + Controls.Add(templateLabel); Controls.Add(label3); Controls.Add(runButton); Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); @@ -253,11 +211,7 @@ namespace ExportDXF.Forms private System.Windows.Forms.DataGridView bomDataGrid; private System.Windows.Forms.TabPage cutTemplatesTab; private System.Windows.Forms.DataGridView cutTemplatesDataGrid; - private System.Windows.Forms.ComboBox equipmentBox; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.ComboBox drawingNoBox; - private System.Windows.Forms.Label titleLabel; - private System.Windows.Forms.TextBox titleBox; + private System.Windows.Forms.Label templateLabel; + private System.Windows.Forms.TextBox txtFilenameTemplate; } } diff --git a/ExportDXF/Forms/MainForm.cs b/ExportDXF/Forms/MainForm.cs index cf124a3..24bb20f 100644 --- a/ExportDXF/Forms/MainForm.cs +++ b/ExportDXF/Forms/MainForm.cs @@ -1,12 +1,11 @@ -using ExportDXF.ApiClient; using ExportDXF.Extensions; using ExportDXF.Models; using ExportDXF.Services; using ExportDXF.ViewFlipDeciders; using System; -using System.Collections.Generic; using System.ComponentModel; using System.Drawing; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -18,14 +17,13 @@ namespace ExportDXF.Forms { private readonly ISolidWorksService _solidWorksService; private readonly IDxfExportService _exportService; - private readonly IFabWorksApiClient _apiClient; + private readonly IDrawingInfoExtractor[] _extractors; private CancellationTokenSource _cancellationTokenSource; private readonly BindingList _logEvents; private readonly BindingList _bomItems; private readonly BindingList _cutTemplates; - private List _allDrawings; - public MainForm(ISolidWorksService solidWorksService, IDxfExportService exportService, IFabWorksApiClient apiClient) + public MainForm(ISolidWorksService solidWorksService, IDxfExportService exportService, IDrawingInfoExtractor[] extractors) { InitializeComponent(); _solidWorksService = solidWorksService ?? @@ -33,17 +31,15 @@ namespace ExportDXF.Forms _solidWorksService.ActiveDocumentChanged += OnActiveDocumentChanged; _exportService = exportService ?? throw new ArgumentNullException(nameof(exportService)); - _apiClient = apiClient ?? - throw new ArgumentNullException(nameof(apiClient)); + _extractors = extractors ?? + throw new ArgumentNullException(nameof(extractors)); _logEvents = new BindingList(); _bomItems = new BindingList(); _cutTemplates = new BindingList(); - _allDrawings = new List(); InitializeViewFlipDeciders(); InitializeLogEventsGrid(); InitializeBomGrid(); InitializeCutTemplatesGrid(); - InitializeDrawingDropdowns(); } ~MainForm() @@ -68,10 +64,8 @@ namespace ExportDXF.Forms LogMessage("Connecting to SolidWorks, this may take a minute..."); await _solidWorksService.ConnectAsync(); _solidWorksService.ActiveDocumentChanged += OnActiveDocumentChanged; - LogMessage("Files will be uploaded to FabWorks API"); - await LoadDrawingDropdownsAsync(); LogMessage("Ready"); - await UpdateActiveDocumentDisplayAsync(); + UpdateActiveDocumentDisplay(); runButton.Enabled = true; } catch (Exception ex) @@ -91,7 +85,7 @@ namespace ExportDXF.Forms ViewFlipDecider = d }) .ToList(); - // Move "Automatic" to the top if it exists + var automatic = items.FirstOrDefault(i => i.Name == "Automatic"); if (automatic != null) { @@ -104,17 +98,13 @@ namespace ExportDXF.Forms 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), @@ -144,26 +134,19 @@ namespace ExportDXF.Forms AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill }); - // Add row coloring based on log level logEventsDataGrid.CellFormatting += LogEventsDataGrid_CellFormatting; - - // 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), @@ -213,14 +196,12 @@ namespace ExportDXF.Forms Width = 120 }); - // Set the data source AFTER adding columns bomDataGrid.DataSource = _bomItems; } private void InitializeCutTemplatesGrid() { cutTemplatesDataGrid.Columns.Clear(); - cutTemplatesDataGrid.AutoGenerateColumns = false; cutTemplatesDataGrid.AllowUserToAddRows = false; cutTemplatesDataGrid.AllowUserToDeleteRows = false; @@ -241,6 +222,13 @@ namespace ExportDXF.Forms Width = 250 }); + cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn + { + DataPropertyName = nameof(CutTemplate.Revision), + HeaderText = "Rev", + Width = 50 + }); + cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName = nameof(CutTemplate.Thickness), @@ -272,69 +260,6 @@ namespace ExportDXF.Forms cutTemplatesDataGrid.DataSource = _cutTemplates; } - private void InitializeDrawingDropdowns() - { - // Wire up event handler; actual data loading happens in LoadDrawingDropdownsAsync - equipmentBox.SelectedIndexChanged += EquipmentBox_SelectedIndexChanged; - } - - private async Task LoadDrawingDropdownsAsync() - { - try - { - var equipmentNumbers = await _apiClient.GetEquipmentNumbersAsync(); - - equipmentBox.Items.Clear(); - equipmentBox.Items.Add(""); - foreach (var eq in equipmentNumbers) - { - equipmentBox.Items.Add(eq); - } - - // Clear _allDrawings — drawing list is now loaded on equipment selection - _allDrawings = new List(); - await UpdateDrawingDropdownAsync(); - } - catch (Exception ex) - { - // API might not be available yet - that's OK - System.Diagnostics.Debug.WriteLine($"Failed to load equipment numbers from API: {ex.Message}"); - } - } - - private async void EquipmentBox_SelectedIndexChanged(object sender, EventArgs e) - { - await UpdateDrawingDropdownAsync(); - } - - private async Task UpdateDrawingDropdownAsync() - { - var selectedEquipment = equipmentBox.SelectedItem?.ToString(); - - drawingNoBox.Items.Clear(); - drawingNoBox.Items.Add(""); - - try - { - var drawingNumbers = await _apiClient.GetDrawingNumbersByEquipmentAsync( - string.IsNullOrEmpty(selectedEquipment) ? null : selectedEquipment); - - foreach (var dn in drawingNumbers) - { - drawingNoBox.Items.Add(dn); - } - } - catch - { - // API might not be available - } - - if (drawingNoBox.Items.Count > 0) - { - drawingNoBox.SelectedIndex = 0; - } - } - private async void button1_Click(object sender, EventArgs e) { if (_cancellationTokenSource != null) @@ -351,6 +276,13 @@ namespace ExportDXF.Forms { try { + var template = txtFilenameTemplate.Text.Trim(); + if (!FilenameTemplateParser.Validate(template, out var error)) + { + MessageBox.Show(error, "Invalid Template", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + _cancellationTokenSource = new CancellationTokenSource(); var token = _cancellationTokenSource.Token; UpdateUIForExportStart(); @@ -362,36 +294,27 @@ namespace ExportDXF.Forms return; } - // Use equipment/drawing values from the UI dropdowns - var equipment = equipmentBox.Text?.Trim(); - var drawingNo = drawingNoBox.Text?.Trim(); - var filePrefix = !string.IsNullOrEmpty(equipment) - ? (!string.IsNullOrEmpty(drawingNo) ? $"{equipment} {drawingNo}" : equipment) - : activeDoc.Title; + var sourceDir = Path.GetDirectoryName(activeDoc.FilePath); + var outputFolder = Path.Combine(sourceDir, "Templates"); var viewFlipDecider = GetSelectedViewFlipDecider(); - var title = titleBox.Text?.Trim(); var exportContext = new ExportContext { ActiveDocument = activeDoc, ViewFlipDecider = viewFlipDecider, - FilePrefix = filePrefix, - Equipment = equipment, - DrawingNo = drawingNo, - Title = string.IsNullOrEmpty(title) ? null : title, - EquipmentId = null, + FilenameTemplate = template, + OutputFolder = outputFolder, CancellationToken = token, ProgressCallback = (msg, level, file) => LogMessage(msg, level, file), BomItemCallback = AddBomItem }; - // Clear previous BOM items and cut templates _bomItems.Clear(); _cutTemplates.Clear(); LogMessage($"Started at {DateTime.Now:t}"); - LogMessage("Exporting (files will be uploaded to API)..."); + LogMessage($"Output: {outputFolder}"); _solidWorksService.SetCommandInProgress(true); @@ -432,27 +355,29 @@ namespace ExportDXF.Forms private void UpdateUIForExportStart() { viewFlipDeciderBox.Enabled = false; + txtFilenameTemplate.Enabled = false; runButton.Text = "Stop"; } private void UpdateUIForExportComplete() { viewFlipDeciderBox.Enabled = true; + txtFilenameTemplate.Enabled = true; runButton.Text = "Start"; runButton.Enabled = true; } - private async void OnActiveDocumentChanged(object sender, EventArgs e) + private void OnActiveDocumentChanged(object sender, EventArgs e) { if (InvokeRequired) { - Invoke(new Action(async () => await UpdateActiveDocumentDisplayAsync())); + Invoke(new Action(() => UpdateActiveDocumentDisplay())); return; } - await UpdateActiveDocumentDisplayAsync(); + UpdateActiveDocumentDisplay(); } - private async Task UpdateActiveDocumentDisplayAsync() + private void UpdateActiveDocumentDisplay() { var activeDoc = _solidWorksService.GetActiveDocument(); var docTitle = activeDoc?.Title ?? "No Document Open"; @@ -461,66 +386,17 @@ namespace ExportDXF.Forms if (activeDoc == null) return; - // Try API first: look up the most recent export for this file path - DrawingInfo drawingInfo = null; - - if (!string.IsNullOrEmpty(activeDoc.FilePath)) + // Try each extractor to auto-fill the template + foreach (var extractor in _extractors) { - drawingInfo = await LookupDrawingInfoFromHistoryAsync(activeDoc.FilePath); - } - - // Fall back to parsing the document title - if (drawingInfo == null) - { - drawingInfo = DrawingInfo.Parse(activeDoc.Title); - } - - if (drawingInfo != null) - { - // Detach event to prevent async race when setting equipment - equipmentBox.SelectedIndexChanged -= EquipmentBox_SelectedIndexChanged; - - if (!string.IsNullOrEmpty(drawingInfo.EquipmentNo)) + if (extractor.TryExtract(activeDoc.Title, out var info)) { - if (!equipmentBox.Items.Contains(drawingInfo.EquipmentNo)) - equipmentBox.Items.Add(drawingInfo.EquipmentNo); - equipmentBox.Text = drawingInfo.EquipmentNo; - } - - // Load drawings for the selected equipment, then set drawing number - await UpdateDrawingDropdownAsync(); - - equipmentBox.SelectedIndexChanged += EquipmentBox_SelectedIndexChanged; - - if (!string.IsNullOrEmpty(drawingInfo.DrawingNo)) - { - if (!drawingNoBox.Items.Contains(drawingInfo.DrawingNo)) - drawingNoBox.Items.Add(drawingInfo.DrawingNo); - drawingNoBox.Text = drawingInfo.DrawingNo; + txtFilenameTemplate.Text = info.DefaultTemplate; + return; } } } - private async Task LookupDrawingInfoFromHistoryAsync(string filePath) - { - try - { - var dto = await _apiClient.GetExportBySourceFileAsync(filePath); - if (dto != null && !string.IsNullOrEmpty(dto.DrawingNumber)) - { - if (!string.IsNullOrEmpty(dto.Title)) - titleBox.Text = dto.Title; - return DrawingInfo.Parse(dto.DrawingNumber); - } - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine($"Failed to look up drawing info from API: {ex.Message}"); - } - - return null; - } - private void LogMessage(string message, LogLevel level = LogLevel.Info, string file = null) { AddLogEvent(level, LogAction.Start, message, part: file); @@ -550,7 +426,6 @@ namespace ExportDXF.Forms _logEvents.Add(logEvent); - // Auto-scroll to the last row if (logEventsDataGrid.Rows.Count > 0) { logEventsDataGrid.FirstDisplayedScrollingRowIndex = logEventsDataGrid.Rows.Count - 1;