using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Text; using System.Windows.Forms; namespace AGVSimulator.Forms { /// /// 경로 예측 테스트 진행 상황 로그 표시 폼 /// public partial class ProgressLogForm : Form { private List _logItems; /// /// 취소 요청 여부 /// public bool CancelRequested { get; private set; } public ProgressLogForm() { InitializeComponent(); CancelRequested = false; _logItems = new List(); } /// /// 로그 추가 (PathTestLogItem) /// public void AddLogItem(PathTestLogItem item) { if (InvokeRequired) { Invoke(new Action(AddLogItem), item); return; } _logItems.Add(item); var listItem = new ListViewItem(item.PreviousPosition ?? "-"); listItem.SubItems.Add(item.MotorDirection ?? "-"); listItem.SubItems.Add(item.CurrentPosition ?? "-"); listItem.SubItems.Add(item.TargetPosition ?? "-"); listItem.SubItems.Add(item.DockingPosition ?? "-"); listItem.SubItems.Add(item.Success ? "O" : "X"); listItem.SubItems.Add(item.Message ?? "-"); listItem.SubItems.Add(item.DetailedPath ?? "-"); listItem.SubItems.Add(item.Timestamp.ToString("HH:mm:ss")); // 성공 여부에 따라 색상 설정 if (!item.Success) { listItem.BackColor = Color.LightPink; } var dockpos = item.DockingPosition ?? string.Empty; var targerpos = item.TargetPosition ?? string.Empty; if (dockpos.Equals("충전기") && targerpos.StartsWith("0015")) listItem.ForeColor = Color.DarkViolet; _logListView.Items.Add(listItem); _logListView.EnsureVisible(_logListView.Items.Count - 1); } /// /// 간단한 텍스트 로그 추가 (상태 메시지용) /// public void AppendLog(string message) { var item = new PathTestLogItem { Message = message, Success = true }; AddLogItem(item); } /// /// 상태 메시지 업데이트 /// public void UpdateStatus(string status) { if (InvokeRequired) { Invoke(new Action(UpdateStatus), status); return; } _statusLabel.Text = status; } /// /// 프로그레스바 업데이트 /// public void UpdateProgress(int value, int maximum) { if (InvokeRequired) { Invoke(new Action(UpdateProgress), value, maximum); return; } _progressBar.Maximum = maximum; _progressBar.Value = Math.Min(value, maximum); } /// /// 작업 완료 시 호출 /// public void SetCompleted() { if (InvokeRequired) { Invoke(new Action(SetCompleted)); return; } _cancelButton.Enabled = false; _closeButton.Enabled = true; UpdateStatus("작업 완료"); } /// /// 작업 취소 시 호출 /// public void SetCancelled() { if (InvokeRequired) { Invoke(new Action(SetCancelled)); return; } _cancelButton.Enabled = false; _closeButton.Enabled = true; UpdateStatus("작업 취소됨"); } private void OnCancel_Click(object sender, EventArgs e) { var result = MessageBox.Show( "진행 중인 작업을 취소하시겠습니까?", "취소 확인", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { CancelRequested = true; _cancelButton.Enabled = false; UpdateStatus("취소 요청됨..."); AppendLog("사용자가 취소를 요청했습니다."); } } private void OnSaveCSV_Click(object sender, EventArgs e) { if (_logItems.Count == 0) { MessageBox.Show("저장할 데이터가 없습니다.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } using (var saveDialog = new SaveFileDialog()) { saveDialog.Filter = "CSV 파일 (*.csv)|*.csv|모든 파일 (*.*)|*.*"; saveDialog.DefaultExt = "csv"; saveDialog.FileName = $"경로예측테스트_{DateTime.Now:yyyyMMdd_HHmmss}.csv"; if (saveDialog.ShowDialog() == DialogResult.OK) { try { SaveToCSV(saveDialog.FileName); MessageBox.Show($"CSV 파일이 저장되었습니다.\n{saveDialog.FileName}", "저장 완료", MessageBoxButtons.OK, MessageBoxIcon.Information); var prc = new System.Diagnostics.Process(); prc.StartInfo = new System.Diagnostics.ProcessStartInfo("explorer", saveDialog.FileName); prc.Start(); } catch (Exception ex) { MessageBox.Show($"CSV 저장 중 오류가 발생했습니다:\n{ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } /// /// CSV 파일로 저장 /// private void SaveToCSV(string filePath) { using (var writer = new StreamWriter(filePath, false, Encoding.UTF8)) { // 헤더 작성 writer.WriteLine("이전위치,모터방향,현재위치,대상위치,도킹위치,성공,메세지,상세경로,시간"); // 데이터 작성 foreach (var item in _logItems) { var line = $"{EscapeCSV(item.PreviousPosition)}," + $"{EscapeCSV(item.MotorDirection)}," + $"{EscapeCSV(item.CurrentPosition)}," + $"{EscapeCSV(item.TargetPosition)}," + $"{EscapeCSV(item.DockingPosition)}," + $"{(item.Success ? "O" : "X")}," + $"{EscapeCSV(item.Message)}," + $"{EscapeCSV(item.DetailedPath)}," + $"{item.Timestamp:yyyy-MM-dd HH:mm:ss}"; writer.WriteLine(line); } } } /// /// CSV 셀 데이터 이스케이프 처리 /// private string EscapeCSV(string value) { if (string.IsNullOrEmpty(value)) return ""; // 쉼표, 큰따옴표, 줄바꿈이 있으면 큰따옴표로 감싸고 내부 큰따옴표는 두 개로 if (value.Contains(",") || value.Contains("\"") || value.Contains("\n") || value.Contains("\r")) { return "\"" + value.Replace("\"", "\"\"") + "\""; } return value; } private void OnClose_Click(object sender, EventArgs e) { this.Close(); } } }