Commit Graph
56 Commits
Author SHA1 Message Date
MsystechandClaude Fable 5 5c97bf1440 파일 계열 키바인딩 배선 + 미저장 종료 가드
메뉴에는 Ctrl+N/O/S/P 가 표시되지만 Window.InputBindings 가 아예 없어 실제로는 동작하지
않는 잘못된 어포던스였다. 그리고 MainView 에 Closing 핸들러가 없어 타이틀바 X·Alt+F4·
파일 종료 어느 경로로도 미저장 확인이 뜨지 않아, 미저장 다중 문서가 확인 없이 버려졌다.

- UndoService 에 savedDepth 기반 IsDirty/MarkSaved 추가. 기존 CanUndo 는 저장해도 영구
  더티라 종료마다 무의미한 확인이 떠서 가드가 존재 가치를 잃는다. Undo/Redo 로 저장 지점
  깊이에 되돌아오면 자동 clean 이 되고, 저장 지점보다 얕은 상태에서 새 편집이 들어오면
  (분기) 되돌아갈 수 없으므로 savedDepth=-1 로 영구 더티 처리한다. 용량 트림 시에도 보정.
- OnSaveFile/OnSaveToDb 를 bool 반환으로. 기존 void 는 저장 대화상자 취소를 감지할 수 없어
  종료 가드에서 저장 선택지를 줄 수 없었다. 성공 시 MarkSaved() 호출.
- ConfirmCloseAll() — 문서별 YesNoCancel 확인. 확인 직전 해당 문서를 활성 탭으로 올려
  어느 문서를 묻는지 보이게 한다(저장 경로가 CurrentDesigner 대상이라 전환이 필수다).
  과거 버전 열람 탭은 저장하면 활성 디자인을 과거 내용으로 덮으므로 저장 선택지를 주지 않는다.
- 종료 경로 두 개를 모두 막는다: MainView.Closing 에서 e.Cancel, 그리고 파일 종료의
  Application.Shutdown() 은 e.Cancel 을 무시하므로 VM 이 먼저 확인하고 IsShuttingDown 을
  세워 Closing 이 재질문하지 않게 한다.
- Window.InputBindings 에는 파일/앱 계열만(Ctrl+N/O/S/Shift+S/P/W). 편집 계열은
  CanvasKeyboardBehavior 가 계속 담당한다 — Ctrl+Z/C/V/X/A/D/G 를 창에 올리면 인스펙터·
  검색 상자 TextBox 의 표준 편집 키와 충돌하고 Spread 붙여넣기 가드도 우회할 여지가 생긴다.
- 저장 진입부에서 포커스가 머문 TextBox 의 BindingExpression.UpdateSource() 호출.
  인스펙터 바인딩이 UpdateSourceTrigger=LostFocus 라 값을 고치다 바로 Ctrl+S 를 누르면
  커밋되지 않은 채 저장되어 조용히 유실됐다.

검증: edit-smoke 에 더티 추적 8건 추가(초기 clean / 편집 후 dirty / MarkSaved 후 clean /
저장 지점 Undo 복귀 시 clean / 더 되돌리면 dirty / Redo 복귀 시 clean / 분기 후 영구 dirty).
1단계 전체 회귀 통과 — 테스트 70/70, edit-smoke 실패 0, 왕복 1,271건 diff 0/예외 0,
db-save-smoke 제자리 갱신(P163)·버저닝(S999) 양쪽, db-word-smoke 통과.

주의: 키바인딩과 종료 대화상자의 실 UI 조작 확인은 아직 하지 않았다(무인 검증 불가 구간).
병행 운영 전 수동 확인 항목으로 남긴다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 18:24:10 +09:00
MsystechandClaude Fable 5 3dcac31a5b 표(Spread) 이름 변경·복제 차단 — 레거시에서 서식이 통째로 안 열리는 경로 봉쇄
Spread 격자는 E_SpdMst 에서 SpdShtCod+SpdName 으로만 조회되는데 SheetMe 에는 그 행을
만드는 경로가 없다(SELECT 3곳뿐). 이름이 바뀌거나 복제본이 생기면 조회 0건 →
Spread.vb:922-955 가 0바이트 파일을 만들고 FpSpread.Open 이 예외 →
bzDesignSheetLoader.LoadObject 에는 try/catch 가 없어 재귀를 타고 :425-427 로 전파되어
Return Nothing. 즉 표가 사라지는 수준이 아니라 그 서식이 아예 열리지 않는다.

