From 4fa38a7b9eb9d3141de5f6c34c459803c2eaa122 Mon Sep 17 00:00:00 2001 From: lacvet Date: Fri, 3 Apr 2026 21:43:10 +0900 Subject: [PATCH] =?UTF-8?q?[Phase52]=20PreviewWindow.xaml.cs=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20=E2=80=94=20Content.cs=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PreviewWindow.xaml.cs: 505 → 317줄 (P/Invoke + 싱글턴 + 탭 관리 유지) - PreviewWindow.Content.cs (신규): 콘텐츠 로드(LoadContent/LoadCsvContent/ParseCsvLine) + 타이틀바 핸들러 9개 (170줄) 빌드: 경고 0, 오류 0 Co-Authored-By: Claude Sonnet 4.6 --- src/AxCopilot/Views/PreviewWindow.Content.cs | 203 +++++++++++++++++++ src/AxCopilot/Views/PreviewWindow.xaml.cs | 188 ----------------- 2 files changed, 203 insertions(+), 188 deletions(-) create mode 100644 src/AxCopilot/Views/PreviewWindow.Content.cs diff --git a/src/AxCopilot/Views/PreviewWindow.Content.cs b/src/AxCopilot/Views/PreviewWindow.Content.cs new file mode 100644 index 0000000..c74b7d2 --- /dev/null +++ b/src/AxCopilot/Views/PreviewWindow.Content.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; + +namespace AxCopilot.Views; + +public partial class PreviewWindow +{ + // ─── 콘텐츠 로드 + 타이틀 바 ───────────────────────────────────────────── + + private async void LoadContent(string filePath) + { + var ext = Path.GetExtension(filePath).ToLowerInvariant(); + + PreviewBrowser.Visibility = Visibility.Collapsed; + TextScroll.Visibility = Visibility.Collapsed; + DataGridContent.Visibility = Visibility.Collapsed; + EmptyMessage.Visibility = Visibility.Collapsed; + + if (!File.Exists(filePath)) + { + EmptyMessage.Text = "파일을 찾을 수 없습니다"; + EmptyMessage.Visibility = Visibility.Visible; + return; + } + + try + { + switch (ext) + { + case ".html": + case ".htm": + if (!_webViewInitialized) return; // OnLoaded에서 재시도 + PreviewBrowser.Source = new Uri(filePath); + PreviewBrowser.Visibility = Visibility.Visible; + break; + + case ".csv": + LoadCsvContent(filePath); + DataGridContent.Visibility = Visibility.Visible; + break; + + case ".md": + if (!_webViewInitialized) return; + var mdText = File.ReadAllText(filePath); + if (mdText.Length > 50000) mdText = mdText[..50000]; + var mdHtml = Services.Agent.TemplateService.RenderMarkdownToHtml( + mdText, _selectedMood ?? "modern"); + PreviewBrowser.NavigateToString(mdHtml); + PreviewBrowser.Visibility = Visibility.Visible; + break; + + case ".txt": + case ".json": + case ".xml": + case ".log": + var text = File.ReadAllText(filePath); + if (text.Length > 50000) text = text[..50000] + "\n\n... (이후 생략)"; + TextContent.Text = text; + TextScroll.Visibility = Visibility.Visible; + break; + + default: + EmptyMessage.Text = "미리보기할 수 없는 파일 형식입니다"; + EmptyMessage.Visibility = Visibility.Visible; + break; + } + } + catch (Exception ex) + { + TextContent.Text = $"미리보기 오류: {ex.Message}"; + TextScroll.Visibility = Visibility.Visible; + } + + await System.Threading.Tasks.Task.CompletedTask; // async 경고 방지 + } + + private void LoadCsvContent(string filePath) + { + var lines = File.ReadAllLines(filePath); + if (lines.Length == 0) return; + + var dt = new DataTable(); + var headers = ParseCsvLine(lines[0]); + foreach (var h in headers) + dt.Columns.Add(h); + + var maxRows = Math.Min(lines.Length, 501); + for (int i = 1; i < maxRows; i++) + { + var vals = ParseCsvLine(lines[i]); + var row = dt.NewRow(); + for (int j = 0; j < Math.Min(vals.Length, headers.Length); j++) + row[j] = vals[j]; + dt.Rows.Add(row); + } + + DataGridContent.ItemsSource = dt.DefaultView; + } + + private static string[] ParseCsvLine(string line) + { + var fields = new List(); + var current = new StringBuilder(); + bool inQuotes = false; + + for (int i = 0; i < line.Length; i++) + { + char c = line[i]; + if (inQuotes) + { + if (c == '"' && i + 1 < line.Length && line[i + 1] == '"') + { current.Append('"'); i++; } + else if (c == '"') inQuotes = false; + else current.Append(c); + } + else + { + if (c == '"') inQuotes = true; + else if (c == ',') { fields.Add(current.ToString()); current.Clear(); } + else current.Append(c); + } + } + fields.Add(current.ToString()); + return fields.ToArray(); + } + + // ─── 타이틀 바 ────────────────────────────────────────────── + + private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + if (e.ClickCount == 2) { ToggleMaximize(); return; } + DragMove(); + } + + private void OpenExternalBtn_Click(object sender, MouseButtonEventArgs e) + { + e.Handled = true; + if (_activeTab == null || !File.Exists(_activeTab)) return; + try + { + System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo + { + FileName = _activeTab, + UseShellExecute = true, + }); + } + catch (Exception ex) + { + Services.LogService.Warn($"외부 프로그램 열기 실패: {ex.Message}"); + } + } + + private void MinBtn_Click(object sender, MouseButtonEventArgs e) + { + e.Handled = true; + WindowState = WindowState.Minimized; + } + + private void MaxBtn_Click(object sender, MouseButtonEventArgs e) + { + e.Handled = true; + ToggleMaximize(); + } + + private void CloseBtn_Click(object sender, MouseButtonEventArgs e) + { + e.Handled = true; + Close(); + } + + private void ToggleMaximize() + { + WindowState = WindowState == WindowState.Maximized + ? WindowState.Normal + : WindowState.Maximized; + } + + private void TitleBtn_Enter(object sender, MouseEventArgs e) + { + if (sender is Border b) + b.Background = TryFindResource("ItemHoverBackground") as Brush + ?? new SolidColorBrush(Color.FromArgb(0x18, 0xFF, 0xFF, 0xFF)); + } + + private void CloseBtnEnter(object sender, MouseEventArgs e) + { + if (sender is Border b) + b.Background = new SolidColorBrush(Color.FromArgb(0x44, 0xFF, 0x40, 0x40)); + } + + private void TitleBtn_Leave(object sender, MouseEventArgs e) + { + if (sender is Border b) + b.Background = Brushes.Transparent; + } +} diff --git a/src/AxCopilot/Views/PreviewWindow.xaml.cs b/src/AxCopilot/Views/PreviewWindow.xaml.cs index 384de58..a002804 100644 --- a/src/AxCopilot/Views/PreviewWindow.xaml.cs +++ b/src/AxCopilot/Views/PreviewWindow.xaml.cs @@ -314,192 +314,4 @@ public partial class PreviewWindow : Window TitleText.Text = $"미리보기 — {Path.GetFileName(_activeTab)}"; } - // ─── 콘텐츠 로드 ──────────────────────────────────────────── - - private async void LoadContent(string filePath) - { - var ext = Path.GetExtension(filePath).ToLowerInvariant(); - - PreviewBrowser.Visibility = Visibility.Collapsed; - TextScroll.Visibility = Visibility.Collapsed; - DataGridContent.Visibility = Visibility.Collapsed; - EmptyMessage.Visibility = Visibility.Collapsed; - - if (!File.Exists(filePath)) - { - EmptyMessage.Text = "파일을 찾을 수 없습니다"; - EmptyMessage.Visibility = Visibility.Visible; - return; - } - - try - { - switch (ext) - { - case ".html": - case ".htm": - if (!_webViewInitialized) return; // OnLoaded에서 재시도 - PreviewBrowser.Source = new Uri(filePath); - PreviewBrowser.Visibility = Visibility.Visible; - break; - - case ".csv": - LoadCsvContent(filePath); - DataGridContent.Visibility = Visibility.Visible; - break; - - case ".md": - if (!_webViewInitialized) return; - var mdText = File.ReadAllText(filePath); - if (mdText.Length > 50000) mdText = mdText[..50000]; - var mdHtml = Services.Agent.TemplateService.RenderMarkdownToHtml( - mdText, _selectedMood ?? "modern"); - PreviewBrowser.NavigateToString(mdHtml); - PreviewBrowser.Visibility = Visibility.Visible; - break; - - case ".txt": - case ".json": - case ".xml": - case ".log": - var text = File.ReadAllText(filePath); - if (text.Length > 50000) text = text[..50000] + "\n\n... (이후 생략)"; - TextContent.Text = text; - TextScroll.Visibility = Visibility.Visible; - break; - - default: - EmptyMessage.Text = "미리보기할 수 없는 파일 형식입니다"; - EmptyMessage.Visibility = Visibility.Visible; - break; - } - } - catch (Exception ex) - { - TextContent.Text = $"미리보기 오류: {ex.Message}"; - TextScroll.Visibility = Visibility.Visible; - } - - await System.Threading.Tasks.Task.CompletedTask; // async 경고 방지 - } - - private void LoadCsvContent(string filePath) - { - var lines = File.ReadAllLines(filePath); - if (lines.Length == 0) return; - - var dt = new DataTable(); - var headers = ParseCsvLine(lines[0]); - foreach (var h in headers) - dt.Columns.Add(h); - - var maxRows = Math.Min(lines.Length, 501); - for (int i = 1; i < maxRows; i++) - { - var vals = ParseCsvLine(lines[i]); - var row = dt.NewRow(); - for (int j = 0; j < Math.Min(vals.Length, headers.Length); j++) - row[j] = vals[j]; - dt.Rows.Add(row); - } - - DataGridContent.ItemsSource = dt.DefaultView; - } - - private static string[] ParseCsvLine(string line) - { - var fields = new List(); - var current = new StringBuilder(); - bool inQuotes = false; - - for (int i = 0; i < line.Length; i++) - { - char c = line[i]; - if (inQuotes) - { - if (c == '"' && i + 1 < line.Length && line[i + 1] == '"') - { current.Append('"'); i++; } - else if (c == '"') inQuotes = false; - else current.Append(c); - } - else - { - if (c == '"') inQuotes = true; - else if (c == ',') { fields.Add(current.ToString()); current.Clear(); } - else current.Append(c); - } - } - fields.Add(current.ToString()); - return fields.ToArray(); - } - - // ─── 타이틀 바 ────────────────────────────────────────────── - - private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - if (e.ClickCount == 2) { ToggleMaximize(); return; } - DragMove(); - } - - private void OpenExternalBtn_Click(object sender, MouseButtonEventArgs e) - { - e.Handled = true; - if (_activeTab == null || !File.Exists(_activeTab)) return; - try - { - System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo - { - FileName = _activeTab, - UseShellExecute = true, - }); - } - catch (Exception ex) - { - Services.LogService.Warn($"외부 프로그램 열기 실패: {ex.Message}"); - } - } - - private void MinBtn_Click(object sender, MouseButtonEventArgs e) - { - e.Handled = true; - WindowState = WindowState.Minimized; - } - - private void MaxBtn_Click(object sender, MouseButtonEventArgs e) - { - e.Handled = true; - ToggleMaximize(); - } - - private void CloseBtn_Click(object sender, MouseButtonEventArgs e) - { - e.Handled = true; - Close(); - } - - private void ToggleMaximize() - { - WindowState = WindowState == WindowState.Maximized - ? WindowState.Normal - : WindowState.Maximized; - } - - private void TitleBtn_Enter(object sender, MouseEventArgs e) - { - if (sender is Border b) - b.Background = TryFindResource("ItemHoverBackground") as Brush - ?? new SolidColorBrush(Color.FromArgb(0x18, 0xFF, 0xFF, 0xFF)); - } - - private void CloseBtnEnter(object sender, MouseEventArgs e) - { - if (sender is Border b) - b.Background = new SolidColorBrush(Color.FromArgb(0x44, 0xFF, 0x40, 0x40)); - } - - private void TitleBtn_Leave(object sender, MouseEventArgs e) - { - if (sender is Border b) - b.Background = Brushes.Transparent; - } }