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;