1009 lines
37 KiB
C#
1009 lines
37 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Drawing;
|
||
using System.Linq;
|
||
using System.Windows.Forms;
|
||
using CadParamPluging.Common;
|
||
|
||
namespace CadParamPluging.UI
|
||
{
|
||
public class TemplateSchemaBindingForm : Form
|
||
{
|
||
private const string OwnershipForging = "锻件尺寸";
|
||
private const string OwnershipPart = "零件尺寸";
|
||
|
||
private readonly ComboBox _cbProjectType;
|
||
private readonly ComboBox _cbDrawingType;
|
||
private readonly ComboBox _cbSheetSize;
|
||
private readonly ComboBox _cbScale;
|
||
private readonly TextBox _txtDisplayName;
|
||
private readonly Label _lblTemplateKey;
|
||
private readonly ListBox _lbSchemas;
|
||
private readonly ListView _lvParams;
|
||
|
||
private readonly TextBox _txtNoteTemplate;
|
||
private readonly Label _lblNotePlaceholderCount;
|
||
private readonly DataGridView _gvNoteBindings;
|
||
private readonly RichTextBox _rtbNotePreview;
|
||
|
||
private readonly List<ParamOption> _remarkParamOptions;
|
||
|
||
private readonly ParamCatalog _catalog;
|
||
private TemplateSchemas _schemas;
|
||
|
||
private sealed class ParamOption
|
||
{
|
||
public string Key { get; set; }
|
||
public string Display { get; set; }
|
||
}
|
||
|
||
public TemplateSchemaBindingForm(
|
||
System.Collections.Generic.IEnumerable<string> projectTypes,
|
||
System.Collections.Generic.IEnumerable<string> drawingTypes,
|
||
System.Collections.Generic.IEnumerable<string> sheetSizes,
|
||
System.Collections.Generic.IEnumerable<string> scales,
|
||
ParamCatalog catalog)
|
||
{
|
||
Text = "模板参数绑定";
|
||
Size = new Size(920, 620);
|
||
MinimumSize = new Size(920, 620);
|
||
StartPosition = FormStartPosition.CenterParent;
|
||
FormBorderStyle = FormBorderStyle.Sizable;
|
||
MaximizeBox = true;
|
||
MinimizeBox = true;
|
||
ShowInTaskbar = false;
|
||
|
||
_catalog = (catalog ?? ParamCatalog.CreateDefault()).Clone();
|
||
_catalog.Normalize();
|
||
|
||
_remarkParamOptions = (_catalog.Items ?? Enumerable.Empty<ParamDefinition>())
|
||
.Where(p => p != null && string.Equals(p.Group ?? string.Empty, "备注参数", StringComparison.OrdinalIgnoreCase))
|
||
.OrderBy(p => p.Order)
|
||
.Select(p => new ParamOption { Key = p.Key, Display = string.Format("{0} ({1})", p.Label, p.Key) })
|
||
.ToList();
|
||
|
||
_schemas = TemplateSchemaStore.Load() ?? new TemplateSchemas();
|
||
_schemas.Normalize();
|
||
|
||
var root = new TableLayoutPanel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
Padding = new Padding(10),
|
||
ColumnCount = 2,
|
||
RowCount = 2
|
||
};
|
||
root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 260));
|
||
root.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
|
||
root.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
|
||
root.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||
|
||
_lbSchemas = new ListBox { Dock = DockStyle.Fill };
|
||
|
||
var leftButtons = new FlowLayoutPanel
|
||
{
|
||
Dock = DockStyle.Bottom,
|
||
FlowDirection = FlowDirection.LeftToRight,
|
||
AutoSize = true
|
||
};
|
||
var btnNew = new Button { Text = "新增模板", AutoSize = true };
|
||
btnNew.Click += (_, __) => OnNewSchema();
|
||
var btnDelete = new Button { Text = "删除模板", AutoSize = true };
|
||
btnDelete.Click += (_, __) => OnDeleteSchema();
|
||
leftButtons.Controls.Add(btnNew);
|
||
leftButtons.Controls.Add(btnDelete);
|
||
|
||
var leftPanel = new Panel { Dock = DockStyle.Fill };
|
||
leftPanel.Controls.Add(_lbSchemas);
|
||
leftPanel.Controls.Add(leftButtons);
|
||
leftButtons.Dock = DockStyle.Bottom;
|
||
|
||
var editor = new TableLayoutPanel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
ColumnCount = 2,
|
||
RowCount = 4,
|
||
AutoSize = true
|
||
};
|
||
editor.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||
editor.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
|
||
|
||
_cbProjectType = CreateCombo(projectTypes);
|
||
_cbDrawingType = CreateCombo(drawingTypes);
|
||
_cbSheetSize = CreateCombo(sheetSizes);
|
||
_cbScale = CreateCombo(scales);
|
||
|
||
_cbProjectType.SelectedIndexChanged += (_, __) => UpdateTemplateKeyLabel();
|
||
_cbDrawingType.SelectedIndexChanged += (_, __) => UpdateTemplateKeyLabel();
|
||
_cbSheetSize.SelectedIndexChanged += (_, __) => UpdateTemplateKeyLabel();
|
||
_cbScale.SelectedIndexChanged += (_, __) => UpdateTemplateKeyLabel();
|
||
|
||
_txtDisplayName = new TextBox { Width = 380 };
|
||
|
||
_lblTemplateKey = new Label { AutoSize = true, ForeColor = Color.DarkBlue };
|
||
|
||
var row = 0;
|
||
editor.Controls.Add(new Label { Text = "交付状态", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row);
|
||
editor.Controls.Add(_cbProjectType, 1, row++);
|
||
editor.Controls.Add(new Label { Text = "工艺方法", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row);
|
||
editor.Controls.Add(_cbDrawingType, 1, row++);
|
||
editor.Controls.Add(new Label { Text = "结构特征", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row);
|
||
editor.Controls.Add(_cbSheetSize, 1, row++);
|
||
editor.Controls.Add(new Label { Text = "特殊条件", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, row);
|
||
editor.Controls.Add(_cbScale, 1, row++);
|
||
|
||
var topBar = new TableLayoutPanel
|
||
{
|
||
Dock = DockStyle.Top,
|
||
ColumnCount = 2,
|
||
RowCount = 2,
|
||
AutoSize = true
|
||
};
|
||
topBar.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
||
topBar.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f));
|
||
|
||
topBar.Controls.Add(new Label { Text = "显示名称", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 0);
|
||
topBar.Controls.Add(_txtDisplayName, 1, 0);
|
||
topBar.Controls.Add(new Label { Text = "TemplateKey", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 1);
|
||
topBar.Controls.Add(_lblTemplateKey, 1, 1);
|
||
|
||
_lvParams = new ListView
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
View = View.Details,
|
||
FullRowSelect = true,
|
||
HideSelection = false,
|
||
CheckBoxes = true
|
||
};
|
||
_lvParams.Columns.Add("Label", 220);
|
||
_lvParams.Columns.Add("Key", 160);
|
||
_lvParams.Columns.Add("归属", 100);
|
||
|
||
var paramsButtonPanel = new FlowLayoutPanel
|
||
{
|
||
Dock = DockStyle.Top,
|
||
FlowDirection = FlowDirection.LeftToRight,
|
||
AutoSize = true
|
||
};
|
||
var btnUp = new Button { Text = "上移", AutoSize = true };
|
||
btnUp.Click += (_, __) => MoveSelectedParam(-1);
|
||
var btnDown = new Button { Text = "下移", AutoSize = true };
|
||
btnDown.Click += (_, __) => MoveSelectedParam(1);
|
||
var btnSelectAll = new Button { Text = "全选", AutoSize = true };
|
||
btnSelectAll.Click += (_, __) => SetAllChecked(true);
|
||
var btnUnselectAll = new Button { Text = "全不选", AutoSize = true };
|
||
btnUnselectAll.Click += (_, __) => SetAllChecked(false);
|
||
var btnSetForging = new Button { Text = "设为锻件尺寸", AutoSize = true };
|
||
btnSetForging.Click += (_, __) => SetSelectedOwnership(false);
|
||
var btnSetPart = new Button { Text = "设为零件尺寸", AutoSize = true };
|
||
btnSetPart.Click += (_, __) => SetSelectedOwnership(true);
|
||
paramsButtonPanel.Controls.Add(btnUp);
|
||
paramsButtonPanel.Controls.Add(btnDown);
|
||
paramsButtonPanel.Controls.Add(btnSelectAll);
|
||
paramsButtonPanel.Controls.Add(btnUnselectAll);
|
||
paramsButtonPanel.Controls.Add(btnSetForging);
|
||
paramsButtonPanel.Controls.Add(btnSetPart);
|
||
|
||
_txtNoteTemplate = new TextBox
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
Multiline = true,
|
||
ScrollBars = ScrollBars.Vertical,
|
||
Height = 120
|
||
};
|
||
|
||
_lblNotePlaceholderCount = new Label
|
||
{
|
||
AutoSize = true,
|
||
ForeColor = Color.DarkBlue,
|
||
Text = "占位符: 0"
|
||
};
|
||
|
||
_gvNoteBindings = new DataGridView
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
AutoGenerateColumns = false,
|
||
AllowUserToAddRows = false,
|
||
AllowUserToDeleteRows = false,
|
||
RowHeadersVisible = false,
|
||
SelectionMode = DataGridViewSelectionMode.FullRowSelect
|
||
};
|
||
|
||
var colIdx = new DataGridViewTextBoxColumn
|
||
{
|
||
HeaderText = "序号",
|
||
Width = 60,
|
||
ReadOnly = true
|
||
};
|
||
|
||
var colLine = new DataGridViewTextBoxColumn
|
||
{
|
||
HeaderText = "所在行",
|
||
Width = 80,
|
||
ReadOnly = true
|
||
};
|
||
|
||
var colSnippet = new DataGridViewTextBoxColumn
|
||
{
|
||
HeaderText = "文本定位",
|
||
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
|
||
ReadOnly = true
|
||
};
|
||
|
||
var colParam = new DataGridViewComboBoxColumn
|
||
{
|
||
HeaderText = "绑定参数(备注参数)",
|
||
Width = 320,
|
||
DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton,
|
||
DataSource = _remarkParamOptions,
|
||
DisplayMember = "Display",
|
||
ValueMember = "Key"
|
||
};
|
||
|
||
_gvNoteBindings.Columns.Add(colIdx);
|
||
_gvNoteBindings.Columns.Add(colLine);
|
||
_gvNoteBindings.Columns.Add(colSnippet);
|
||
_gvNoteBindings.Columns.Add(colParam);
|
||
|
||
_gvNoteBindings.DataError += (_, __) => { };
|
||
_gvNoteBindings.SelectionChanged += (_, __) => HighlightSelectedPlaceholderInPreview();
|
||
|
||
_rtbNotePreview = new RichTextBox
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
ReadOnly = true,
|
||
HideSelection = false
|
||
};
|
||
|
||
var btnParseNote = new Button { Text = "解析占位符", AutoSize = true };
|
||
btnParseNote.Click += (_, __) => ReloadNoteBindingsFromTemplateText();
|
||
|
||
var rightPanel = new TableLayoutPanel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
ColumnCount = 1,
|
||
RowCount = 3
|
||
};
|
||
rightPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||
rightPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||
rightPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
|
||
|
||
rightPanel.Controls.Add(editor, 0, 0);
|
||
rightPanel.Controls.Add(topBar, 0, 1);
|
||
|
||
var paramArea = new TableLayoutPanel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
ColumnCount = 1,
|
||
RowCount = 2
|
||
};
|
||
paramArea.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||
paramArea.RowStyles.Add(new RowStyle(SizeType.Percent, 100f));
|
||
paramArea.Controls.Add(paramsButtonPanel, 0, 0);
|
||
paramArea.Controls.Add(_lvParams, 0, 1);
|
||
|
||
var noteArea = new TableLayoutPanel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
ColumnCount = 1,
|
||
RowCount = 6,
|
||
Padding = new Padding(0)
|
||
};
|
||
noteArea.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||
noteArea.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||
noteArea.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||
noteArea.RowStyles.Add(new RowStyle(SizeType.Percent, 60f));
|
||
noteArea.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||
noteArea.RowStyles.Add(new RowStyle(SizeType.Percent, 40f));
|
||
|
||
noteArea.Controls.Add(new Label { Text = "附注模板(多行文本,使用 * 作为占位符;**** 会忽略)", AutoSize = true }, 0, 0);
|
||
noteArea.Controls.Add(_txtNoteTemplate, 0, 1);
|
||
|
||
var noteToolbar = new FlowLayoutPanel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
FlowDirection = FlowDirection.LeftToRight,
|
||
AutoSize = true
|
||
};
|
||
noteToolbar.Controls.Add(btnParseNote);
|
||
noteToolbar.Controls.Add(_lblNotePlaceholderCount);
|
||
noteArea.Controls.Add(noteToolbar, 0, 2);
|
||
noteArea.Controls.Add(_gvNoteBindings, 0, 3);
|
||
noteArea.Controls.Add(new Label { Text = "编号预览(用于对照绑定):", AutoSize = true }, 0, 4);
|
||
noteArea.Controls.Add(_rtbNotePreview, 0, 5);
|
||
|
||
var tabs = new TabControl { Dock = DockStyle.Fill };
|
||
var tabParams = new TabPage { Text = "参数绑定" };
|
||
tabParams.Controls.Add(paramArea);
|
||
var tabNotes = new TabPage { Text = "附注绑定" };
|
||
tabNotes.Controls.Add(noteArea);
|
||
tabs.TabPages.Add(tabParams);
|
||
tabs.TabPages.Add(tabNotes);
|
||
|
||
rightPanel.Controls.Add(tabs, 0, 2);
|
||
|
||
var bottomButtons = new FlowLayoutPanel
|
||
{
|
||
Dock = DockStyle.Fill,
|
||
FlowDirection = FlowDirection.RightToLeft,
|
||
AutoSize = true
|
||
};
|
||
var btnClose = new Button { Text = "关闭", DialogResult = DialogResult.Cancel };
|
||
var btnSave = new Button { Text = "保存" };
|
||
btnSave.Click += (_, __) => OnSave();
|
||
bottomButtons.Controls.Add(btnClose);
|
||
bottomButtons.Controls.Add(btnSave);
|
||
|
||
root.Controls.Add(leftPanel, 0, 0);
|
||
root.Controls.Add(rightPanel, 1, 0);
|
||
root.Controls.Add(bottomButtons, 0, 1);
|
||
root.SetColumnSpan(bottomButtons, 2);
|
||
|
||
Controls.Add(root);
|
||
CancelButton = btnClose;
|
||
|
||
BuildParamListItems();
|
||
UpdateTemplateKeyLabel();
|
||
|
||
_lbSchemas.SelectedIndexChanged += (_, __) => LoadSelectedSchemaToUi();
|
||
ReloadSchemaList();
|
||
}
|
||
|
||
private static ComboBox CreateCombo(System.Collections.Generic.IEnumerable<string> items)
|
||
{
|
||
var cb = new ComboBox { DropDownStyle = ComboBoxStyle.DropDownList, Width = 220 };
|
||
var arr = (items ?? Enumerable.Empty<string>())
|
||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||
.Select(s => s.Trim())
|
||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||
.ToArray();
|
||
if (arr.Length > 0)
|
||
{
|
||
cb.Items.AddRange(arr);
|
||
cb.SelectedIndex = 0;
|
||
}
|
||
return cb;
|
||
}
|
||
|
||
private void BuildParamListItems()
|
||
{
|
||
_lvParams.BeginUpdate();
|
||
try
|
||
{
|
||
_lvParams.Items.Clear();
|
||
foreach (var p in (_catalog.Items ?? Enumerable.Empty<ParamDefinition>())
|
||
.Where(x => x != null)
|
||
.Where(x => !string.Equals(x.Group ?? string.Empty, "备注参数", StringComparison.OrdinalIgnoreCase))
|
||
.OrderBy(x => x.Order))
|
||
{
|
||
var it = new ListViewItem(new[] { p.Label, p.Key, GuessOwnershipText(p.Key) })
|
||
{
|
||
Tag = p.Key,
|
||
Checked = false
|
||
};
|
||
_lvParams.Items.Add(it);
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
_lvParams.EndUpdate();
|
||
}
|
||
}
|
||
|
||
private void ApplySchemaToParamList(TemplateSchemaDefinition schema)
|
||
{
|
||
var selectedKeys = (schema?.SelectedParamKeys ?? new List<string>()).ToList();
|
||
var keySet = new HashSet<string>(selectedKeys, StringComparer.OrdinalIgnoreCase);
|
||
|
||
var partKeySet = new HashSet<string>(
|
||
(schema?.SelectedPartParamKeys ?? new List<string>()).Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()),
|
||
StringComparer.OrdinalIgnoreCase);
|
||
|
||
var all = _lvParams.Items.Cast<ListViewItem>().ToList();
|
||
var byKey = all.ToDictionary(i => (string)i.Tag, i => i, StringComparer.OrdinalIgnoreCase);
|
||
|
||
foreach (var it in all)
|
||
{
|
||
var key = (string)it.Tag;
|
||
if (string.IsNullOrWhiteSpace(key))
|
||
{
|
||
continue;
|
||
}
|
||
EnsureOwnershipSubItem(it);
|
||
if (partKeySet.Contains(key))
|
||
{
|
||
it.SubItems[2].Text = OwnershipPart;
|
||
}
|
||
else if (keySet.Contains(key))
|
||
{
|
||
it.SubItems[2].Text = OwnershipForging;
|
||
}
|
||
else if (string.IsNullOrWhiteSpace(it.SubItems[2].Text))
|
||
{
|
||
it.SubItems[2].Text = GuessOwnershipText(key);
|
||
}
|
||
}
|
||
|
||
var ordered = new List<ListViewItem>();
|
||
foreach (var k in selectedKeys)
|
||
{
|
||
if (byKey.TryGetValue(k, out var it))
|
||
{
|
||
ordered.Add(it);
|
||
}
|
||
}
|
||
|
||
foreach (var it in all)
|
||
{
|
||
if (!keySet.Contains((string)it.Tag))
|
||
{
|
||
ordered.Add(it);
|
||
}
|
||
}
|
||
|
||
_lvParams.BeginUpdate();
|
||
try
|
||
{
|
||
_lvParams.Items.Clear();
|
||
foreach (var it in ordered)
|
||
{
|
||
var key = (string)it.Tag;
|
||
it.Checked = keySet.Contains(key);
|
||
_lvParams.Items.Add(it);
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
_lvParams.EndUpdate();
|
||
}
|
||
}
|
||
|
||
private void ReloadSchemaList()
|
||
{
|
||
var prev = _lbSchemas.SelectedIndex;
|
||
|
||
_lbSchemas.Items.Clear();
|
||
foreach (var s in (_schemas.Items ?? Enumerable.Empty<TemplateSchemaDefinition>())
|
||
.Where(x => x != null)
|
||
.OrderBy(x => x.ProjectType)
|
||
.ThenBy(x => x.DrawingType)
|
||
.ThenBy(x => x.SheetSize)
|
||
.ThenBy(x => x.Scale))
|
||
{
|
||
_lbSchemas.Items.Add(FormatSchema(s));
|
||
}
|
||
|
||
if (_lbSchemas.Items.Count > 0)
|
||
{
|
||
_lbSchemas.SelectedIndex = Math.Max(0, Math.Min(prev, _lbSchemas.Items.Count - 1));
|
||
}
|
||
}
|
||
|
||
private static string FormatSchema(TemplateSchemaDefinition s)
|
||
{
|
||
if (s == null)
|
||
{
|
||
return "(null)";
|
||
}
|
||
|
||
var name = string.IsNullOrWhiteSpace(s.DisplayName) ? "(未命名)" : s.DisplayName;
|
||
return $"{name} | {s.ProjectType}/{s.DrawingType}/{s.SheetSize}/{s.Scale}";
|
||
}
|
||
|
||
private TemplateSchemaDefinition GetSelectedSchema()
|
||
{
|
||
var idx = _lbSchemas.SelectedIndex;
|
||
if (idx < 0)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
var ordered = (_schemas.Items ?? Enumerable.Empty<TemplateSchemaDefinition>())
|
||
.Where(x => x != null)
|
||
.OrderBy(x => x.ProjectType)
|
||
.ThenBy(x => x.DrawingType)
|
||
.ThenBy(x => x.SheetSize)
|
||
.ThenBy(x => x.Scale)
|
||
.ToList();
|
||
|
||
if (idx >= ordered.Count)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
var key = ordered[idx].TemplateKey;
|
||
return (_schemas.Items ?? new List<TemplateSchemaDefinition>())
|
||
.Where(x => x != null)
|
||
.FirstOrDefault(x => string.Equals(x.TemplateKey, key, StringComparison.OrdinalIgnoreCase));
|
||
}
|
||
|
||
private void LoadSelectedSchemaToUi()
|
||
{
|
||
var schema = GetSelectedSchema();
|
||
if (schema == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
SelectComboByText(_cbProjectType, schema.ProjectType);
|
||
SelectComboByText(_cbDrawingType, schema.DrawingType);
|
||
SelectComboByText(_cbSheetSize, schema.SheetSize);
|
||
SelectComboByText(_cbScale, schema.Scale);
|
||
_txtDisplayName.Text = schema.DisplayName ?? string.Empty;
|
||
UpdateTemplateKeyLabel();
|
||
ApplySchemaToParamList(schema);
|
||
LoadNoteBindingsToUi(schema);
|
||
}
|
||
|
||
private static void SelectComboByText(ComboBox cb, string value)
|
||
{
|
||
if (cb == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var v = (value ?? string.Empty).Trim();
|
||
for (var i = 0; i < cb.Items.Count; i++)
|
||
{
|
||
if (string.Equals((cb.Items[i] as string) ?? string.Empty, v, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
cb.SelectedIndex = i;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
private void UpdateTemplateKeyLabel()
|
||
{
|
||
var key = TemplateKeyBuilder.Build(_cbProjectType.Text, _cbDrawingType.Text, _cbSheetSize.Text, _cbScale.Text);
|
||
_lblTemplateKey.Text = key ?? string.Empty;
|
||
}
|
||
|
||
private void OnNewSchema()
|
||
{
|
||
if (string.IsNullOrWhiteSpace(_cbProjectType.Text) || string.IsNullOrWhiteSpace(_cbDrawingType.Text))
|
||
{
|
||
MessageBox.Show(this, "请先选择模板四个参数。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
return;
|
||
}
|
||
|
||
var candidate = new TemplateSchemaDefinition
|
||
{
|
||
ProjectType = _cbProjectType.Text,
|
||
DrawingType = _cbDrawingType.Text,
|
||
SheetSize = _cbSheetSize.Text,
|
||
Scale = _cbScale.Text,
|
||
DisplayName = _txtDisplayName.Text
|
||
};
|
||
candidate.Normalize();
|
||
|
||
if ((_schemas.Items ?? new List<TemplateSchemaDefinition>())
|
||
.Where(x => x != null)
|
||
.Any(x => string.Equals(x.TemplateKey, candidate.TemplateKey, StringComparison.OrdinalIgnoreCase)))
|
||
{
|
||
MessageBox.Show(this, "该模板定义已存在(四参数组合重复)。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
return;
|
||
}
|
||
|
||
if (_schemas.Items == null)
|
||
{
|
||
_schemas.Items = new List<TemplateSchemaDefinition>();
|
||
}
|
||
_schemas.Items.Add(candidate);
|
||
_schemas.Normalize();
|
||
ReloadSchemaList();
|
||
}
|
||
|
||
private void OnDeleteSchema()
|
||
{
|
||
var schema = GetSelectedSchema();
|
||
if (schema == null)
|
||
{
|
||
MessageBox.Show(this, "请先选择一个模板定义。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var confirm = MessageBox.Show(this, $"确认删除模板定义:{FormatSchema(schema)}?", "删除", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||
if (confirm != DialogResult.Yes)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_schemas.Items = (_schemas.Items ?? Enumerable.Empty<TemplateSchemaDefinition>())
|
||
.Where(x => x != null && !string.Equals(x.TemplateKey, schema.TemplateKey, StringComparison.OrdinalIgnoreCase))
|
||
.ToList();
|
||
_schemas.Normalize();
|
||
ReloadSchemaList();
|
||
}
|
||
|
||
private void MoveSelectedParam(int delta)
|
||
{
|
||
if (_lvParams.SelectedItems.Count == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var item = _lvParams.SelectedItems[0];
|
||
var idx = item.Index;
|
||
var newIdx = idx + delta;
|
||
if (newIdx < 0 || newIdx >= _lvParams.Items.Count)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_lvParams.BeginUpdate();
|
||
try
|
||
{
|
||
_lvParams.Items.RemoveAt(idx);
|
||
_lvParams.Items.Insert(newIdx, item);
|
||
item.Selected = true;
|
||
item.Focused = true;
|
||
}
|
||
finally
|
||
{
|
||
_lvParams.EndUpdate();
|
||
}
|
||
}
|
||
|
||
private void SetSelectedOwnership(bool part)
|
||
{
|
||
if (_lvParams.SelectedItems.Count == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_lvParams.BeginUpdate();
|
||
try
|
||
{
|
||
foreach (ListViewItem it in _lvParams.SelectedItems)
|
||
{
|
||
if (it == null)
|
||
{
|
||
continue;
|
||
}
|
||
EnsureOwnershipSubItem(it);
|
||
it.SubItems[2].Text = part ? OwnershipPart : OwnershipForging;
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
_lvParams.EndUpdate();
|
||
}
|
||
}
|
||
|
||
private static void EnsureOwnershipSubItem(ListViewItem it)
|
||
{
|
||
if (it == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
while (it.SubItems.Count < 3)
|
||
{
|
||
it.SubItems.Add(string.Empty);
|
||
}
|
||
}
|
||
|
||
private static bool IsPartKey(string key)
|
||
{
|
||
var k = (key ?? string.Empty).Trim();
|
||
return k.EndsWith("Prime", StringComparison.OrdinalIgnoreCase);
|
||
}
|
||
|
||
private static string GuessOwnershipText(string key)
|
||
{
|
||
return IsPartKey(key) ? OwnershipPart : OwnershipForging;
|
||
}
|
||
|
||
private void SetAllChecked(bool value)
|
||
{
|
||
_lvParams.BeginUpdate();
|
||
try
|
||
{
|
||
foreach (ListViewItem it in _lvParams.Items)
|
||
{
|
||
it.Checked = value;
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
_lvParams.EndUpdate();
|
||
}
|
||
}
|
||
|
||
private void LoadNoteBindingsToUi(TemplateSchemaDefinition schema)
|
||
{
|
||
if (schema == null)
|
||
{
|
||
_txtNoteTemplate.Text = string.Empty;
|
||
ReloadNoteBindingsGrid(string.Empty, null);
|
||
return;
|
||
}
|
||
|
||
_txtNoteTemplate.Text = schema.NoteTemplateText ?? string.Empty;
|
||
ReloadNoteBindingsGrid(_txtNoteTemplate.Text, schema.NoteBindings);
|
||
}
|
||
|
||
private void ReloadNoteBindingsFromTemplateText()
|
||
{
|
||
var map = ReadNoteBindingMapFromGrid();
|
||
|
||
var bindings = map
|
||
.Select(kv => new NotePlaceholderBinding { Index = kv.Key, ParamKey = kv.Value })
|
||
.ToList();
|
||
|
||
ReloadNoteBindingsGrid(_txtNoteTemplate.Text ?? string.Empty, bindings);
|
||
}
|
||
|
||
private void ReloadNoteBindingsGrid(string templateText, IEnumerable<NotePlaceholderBinding> bindings)
|
||
{
|
||
var occ = NoteTemplateEngine.ParseOccurrences(templateText ?? string.Empty);
|
||
var count = occ.Count;
|
||
_lblNotePlaceholderCount.Text = string.Format("占位符: {0}", count);
|
||
|
||
_rtbNotePreview.Text = NoteTemplateEngine.BuildNumberedPreviewText(templateText ?? string.Empty);
|
||
|
||
var map = new Dictionary<int, string>();
|
||
foreach (var b in bindings ?? Enumerable.Empty<NotePlaceholderBinding>())
|
||
{
|
||
if (b == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (b.Index <= 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var key = (b.ParamKey ?? string.Empty).Trim();
|
||
if (key.Length == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (!map.ContainsKey(b.Index))
|
||
{
|
||
map[b.Index] = key;
|
||
}
|
||
}
|
||
|
||
_gvNoteBindings.SuspendLayout();
|
||
try
|
||
{
|
||
_gvNoteBindings.Rows.Clear();
|
||
foreach (var o in occ)
|
||
{
|
||
var idx = _gvNoteBindings.Rows.Add();
|
||
var row = _gvNoteBindings.Rows[idx];
|
||
row.Cells[0].Value = o.Index;
|
||
row.Cells[1].Value = string.Format("第{0}行", o.LineNumber);
|
||
row.Cells[2].Value = BuildOccurrenceSnippet(o);
|
||
row.Cells[3].Value = map.ContainsKey(o.Index) ? map[o.Index] : null;
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
_gvNoteBindings.ResumeLayout();
|
||
}
|
||
|
||
HighlightSelectedPlaceholderInPreview();
|
||
}
|
||
|
||
private Dictionary<int, string> ReadNoteBindingMapFromGrid()
|
||
{
|
||
var map = new Dictionary<int, string>();
|
||
foreach (DataGridViewRow row in _gvNoteBindings.Rows)
|
||
{
|
||
if (row == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var idxObj = row.Cells[0].Value;
|
||
var keyObj = row.Cells[3].Value;
|
||
|
||
int idx;
|
||
if (idxObj == null || !int.TryParse(idxObj.ToString(), out idx) || idx <= 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var key = (keyObj ?? string.Empty).ToString().Trim();
|
||
if (key.Length == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (!map.ContainsKey(idx))
|
||
{
|
||
map[idx] = key;
|
||
}
|
||
}
|
||
|
||
return map;
|
||
}
|
||
|
||
private static string BuildOccurrenceSnippet(NoteTemplateEngine.PlaceholderOccurrence o)
|
||
{
|
||
if (o == null)
|
||
{
|
||
return string.Empty;
|
||
}
|
||
|
||
var line = o.LineText ?? string.Empty;
|
||
var token = string.Format("【#{0}】", o.Index);
|
||
|
||
var col = o.ColumnInLine;
|
||
if (col < 0) col = 0;
|
||
if (col >= line.Length)
|
||
{
|
||
return token;
|
||
}
|
||
|
||
const int ctx = 16;
|
||
var start = Math.Max(0, col - ctx);
|
||
var end = Math.Min(line.Length, col + 1 + ctx);
|
||
|
||
var prefix = start > 0 ? "…" : string.Empty;
|
||
var suffix = end < line.Length ? "…" : string.Empty;
|
||
|
||
var left = line.Substring(start, col - start);
|
||
var right = line.Substring(col + 1, end - (col + 1));
|
||
|
||
return prefix + left + token + right + suffix;
|
||
}
|
||
|
||
private void HighlightSelectedPlaceholderInPreview()
|
||
{
|
||
if (_rtbNotePreview == null || string.IsNullOrEmpty(_rtbNotePreview.Text))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (_gvNoteBindings.SelectedRows.Count == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var row = _gvNoteBindings.SelectedRows[0];
|
||
if (row == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var idxObj = row.Cells[0].Value;
|
||
int idx;
|
||
if (idxObj == null || !int.TryParse(idxObj.ToString(), out idx) || idx <= 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var token = string.Format("【#{0}】", idx);
|
||
var pos = _rtbNotePreview.Text.IndexOf(token, StringComparison.Ordinal);
|
||
if (pos < 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_rtbNotePreview.Select(pos, token.Length);
|
||
_rtbNotePreview.ScrollToCaret();
|
||
}
|
||
|
||
private void OnSave()
|
||
{
|
||
var schema = GetSelectedSchema();
|
||
if (schema == null)
|
||
{
|
||
MessageBox.Show(this, "请先选择一个模板定义。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
schema.ProjectType = _cbProjectType.Text;
|
||
schema.DrawingType = _cbDrawingType.Text;
|
||
schema.SheetSize = _cbSheetSize.Text;
|
||
schema.Scale = _cbScale.Text;
|
||
schema.DisplayName = _txtDisplayName.Text;
|
||
|
||
var selectedParamKeys = _lvParams.Items
|
||
.Cast<ListViewItem>()
|
||
.Where(i => i.Checked)
|
||
.Select(i => (string)i.Tag)
|
||
.Where(k => !string.IsNullOrWhiteSpace(k))
|
||
.ToList();
|
||
|
||
// “备注参数”仅在附注绑定中配置,不出现在模板参数绑定里。
|
||
selectedParamKeys = selectedParamKeys
|
||
.Where(k =>
|
||
{
|
||
var def = _catalog.FindByKey(k);
|
||
if (def == null)
|
||
{
|
||
return true;
|
||
}
|
||
return !string.Equals(def.Group ?? string.Empty, "备注参数", StringComparison.OrdinalIgnoreCase);
|
||
})
|
||
.ToList();
|
||
|
||
schema.SelectedParamKeys = selectedParamKeys;
|
||
|
||
var selectedPartKeys = _lvParams.Items
|
||
.Cast<ListViewItem>()
|
||
.Where(i => i != null && i.Checked)
|
||
.Select(i =>
|
||
{
|
||
var key = ((string)i.Tag ?? string.Empty).Trim();
|
||
EnsureOwnershipSubItem(i);
|
||
var own = (i.SubItems[2].Text ?? string.Empty).Trim();
|
||
if (own.Length == 0)
|
||
{
|
||
own = GuessOwnershipText(key);
|
||
i.SubItems[2].Text = own;
|
||
}
|
||
var isPart = string.Equals(own, OwnershipPart, StringComparison.OrdinalIgnoreCase);
|
||
return new { Key = key, IsPart = isPart };
|
||
})
|
||
.Where(x => x.Key.Length > 0 && x.IsPart)
|
||
.Select(x => x.Key)
|
||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||
.ToList();
|
||
|
||
schema.SelectedPartParamKeys = selectedPartKeys;
|
||
schema.PartOwnershipConfigured = true;
|
||
|
||
schema.NoteTemplateText = _txtNoteTemplate.Text ?? string.Empty;
|
||
var placeholderCount = NoteTemplateEngine.CountPlaceholders(schema.NoteTemplateText);
|
||
if (_gvNoteBindings.Rows.Count != placeholderCount)
|
||
{
|
||
ReloadNoteBindingsFromTemplateText();
|
||
MessageBox.Show(this, "附注模板已变化,已重新解析占位符。请确认附注绑定后再保存。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
return;
|
||
}
|
||
|
||
var noteBindings = new List<NotePlaceholderBinding>();
|
||
if (placeholderCount > 0)
|
||
{
|
||
var map = ReadNoteBindingMapFromGrid();
|
||
for (var i = 1; i <= placeholderCount; i++)
|
||
{
|
||
if (!map.TryGetValue(i, out var key) || string.IsNullOrWhiteSpace(key))
|
||
{
|
||
MessageBox.Show(this, string.Format("请绑定第 {0} 个占位符(*)对应的参数。", i), "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
return;
|
||
}
|
||
|
||
var def = _catalog.FindByKey(key);
|
||
if (def == null || !string.Equals(def.Group ?? string.Empty, "备注参数", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
MessageBox.Show(this, string.Format("占位符 #{0} 绑定的参数不在【备注参数】分组:{1}", i, key), "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
return;
|
||
}
|
||
|
||
noteBindings.Add(new NotePlaceholderBinding { Index = i, ParamKey = key.Trim() });
|
||
}
|
||
}
|
||
|
||
schema.NoteBindings = noteBindings;
|
||
schema.Normalize();
|
||
|
||
if ((_schemas.Items ?? new List<TemplateSchemaDefinition>())
|
||
.Where(x => x != null)
|
||
.Any(x => !ReferenceEquals(x, schema) && string.Equals(x.TemplateKey, schema.TemplateKey, StringComparison.OrdinalIgnoreCase)))
|
||
{
|
||
MessageBox.Show(this, "保存失败:存在重复的四参数组合。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
TemplateSchemaStore.Save(_schemas);
|
||
MessageBox.Show(this, "已保存。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
ReloadSchemaList();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show(this, $"保存失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
}
|
||
}
|