표(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>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d0538ef95a
commit
3dcac31a5b
@@ -909,7 +909,7 @@ public sealed class DesignerViewModel : ViewModelBase
|
||||
clipboard.AddRange(ordered);
|
||||
}
|
||||
|
||||
/// <summary>붙여넣기 — 활성 페이지에 +12,+12 오프셋, 새 Id 부여</summary>
|
||||
/// <summary>붙여넣기 — 활성 페이지에 +12,+12 오프셋, 새 Id 부여 (표는 제외 — <see cref="ContainsSpread"/> 참조)</summary>
|
||||
public void Paste()
|
||||
{
|
||||
if (clipboard.Count == 0)
|
||||
@@ -922,11 +922,26 @@ public sealed class DesignerViewModel : ViewModelBase
|
||||
return;
|
||||
}
|
||||
|
||||
var (pastable, blocked) = FilterPastable(clipboard);
|
||||
if (blocked > 0)
|
||||
{
|
||||
System.Windows.MessageBox.Show(
|
||||
$"표(Spread) {blocked}개는 붙여넣지 않았습니다.\n\n" +
|
||||
"표의 격자 디자인은 서식코드+컨트롤이름으로 별도 테이블(E_SpdMst)에서 조회됩니다.\n" +
|
||||
"복제본에는 격자가 없어 EMR 에서 해당 서식이 열리지 않습니다.\n" +
|
||||
"표 추가는 레거시 서식생성기를 사용하세요.",
|
||||
"붙여넣기", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Warning);
|
||||
}
|
||||
if (pastable.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Undo.Snapshot();
|
||||
var pasted = new List<ControlViewModel>();
|
||||
var usedIds = IdGenerator.CollectUsed(document);
|
||||
// 모델 순서(0=최상위) 유지: 역순으로 index 0 삽입
|
||||
foreach (var source in Enumerable.Reverse(clipboard))
|
||||
foreach (var source in Enumerable.Reverse(pastable))
|
||||
{
|
||||
var clone = source.Clone();
|
||||
AssignNewIds(clone, usedIds);
|
||||
@@ -938,6 +953,31 @@ public sealed class DesignerViewModel : ViewModelBase
|
||||
Selection.Set(pasted, pasted.LastOrDefault());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 표(Spread) 타입 — E_SpdMst 격자를 서식코드+이름으로 조회하므로 이름 변경·복제가 금지된다.
|
||||
/// VM 형이 아니라 모델 Type 문자열로 판정한다(클립보드가 ControlElement 이고 컨테이너 중첩도 잡아야 함).
|
||||
/// </summary>
|
||||
public static bool IsSpread(ControlElement element)
|
||||
=> string.Equals(element.Type, "Spread", StringComparison.Ordinal);
|
||||
|
||||
/// <summary>자신 또는 자손에 표(Spread)가 있는지</summary>
|
||||
public static bool ContainsSpread(ControlElement element)
|
||||
=> IsSpread(element) || element.Children.Any(ContainsSpread);
|
||||
|
||||
/// <summary>
|
||||
/// 붙여넣기 가능 항목과 차단된 표 개수 — 알림과 분리해 무인 검증이 가능하도록 둔 순수 함수.
|
||||
/// 표의 격자는 서식코드+컨트롤이름으로만 조회되는 E_SpdMst 에 있고 SheetMe 는 그 행을 만들지 못한다.
|
||||
/// 복제본은 이름이 달라 조회 0건 → 레거시가 빈 파일로 FpSpread.Open 을 시도하다 예외 →
|
||||
/// LoadObject 에 try/catch 가 없어 최상위로 전파되어 그 서식이 통째로 열리지 않는다.
|
||||
/// 선택 전체를 막지 않고 표만 걸러내는 이유: "라벨 20개 + 표 1개" 복사 같은 정상 작업까지 막히기 때문.
|
||||
/// </summary>
|
||||
public static (List<ControlElement> Pastable, int BlockedSpreads) FilterPastable(IEnumerable<ControlElement> source)
|
||||
{
|
||||
var all = source.ToList();
|
||||
var pastable = all.Where(element => !ContainsSpread(element)).ToList();
|
||||
return (pastable, all.Count - pastable.Count);
|
||||
}
|
||||
|
||||
/// <summary>선택 z-order 변경 — 모델 index 0 = 최상위 / VM 마지막 = 최상위</summary>
|
||||
public void ReorderSelection(bool toFront)
|
||||
{
|
||||
|
||||
@@ -372,11 +372,28 @@ public sealed class InspectorViewModel : ViewModelBase
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 표(Spread)의 격자는 E_SpdMst 에서 서식코드+이름으로 조회된다. 이름을 바꾸면 조회 0건 →
|
||||
// 레거시가 빈 파일로 FpSpread.Open 을 시도하다 예외 → LoadObject 에 try/catch 가 없어
|
||||
// 최상위로 전파되어 그 서식이 통째로 열리지 않는다. SheetMe 는 E_SpdMst 행을 만들 수 없으므로 금지한다.
|
||||
if (DesignerViewModel.IsSpread(vm.Model))
|
||||
{
|
||||
System.Windows.MessageBox.Show(
|
||||
"표(Spread)는 이름을 바꿀 수 없습니다.\n\n" +
|
||||
$"격자 디자인이 서식코드+이름('{vm.Id}')으로 별도 테이블(E_SpdMst)에 저장되어 있어,\n" +
|
||||
"이름을 바꾸면 EMR 에서 이 서식이 열리지 않습니다.",
|
||||
"이름 변경", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Warning);
|
||||
Rebuild();
|
||||
return;
|
||||
}
|
||||
|
||||
var used = IdGenerator.CollectUsed(designer.Document);
|
||||
used.Remove(vm.Id);
|
||||
if (used.Contains(trimmed))
|
||||
{
|
||||
System.Windows.MessageBox.Show($"이미 사용 중인 이름입니다: {trimmed}", "이름 변경");
|
||||
// 거부했으므로 편집 상자에 남은 잘못된 이름을 원래 값으로 되돌린다
|
||||
Rebuild();
|
||||
return;
|
||||
}
|
||||
vm.Model.Id = trimmed;
|
||||
|
||||
Reference in New Issue
Block a user