From d83478619e60e63468bc189a840110898fdf266a Mon Sep 17 00:00:00 2001 From: Msystech Date: Fri, 21 Aug 2026 08:44:53 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=ED=8E=B8=EC=A7=91?= =?UTF-8?q?=EA=B8=B0=20=E2=80=94=20Enter=20=EA=B0=80=20=EC=83=88=EB=8D=98?= =?UTF-8?q?=20=EA=B2=83=EA=B3=BC=20=EC=A7=80=EB=82=98=EA=B0=84=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EA=B2=B0=EA=B3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Enter 한 번에 변수를 못 넣은 채 저장되고 닫혔다 치환 변수 검색칸에 KeyDown 이 없었고 확인 버튼은 IsDefault 다. 그래서 '차트' 를 치고 Enter 를 누르면 검색도 삽입도 아니라 SQL 이 저장되고 창이 닫힌다. 변수를 하나도 못 넣은 채 편집이 끝나는데, 무엇이 일어났는지 알기도 어렵다 — 창이 사라졌으니 되짚을 화면이 없다. Enter 는 지금 걸러진 목록의 선택 항목을 넣는다(검색으로 하나까지 좁혀진 경우가 대부분이다). ↓ 는 목록으로 이동한다 — 손을 마우스로 옮기지 않고 훑을 수 있어야 한다. 둘 다 e.Handled 로 기본 버튼에 닿지 않게 막는다. ## 검증한 뒤 SQL 을 고쳐도 초록 요약이 그대로 남았다 "검증했다"고 믿고 저장하는데 저장되는 것은 검증하지 않은 문장이다. 검증 시점의 원문을 기억해 두고, 지금 텍스트와 다르면 결과 칸을 흐리게 낮추고 요약 앞에 '(수정됨 — 다시 실행하세요)'를 붙인다. 결과를 지우지는 않는다. 방금 본 컬럼명이 사라지면 그것대로 불편하다 — 배선 필드 칸에 옮겨 적는 중일 수 있다. 유효하지 않다는 사실만 말한다. ## 판정 - 단위 시험 388 · edit-smoke 390건 전건 통과 - --query-popup(자동완성 팝업 진단) 전건 통과 - --dialog-shots 69장 · --modal-check · --maxrect 전건 통과 - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 ## 남은 것 조사에서 함께 나온 것 중 이번에 안 한 것들 — '돌린 SQL 보기'(치환을 마친 문장을 창 안에서 확인), 0행일 때도 컬럼 머리글 남기기, 치환 변수를 안 쓰는 쿼리에 늘 붙는 '구문만 검사' 꼬리표 제거, 인스펙터로 연 편집기에서 컨트롤 변수 칩이 사라지는 것. 전부 근거가 잡혀 있고 다음 회차에 이어서 할 수 있다. Co-Authored-By: Claude Fable 5 --- .../Views/QueryEditorWindow.xaml | 3 + .../Views/QueryEditorWindow.xaml.cs | 64 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/SheetMe.Designer/Views/QueryEditorWindow.xaml b/src/SheetMe.Designer/Views/QueryEditorWindow.xaml index ba8b3db..9ef8c4e 100644 --- a/src/SheetMe.Designer/Views/QueryEditorWindow.xaml +++ b/src/SheetMe.Designer/Views/QueryEditorWindow.xaml @@ -422,8 +422,11 @@ + 마지막으로 돌린 SQL — 진단이 "무엇을 돌렸는가"를 확인할 때 쓴다 private string lastTrialSql = string.Empty; + /// 검증을 돌린 시점의 SQL 원문 — 그 뒤 고쳤는지 판정한다 + private string trialBaseline = string.Empty; + /// 진단 전용 — 검증 실행이 실제로 만든 SQL internal string LastTrialSql => lastTrialSql; @@ -552,6 +555,8 @@ public partial class QueryEditorWindow : Window emptyPlaceholder: "NULL"); var probe = converted.Sql; lastTrialSql = probe; + // 치환 원문을 기준으로 삼는다 — 사용자가 고치는 것은 이쪽이다 + trialBaseline = SqlBox.Text; Mouse.OverrideCursor = Cursors.Wait; SheetMe.Data.Stores.QueryTrialResult result; @@ -736,8 +741,38 @@ public partial class QueryEditorWindow : Window LengthText.Text = $"{text.Length:N0}자 · {CountLines(text)}줄"; UpdateCaretText(); UpdateProblems(text); + RefreshTrialFreshness(); } + /// + /// 검증 결과가 지금 SQL 의 것인지 표시한다. + /// + /// 전에는 검증을 돌린 뒤 SQL 을 고쳐도 초록 요약과 결과 표가 그대로 남았다. + /// "검증했다"고 믿고 저장하는데, 저장되는 것은 검증하지 않은 문장이다. + /// 결과를 지우지는 않는다 — 방금 본 컬럼명이 사라지면 그것대로 불편하다. + /// 흐리게 낮추고 다시 돌리라고 말하는 것으로 충분하다. + /// + private void RefreshTrialFreshness() + { + if (TrialPane is null || TrialPane.Visibility != Visibility.Visible || trialBaseline.Length == 0) + { + return; + } + var stale = !string.Equals(trialBaseline, SqlBox.Text, StringComparison.Ordinal); + TrialPane.Opacity = stale ? 0.5 : 1.0; + if (stale && !TrialSummary.Text.StartsWith(StaleMark, StringComparison.Ordinal)) + { + TrialSummary.Text = StaleMark + TrialSummary.Text; + } + else if (!stale && TrialSummary.Text.StartsWith(StaleMark, StringComparison.Ordinal)) + { + TrialSummary.Text = TrialSummary.Text[StaleMark.Length..]; + } + } + + /// 검증 이후 SQL 이 바뀌었을 때 요약 앞에 붙는 표시 + private const string StaleMark = "(수정됨 — 다시 실행하세요) "; + /// 줄·열 표시 — 오류 메시지의 위치를 찾아갈 때 쓴다 private void UpdateCaretText() { @@ -1047,6 +1082,35 @@ public partial class QueryEditorWindow : Window #endregion #region Methods - Variables + /// + /// 변수 검색칸의 Enter·↓ — 확인 버튼으로 새어 나가는 것을 막는다. + /// + /// 확인 버튼이 IsDefault 라, 이 칸에서 Enter 를 누르면 검색이나 삽입이 아니라 + /// SQL 이 저장되고 창이 닫혔다. '차트' 를 치고 Enter 를 눌렀을 뿐인데 + /// 변수를 하나도 못 넣은 채 편집이 끝난다 — 무엇이 일어났는지도 알기 어렵다. + /// + /// Enter 는 지금 걸러진 목록의 선택 항목을 넣는다(필터가 하나로 좁혀졌을 때가 대부분이다). + /// ↓ 는 목록으로 이동한다 — 손을 마우스로 옮기지 않고 훑을 수 있어야 한다. + /// + private void OnVariableSearchKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + { + InsertSelectedVariable(); + e.Handled = true; // IsDefault 버튼에 도달시키지 않는다 + return; + } + if (e.Key == Key.Down && VariableList.Items.Count > 0) + { + VariableList.Focus(); + if (VariableList.SelectedIndex < 0) + { + VariableList.SelectedIndex = 0; + } + e.Handled = true; + } + } + private void OnVariableSearchChanged(object sender, TextChangedEventArgs e) { SearchPlaceholder.Visibility = VariableSearch.Text.Length == 0 ? Visibility.Visible : Visibility.Collapsed;