열기·저장을 DB 로만 — 'DB에서 열기' 대화상자를 지우고 좌측 목록으로 모은다
<b>먼저 밝힐 것: 내가 "완전 중복"이라고 인용한 판정이 틀렸다.</b> 좌측 목록과 이 대화상자는 같은 조회를 쓰지만(둘 다 ListSheets, WHERE·ORDER BY·상한 동일) 같은 쓸모를 주지 않았다. 지우기 전에 구멍 넷을 좌측에 옮겼다. <b>① 저장·등록 뒤 재조회 — 가장 컸다.</b> 좌측 목록은 기동 1회와 검색 버튼으로만 채워졌고 저장 뒤 갱신이 없었다. 즉 <b>방금 저장한 서식이 목록에 안 떴다</b>. 대화상자는 열 때마다 재조회해서 그 구멍을 덮고 있었다. 그것을 안 메우고 창만 지웠으면, DB 전용으로 바꾼 직후 신규 서식을 저장한 사용자가 그 서식을 다시 찾지 못했을 것이다. <b>② 서식명 툴팁</b> — 좌측은 폭이 148px 남짓(자물쇠 붙으면 134, 패널 최소폭이면 80)이라 긴 이름이 잘리는데 전문을 볼 방법이 없었다. 대화상자는 열이 300px 에 드래그로 늘릴 수 있었다. <b>③ '디자인 없음'과 '서식생성기 사용 꺼짐'</b> 이 좌측에서는 둘 다 같은 회색+Opacity 0.6 이라 화면만 보고 구분할 수 없었다. 툴팁으로 갈랐다. <b>④ Enter 로 열기</b> — 좌측은 더블클릭 전용이라 키보드로 서식을 열 수 없었다. 대화상자에는 [열기] 버튼이 있어 그 구멍이 가려져 있었다. 검색칸에서 ↓ 로 목록에 내려가는 길도 붙였다. 그 다음 지웠다: SheetOpenDialogView(680×560), OpenFromDbCommand, 파일 메뉴의 파일 열기· 다른 이름으로 저장·DB에서 열기, 빈 화면의 '파일 열기' 버튼, Ctrl+Shift+S. Ctrl+O 는 이제 서식 목록으로 간다 — 전에는 OS 파일 대화상자였고, 운영 서식은 전부 DB 에 있다. <b>SaveMode 기본값은 바꾸지 않았다.</b> 조사해 보니 그 규칙은 실재하고 문서·코드 4곳에 있다 — docs/DEPLOYMENT.md:56 은 "이 기본값을 바꾸지 말 것"이라고 명시한다. 배포된 ini 의 CurrentServer 가 운영 병원 DB 를 가리켜서, 명시적으로 켠 단말에서만 운영 테이블(E_SdgMst/E_SctMst)에 쓰게 하려는 장치다. ini 는 SaveMode 를 담지 않으므로 이 규칙이 병원 단말의 유일한 방어선이다. UI 진입점만 없애고 규칙은 그대로 둔다. 파일 저장·열기 <b>코드</b>도 남긴다 — 접속 없이 도는 --render-smoke 와 --edit-smoke 직렬화 왕복이 그 경로를 쓴다. 대신 화면이 상태를 말하게 했다 — SaveMode=File 단말에서는 저장 메뉴·버튼이 비활성이다. 전에는 항상 활성이고 누른 뒤에야 경고가 떴다. <b>종료 가드를 고쳤다 — 앱이 안 닫히는 상태를 없앤다.</b> 전에는 저장 실패가 곧 종료 중단이었다. 파일 폴백이 있을 때는 드문 분기였지만 저장이 DB 로만 가면 흔한 경로가 된다 — SaveMode=File 단말이나 접속 불가에서 <b>수정한 탭을 가진 사용자가 앱을 닫을 수 없게</b> 된다. 이제 '버리고 종료'를 묻는다. 게이트 대체물도 함께 옮겼다: --dialog-shots 의 01-sheet-open 을 지우면 서식명 잘림을 잡을 자리가 통째로 사라지므로, 좌측 목록에 표본을 넣은 01-sheet-list 샷으로 바꿨다 (진단 모드는 Loaded 를 안 돌려 목록이 비므로 표본을 직접 주입한다). 검사한 글자 2,531 → 2,649개. 게이트: 테스트 291/291, --edit-smoke 0실패, --dialog-shots 62장 FAIL 0 대조군 4/4, --modal-check 0실패, --cleartype 11/11, --maxrect 0실패, --scale-budget 5/5, 빌드 경고 0, --db-smoke 1271건 diff 0, --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 동일. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2f5c9bf82d
commit
a386c5504b
@@ -26,9 +26,8 @@
|
||||
-->
|
||||
<Window.InputBindings>
|
||||
<KeyBinding Key="N" Modifiers="Control" Command="{Binding NewFileCommand}"/>
|
||||
<KeyBinding Key="O" Modifiers="Control" Command="{Binding OpenFileCommand}"/>
|
||||
<!-- Ctrl+O 는 코드비하인드에서 서식 목록으로 보낸다(파일 대화상자가 아니다) -->
|
||||
<KeyBinding Key="S" Modifiers="Control" Command="{Binding SaveFileCommand}"/>
|
||||
<KeyBinding Key="S" Modifiers="Control+Shift" Command="{Binding SaveAsFileCommand}"/>
|
||||
<KeyBinding Key="P" Modifiers="Control" Command="{Binding PrintCommand}"/>
|
||||
<KeyBinding Key="W" Modifiers="Control" Command="{Binding CloseDocumentCommand}"/>
|
||||
<!-- F4 로 인스펙터 첫 칸으로 들어간다. 전에는 인스펙터로 포커스를 보내는 키가 저장소에
|
||||
@@ -155,18 +154,21 @@
|
||||
Content="{Binding Source=chevron-down, Converter={StaticResource IconName}, ConverterParameter=11}"/>
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
<!--
|
||||
파일 경로를 메뉴에서 뺐다 — 열기·저장은 DB 만 쓴다.
|
||||
운영 서식 1,271건이 전부 DB 에 있고, 파일로 저장한 XML 은 EMR 이 읽지 않는다.
|
||||
'DB에서 열기' 대화상자도 지웠다 — 좌측 '서식 목록' 탭이 같은 조회를 상시로 한다
|
||||
(그 창이 덮고 있던 구멍 넷을 좌측에 먼저 옮겼다: 저장 후 재조회 · 서식명 툴팁 ·
|
||||
디자인 없음/사용 꺼짐 구분 · Enter 로 열기).
|
||||
파일 저장·열기 코드는 남아 있다 — 접속 없이 도는 진단(render-smoke,
|
||||
edit-smoke 직렬화 왕복)이 그 경로를 쓴다. UI 진입점만 없앤 것이다.
|
||||
-->
|
||||
<MenuItem Header="파일(_F)">
|
||||
<MenuItem Header="새 서식(_N)" Command="{Binding NewFileCommand}" InputGestureText="Ctrl+N"/>
|
||||
<MenuItem Header="열기(_O)..." Command="{Binding OpenFileCommand}" InputGestureText="Ctrl+O"/>
|
||||
<MenuItem Header="서식 목록에서 열기(_O)" Click="OnOpenFromListClick" InputGestureText="Ctrl+O"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="저장(_S)" Command="{Binding SaveFileCommand}" InputGestureText="Ctrl+S"/>
|
||||
<MenuItem Header="다른 이름으로 저장(_A)..." Command="{Binding SaveAsFileCommand}" InputGestureText="Ctrl+Shift+S"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="DB에서 열기(_D)..." Command="{Binding OpenFromDbCommand}"/>
|
||||
<MenuItem Header="DB에 저장(_B)..." Command="{Binding SaveToDbCommand}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="JSON 가져오기(_I)..." Command="{Binding ImportJsonCommand}"/>
|
||||
<MenuItem Header="JSON 내보내기(_E)..." Command="{Binding ExportJsonCommand}"/>
|
||||
<MenuItem Header="저장(_S)" Command="{Binding SaveToDbCommand}" InputGestureText="Ctrl+S"
|
||||
IsEnabled="{Binding CanSaveToDb}"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="미리보기(_V)..." Command="{Binding PreviewCommand}"/>
|
||||
<MenuItem Header="인쇄(_P)..." Command="{Binding PrintCommand}" InputGestureText="Ctrl+P"/>
|
||||
@@ -348,6 +350,7 @@
|
||||
<!-- 자리표시자는 TextBox 위에 겹친 TextBlock — Text 가 비었을 때만 보인다 -->
|
||||
<Grid>
|
||||
<TextBox x:Name="SheetSearchBox"
|
||||
PreviewKeyDown="OnSheetSearchKeyDown"
|
||||
Text="{Binding SheetSearchKeyword, UpdateSourceTrigger=PropertyChanged}">
|
||||
<TextBox.InputBindings>
|
||||
<KeyBinding Key="Enter" Command="{Binding SearchSheetsCommand}"/>
|
||||
@@ -384,7 +387,8 @@
|
||||
VirtualizingPanel.VirtualizationMode="Recycling"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
MouseDoubleClick="OnSheetListDoubleClick"
|
||||
ToolTip="분류 머리글을 눌러 펼치고, 서식을 더블클릭해 엽니다">
|
||||
PreviewKeyDown="OnSheetListKeyDown"
|
||||
ToolTip="분류 머리글을 눌러 펼치고, 서식을 더블클릭하거나 Enter 로 엽니다">
|
||||
<ListBox.GroupStyle>
|
||||
<GroupStyle>
|
||||
<GroupStyle.ContainerStyle>
|
||||
@@ -464,17 +468,28 @@
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<TextBlock Text="{Binding Name}" FontSize="12" TextTrimming="CharacterEllipsis">
|
||||
<!--
|
||||
서식명 툴팁 — 폭이 148px 남짓(자물쇠가 붙으면 134, 패널 최소폭이면 80)이라
|
||||
긴 이름은 말줄임표로 잘리는데 전문을 볼 방법이 없었다.
|
||||
DB에서 열기 대화상자는 열을 300px 로 주고 드래그로 늘릴 수 있었다 —
|
||||
그 창을 지우기 전에 여기로 옮긴다.
|
||||
'디자인 없음'과 '서식생성기 사용 꺼짐'을 툴팁으로 갈라 준다.
|
||||
전에는 둘 다 같은 회색+0.6 이라 화면만 보고는 구분할 수 없었다.
|
||||
-->
|
||||
<TextBlock Text="{Binding Name}" FontSize="12" TextTrimming="CharacterEllipsis"
|
||||
ToolTip="{Binding Name}">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding HasDesign}" Value="False">
|
||||
<Setter Property="Foreground" Value="{DynamicResource B.Muted}"/>
|
||||
<Setter Property="Opacity" Value="0.6"/>
|
||||
<Setter Property="ToolTip" Value="아직 디자인이 없는 서식입니다 — 열면 빈 종이로 시작합니다"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding DesignAllowed}" Value="False">
|
||||
<Setter Property="Foreground" Value="{DynamicResource B.Muted}"/>
|
||||
<Setter Property="Opacity" Value="0.6"/>
|
||||
<Setter Property="ToolTip" Value="기록지 정보에서 서식생성기 사용이 꺼져 있습니다 — 열 수 없습니다"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
@@ -729,9 +744,8 @@
|
||||
Text="새 서식을 만들거나, 왼쪽 서식 목록에서 기존 서식을 두 번 눌러 엽니다."/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button Content="새 서식" Command="{Binding NewFileCommand}" Padding="16,7" Margin="0,0,8,0"/>
|
||||
<Button Content="DB에서 열기" Command="{Binding OpenFromDbCommand}" Padding="16,7"
|
||||
<Button Content="서식 목록에서 열기" Click="OnOpenFromListClick" Padding="16,7"
|
||||
IsEnabled="{Binding CanUseDb}"/>
|
||||
<Button Content="파일 열기" Command="{Binding OpenFileCommand}" Padding="16,7" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
@@ -161,11 +161,72 @@ public partial class MainView : Window
|
||||
/// </summary>
|
||||
private void OnWindowPreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key != System.Windows.Input.Key.F4)
|
||||
if (e.Key == System.Windows.Input.Key.F4)
|
||||
{
|
||||
Inspector.FocusFirstRow();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
// Ctrl+O — 서식 목록으로. 전에는 OS 파일 대화상자로 갔다.
|
||||
// 손이 먼저 가는 키인데 디스크로 가고, 운영 서식 1,271건은 전부 DB 에 있다.
|
||||
if (e.Key == System.Windows.Input.Key.O
|
||||
&& System.Windows.Input.Keyboard.Modifiers == System.Windows.Input.ModifierKeys.Control)
|
||||
{
|
||||
FocusSheetList();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>파일 메뉴·빈 화면 버튼에서 서식 목록으로 보낸다</summary>
|
||||
private void OnOpenFromListClick(object sender, RoutedEventArgs e) => FocusSheetList();
|
||||
|
||||
/// <summary>서식 목록 탭으로 옮기고 검색칸에 커서를 둔다</summary>
|
||||
private void FocusSheetList()
|
||||
{
|
||||
if (DataContext is MainViewModel viewModel)
|
||||
{
|
||||
viewModel.SelectedLeftTabIndex = 0;
|
||||
}
|
||||
// 탭이 방금 바뀌어 아직 시각 트리가 없다 — 레이아웃이 한 번 돈 뒤에 잡는다
|
||||
// (LayerPanelView 의 검색칸 포커스와 같은 규범).
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
SheetSearchBox.Focus();
|
||||
System.Windows.Input.Keyboard.Focus(SheetSearchBox);
|
||||
SheetSearchBox.SelectAll();
|
||||
}), System.Windows.Threading.DispatcherPriority.Input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 서식 목록 키 처리 — Enter 로 연다.
|
||||
///
|
||||
/// 전에는 <b>더블클릭 전용</b>이라 키보드로는 서식을 열 수 없었다.
|
||||
/// 'DB에서 열기' 대화상자에는 [열기] 버튼이 있어서 그 구멍이 가려져 있었다 — 그 창을 지우기 전에 메운다.
|
||||
/// </summary>
|
||||
private void OnSheetListKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key != System.Windows.Input.Key.Enter || DataContext is not MainViewModel viewModel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Inspector.FocusFirstRow();
|
||||
viewModel.OpenSheetFromList(SheetListBox.SelectedItem as SheetSummary);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>검색칸에서 ↓ 를 누르면 목록으로 내려간다 — 검색과 선택 사이에 마우스를 두지 않는다</summary>
|
||||
private void OnSheetSearchKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.Key != System.Windows.Input.Key.Down || SheetListBox.Items.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SheetListBox.SelectedIndex = Math.Max(0, SheetListBox.SelectedIndex);
|
||||
SheetListBox.Focus();
|
||||
if (SheetListBox.ItemContainerGenerator.ContainerFromIndex(SheetListBox.SelectedIndex)
|
||||
is System.Windows.Controls.ListBoxItem item)
|
||||
{
|
||||
item.Focus();
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
<Window x:Class="SheetMe.Designer.Views.SheetOpenDialogView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="DB에서 서식 열기" Width="680" Height="560"
|
||||
WindowStartupLocation="CenterOwner" ShowInTaskbar="False"
|
||||
Style="{StaticResource ThemedWindow}">
|
||||
<DockPanel Margin="12">
|
||||
<DockPanel DockPanel.Dock="Top">
|
||||
<Button DockPanel.Dock="Right" Content="검색" Padding="14,4" Margin="6,0,0,0" Click="OnSearch" IsDefault="True"/>
|
||||
<TextBox x:Name="SearchBox" Padding="4,3" VerticalContentAlignment="Center"/>
|
||||
</DockPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0">
|
||||
<TextBlock x:Name="CountText" VerticalAlignment="Center" Margin="0,0,12,0" Foreground="{DynamicResource B.Muted}"/>
|
||||
<Button Content="열기" Padding="18,5" Click="OnOpen"/>
|
||||
<Button Content="취소" Padding="18,5" Margin="8,0,0,0" IsCancel="True"/>
|
||||
</StackPanel>
|
||||
|
||||
<ListView x:Name="SheetList" Margin="0,10,0,0" MouseDoubleClick="OnOpen">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="서식코드" Width="100" DisplayMemberBinding="{Binding ShtCod}"/>
|
||||
<!-- 좌측 패널은 분류로 묶어 보여주지만 이 대화상자는 그리드다 — 같은 정보를 열로 준다 -->
|
||||
<GridViewColumn Header="분류" Width="120" DisplayMemberBinding="{Binding ClassName}"/>
|
||||
<GridViewColumn Header="서식명" Width="300" DisplayMemberBinding="{Binding Name}"/>
|
||||
<GridViewColumn Header="디자인" Width="70">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="있음" Foreground="{DynamicResource B.Success}"
|
||||
Visibility="{Binding HasDesign, Converter={StaticResource BoolToVisibility}}"/>
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
@@ -1,64 +0,0 @@
|
||||
using System.Windows;
|
||||
using SheetMe.Data.Stores;
|
||||
|
||||
using SheetMe.Designer.Services;
|
||||
|
||||
namespace SheetMe.Designer.Views;
|
||||
|
||||
/// <summary>
|
||||
/// DB 서식 열기 대화상자 — 검색/목록/선택.
|
||||
/// 검색 실행 콜백을 주입받는 얇은 대화상자(모달 결과 = SelectedSheet).
|
||||
/// </summary>
|
||||
public partial class SheetOpenDialogView : Window
|
||||
{
|
||||
#region Member Fields
|
||||
private readonly Func<string?, List<SheetSummary>> search;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>선택된 서식 — 확인 시 채워짐</summary>
|
||||
public SheetSummary? SelectedSheet { get; private set; }
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public SheetOpenDialogView(Func<string?, List<SheetSummary>> search)
|
||||
{
|
||||
this.search = search;
|
||||
InitializeComponent();
|
||||
Loaded += (_, _) => RunSearch();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
private void OnSearch(object sender, RoutedEventArgs e) => RunSearch();
|
||||
|
||||
private void RunSearch()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = search(SearchBox.Text);
|
||||
SheetList.ItemsSource = result;
|
||||
CountText.Text = $"{result.Count}건";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DialogService.Notify(DialogKind.Error, "오류", "서식 목록 조회 중 오류가 발생했습니다.", ex.Message, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOpen(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (SheetList.SelectedItem is not SheetSummary selected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!selected.HasDesign)
|
||||
{
|
||||
DialogService.Notify(DialogKind.Warning, "열기", "선택한 서식에는 저장된 디자인이 없습니다.", owner: this);
|
||||
return;
|
||||
}
|
||||
SelectedSheet = selected;
|
||||
DialogResult = true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user