- 이름 변경: 완전 금지(RenameControl 진입부 가드). 기존 중복 이름 거부 경로도 Rebuild() 를
  호출하도록 통일 — 지금까지는 return 만 해서 편집 상자에 잘못된 이름이 남아 있었다.
- 붙여넣기: 표만 제외하고 나머지는 통과 + 제외 건수 알림. 전체 거부는 라벨 20개에 표 1개가
  섞인 복사 같은 정상 작업까지 막는다. 조기 반환을 Undo.Snapshot() 앞에 둬 빈 스텝이
  쌓이지 않게 했다.
- 가드는 커맨드 람다가 아니라 Paste() 메서드 본문에 — CanvasKeyboardBehavior 가 커맨드를
  우회해 designer.CopySelection()/Paste() 를 직접 호출하므로 키보드 경로도 함께 막힌다.
- 잘라내기는 별도 가드 불필요(표 삭제 자체는 안전), 복제는 Copy+Paste 라 자동 차단.
- 판정은 VM 형이 아니라 모델 Type 문자열 + 자식 재귀 — 클립보드가 ControlElement 이고
  컨테이너에 중첩된 표도 잡아야 한다.

검증: edit-smoke 에 판정·필터 순수 로직 8건 추가(FilterPastable 을 알림과 분리해 무인
검증이 가능하도록 함). 실 UI 프로브로 P062(Spread 실물 보유)를 열어 실제 입력으로 이름
변경을 시도 → 가드 대화상자 발동, 레이어·인스펙터 헤더 모두 Spread1 유지, 확인 후 편집
상자 원복까지 확인.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 17:45:53 +09:00
MsystechandClaude Fable 5 d0538ef95a 쿼리 치환 변수를 클래스 전체 이름 형식으로 교체 (치환 실패 → ORA 오류 수정)
레거시 런타임 bzDesignSheetLoader.ConvertQuery 는 토큰 접두어를
PatientInfo/SheetInfo/WorkInfo 의 GetType.FullName 과 Select Case 완전일치로 비교한다.
기존 목록은 <<PatientInfo.ChtNum>> 축약형이라 어떤 토큰도 치환되지 않고 <<...>> 가
SQL 에 리터럴로 남아 ORA 구문오류를 냈다 — 그 데이터소스를 참조하는 컨트롤이 전부 공백이 되는
조용한 실패다. 기존 서식의 쿼리는 원문 보존이라 영향 없고, 신규 작성분만 해당된다.

접두어는 ucLoadSheetBase.vb:7619-7631 이 형을 고정한다:
  PatientInfo/WorkInfo → M.CMM.HISOperatingInfo.*
  SheetInfo            → M.EMR.SheetLoadOperatingInfo.bzSheetInfo

기존 20개 중 8개는 접두어뿐 아니라 속성명 자체가 실존하지 않았다(리플렉션 null):
PatientInfo.OdrNum/OdrSeq, SheetInfo.EmrGbn/PatTyp/OdrNum/OdrSeq, WorkInfo.WrkNam/AdpDep.
bzPatientInfo/bzSheetInfo/bzWorkInfo 의 실존 공개 스칼라 속성으로 다시 큐레이션했다.
DataRow 접근형(...PatInfDR.item(컬럼))은 LastIndexOf(.) 규칙이 접두어를 깨뜨려
이 경로에서 반드시 실패하므로 목록에서 제외.

- LegacyQueryVariableCatalog 신설(그룹/설명 포함 레코드)
- 편집기 목록을 그룹 헤더 + 설명/토큰 2줄 + 툴팁으로 — 축약 오해 재발 방지
- 상용구 편집의 QueryEditorWindow 재사용에 showVariables:false 추가
  (상용구 문구 화면에 SQL 변수 목록이 노출되던 오조작 여지 제거)

검증: 테스트 70/70(레거시 완전일치 규칙 시뮬레이션 + 운영 실사용 토큰 존재 검사 포함),
edit-smoke 에 두 모드 실제 창 생성 검사 추가 — 실패 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 17:34:58 +09:00
MsystechandClaude Fable 5 c445b851a1 인스펙터 기본값 도입 + Choice 콤보의 속성 삭제 버그 수정
[값 삭제 버그] InspectorView 의 ComboBox SelectedItem 은 TwoWay 기본이라, 저장된 값이
Choices 에 없으면 null 로 코어스한 뒤 그 null 을 소스에 되써서 속성을 삭제했다.
Label TextAlign Choices 에 Bottom* 3값이 빠져 있어, 해당 라벨을 선택하는 것만으로
발동했다(운영 활성 디자인 1,305건 census: BottomCenter 126 / BottomLeft 107 / BottomRight 16).
- ContentAlignment 9값 전체로 보정
- ChoiceRowViewModel.EnsureChoice — 목록 밖 값을 표시 전에 편입(사이트 커스텀 값 방어)

[기본값] PropertyDef.Default 추가. RowBinding.Get 한 곳에서만 주입하므로
Initialize(building=true) 경로를 타 Commit 이 발생하지 않는다 — 사용자가 건드리기 전까지
PropBag 에 아무것도 쓰이지 않아 왕복 무손실이 유지된다. 다중 선택 병합도 자동으로 옳아진다.
지정 대상(레거시 필드 초기값/WinForms DefaultValueAttribute 근거):
  TextBox.RwdRsvWrdYon=True (TextBox.vb:63, 2022-09-28 추가라 이전 서식엔 키 없음)
  DataTable.ExcuteQuery=True (MDataTable.vb:15)
  Label.TextAlign=TopLeft / TextBox.TextAlign=Left / TextBox.BorderStyle=Fixed3D
  Panel.BorderStyle=None / PictureBox.SizeMode=Normal / DateTimePicker.Format=Long
이게 없으면 기본 True 속성이 항상 '꺼짐'으로 보이고, 사용자가 껐다 켜는 순간
명시 False 가 기록돼 상용구 입력·데이터소스 자동 실행이 실제로 죽는다.

ControlRegistryTests 신설 — Default⊆Choices, Toggle 기본값 표기, 그리고 운영 실사용
열거값이 Choices 에 전부 포함되는지(census 근거) 검사.

검증: 테스트 59/59, edit-smoke 실패 0, 전수 왕복 1,271건 diff 0/예외 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 17:30:28 +09:00
MsystechandClaude Fable 5 20e982faae 제자리 갱신 시 E_SctMst.SctObjTxt 갱신 누락 수정
ShtCneYon='Y' 서식은 기존 이름 행을 continue 로 건너뛰기만 해서, 라벨 문구를
고쳐도 항목사전(SctObjTxt)이 옛 문구로 남았다. 이 값은 외부인터페이스·환자전달사항·
알람이 리터럴로 매칭하는 조회 키라 조용한 데이터 불일치가 된다.

레거시 bzSaveSheetDesignNControlInfo.vb:378 과 동일하게 SctObjTxt 만 덮어쓴다:
- SctObjTyp/SctParObj/SctObjSeq/SctObjID 는 갱신하지 않음(SctKey 보존 의미론)
- 삭제된 컨트롤의 잔존 행도 지우지 않음(레거시 동일)
- SctKey 기준 UPDATE — 동명 중복 오염 데이터에서 다중 행 덮어쓰기 방지
- Spread AsTemplate 항목 행은 ObjName 이 항목 텍스트라 컨트롤 이름과 분리해 매칭.
  레거시의 매 저장 중복 INSERT 버그는 복제하지 않는다(런타임이 개수를 세지 않음).

--db-save-smoke 에 문구 변경 검증 추가 — 무변경 재저장으로는 이 경로를 증명할 수
없으므로 실제로 Text 를 바꿔 SctObjTxt 반영·SctKey 보존을 확인하고 원복한다.

검증: P163(ShtCneYon=Y) 2회 연속 통과(행 6/6 안정, SctKey 보존, 원복 확인),
S999(버저닝) diff 0 + 이전 버전 SdgDelYon='Y', 전수 왕복 1,271건 diff 0/예외 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 17:25:29 +09:00
MsystechandClaude Fable 5 16c07f48dc 초기 커밋: SheetMe 서식생성기 (P0~P5 완료 상태)
레거시 서식생성기(VB.NET WinForms) 대체용 C#/.NET 10 WPF 디자이너.
기준선: 실DB 활성 디자인 1,271건 왕복 의미론 diff 0 / 예외 0, 단위 테스트 49/49.

이 커밋에 함께 포함된 자격증명 분리:
- appsettings.json 을 __HOST__/__PASSWORD__ 플레이스홀더로 전환
- 실접속 정보는 appsettings.Development.json 으로 분리(.gitignore 제외,
  csproj Debug 조건부 복사라 Release 산출물에 실리지 않음)
- ConfigLoader 를 환경변수 > Development > appsettings 순 레이어링으로 변경,
  미치환 플레이스홀더는 '미설정'으로 간주

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 17:20:22 +09:00