D-7 끌어다 놓기를 화면에서 확인하고 세 군데를 고쳤다
경로 칸(TextBox)이 Drop 을 먼저 먹어 놓아도 아무 일이 없었다 - Preview 로 옮겼다. 파일 비교의 경로 글자는 Background 가 없어 놓을 자리 자체가 없었다. 칸에 놓아도 다시 견주지 않던 것을 DropFile / DropFolder 로 고쳤다. 파일을 하나씩 놓아 짝을 만들 수 있게 했다. 검색 결과 칸에 머리글을 넣고 줄 간격을 목록과 맞췄다.
This commit is contained in:
parent
373990b3b6
commit
196af0a913
31
doc/진행상황.md
31
doc/진행상황.md
@ -132,7 +132,7 @@ CommunityToolkit 커맨드는 CommandManager 를 구독하지 않는데 이 둘
|
||||
| ~~취소~~ | ~~D-4 비교 창 여러 개~~ (2026-09-09 사용자 판단으로 뺌) |
|
||||
| **완료** | D-5 덩어리 단위 반영 (3-Way 에서 BASE 를 가져오던 것을 REMOTE 로) |
|
||||
| **완료** | D-6 비교 결과 텍스트 내보내기 |
|
||||
| **완료**(화면 확인 남음) | D-7 드래그 앤 드롭으로 열기 |
|
||||
| **완료** | D-7 드래그 앤 드롭으로 열기 |
|
||||
|
||||
### E. 추가 요청 (2026-09-09 오후)
|
||||
|
||||
@ -203,7 +203,7 @@ BASE 머리글에 그렇게 적었다 - `BASE (merge base) · 이 파일 없음
|
||||
|
||||
---
|
||||
|
||||
### D-7. 드래그 앤 드롭으로 열기 — **코드 완료 · 화면 확인 남음** (2026-09-09)
|
||||
### D-7. 드래그 앤 드롭으로 열기 — **완료** (2026-09-09)
|
||||
|
||||
탐색기에서 파일·폴더를 끌어다 놓으면 그 자리에서 비교가 열린다.
|
||||
|
||||
@ -212,8 +212,31 @@ BASE 머리글에 그렇게 적었다 - `BASE (merge base) · 이 파일 없음
|
||||
가고 해당 탭이 켜진다. 화면 아무 데나 놓으면 이 판단을 타고, 왼쪽·오른쪽 경로 칸에 바로 놓으면
|
||||
그 칸만 채운다.
|
||||
|
||||
<b>화면에서 실제로 끌어다 놓는 확인은 아직 못 했다.</b> 작업 중 컴퓨터가 잠겨 탐색기에서
|
||||
끄는 동작을 만들 수 없었다. 잠금이 풀리면 확인한다.
|
||||
**실제로 탐색기에서 끌어다 놓아 보니 세 가지가 걸렸다.** 코드만 보고는 알 수 없는 것들이다.
|
||||
|
||||
<b>① 경로 칸 위에 놓으면 아무 일도 일어나지 않았다.</b>
|
||||
폴더 비교의 경로 칸은 `TextBox` 인데, `TextBoxBase` 의 클래스 처리기가 `DragOver`·`Drop` 을
|
||||
<b>먼저</b> 먹는다. 그쪽은 글자 끌어다 놓기만 알아서 파일 목록은 버리고 `Handled` 로 막아 버린다.
|
||||
터널링 쪽(`PreviewDragOver`·`PreviewDrop`)으로 옮겨 클래스 처리기보다 먼저 받게 고쳤다.
|
||||
|
||||
<b>② 파일 비교 화면의 경로 글자는 놓을 자리 자체가 없었다.</b>
|
||||
`TextBlock` 은 `Background` 가 없으면 히트 테스트에 안 잡힌다. `Background="Transparent"` 를 줬다.
|
||||
|
||||
<b>③ 칸에 놓아도 다시 견주지 않았다.</b> 칸 값만 바뀌고 화면은 옛 파일을 그대로 보여 줬다 -
|
||||
"놓았는데 아무 일도 없다"로 읽힌다. `HomeViewModel.DropFile` 과 `FolderViewModel.DropFolder` 를
|
||||
만들어 넣은 뒤 바로 다시 견주게 했다. 폴더는 양쪽이 다 찼을 때만 견준다.
|
||||
|
||||
**파일 하나씩 끌어다 놓아 짝을 만들 수 있게 했다.** 그 전에는 두 번째 파일이 첫 번째를 밀어내
|
||||
아무리 놓아도 왼쪽만 바뀌었다. 왼쪽만 차 있고 오른쪽이 비어 있으면 오른쪽을 채운다.
|
||||
|
||||
**확인한 것**
|
||||
|
||||
| 놓은 것 | 결과 |
|
||||
|---|---|
|
||||
| 폴더를 왼쪽·오른쪽 칸에 하나씩 | 두 칸이 차고 곧바로 비교가 돌았다 (`전체 4개 · 다름 1 · 왼쪽만 1 · 오른쪽만 1 · 같음 1`) |
|
||||
| 폴더를 화면 몸통에 | 왼쪽 칸에 들어갔다 |
|
||||
| 파일을 폴더 비교 몸통에 | 파일 비교 탭으로 넘어가고 BASE 에 들어갔다 |
|
||||
| 그 뒤 파일을 하나 더 | LOCAL 에 들어가고 짝이 맞춰졌다 (`총 8 라인 · 차이 2 라인`) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -343,6 +343,23 @@ namespace MergeHub.ViewModels
|
||||
|
||||
private CancellationTokenSource? _compareCancel;
|
||||
|
||||
/// <summary>
|
||||
/// 끌어다 놓은 폴더를 한쪽 칸에 넣고, <b>양쪽이 다 차면 바로 견준다.</b>
|
||||
///
|
||||
/// 탐색기 우클릭으로 넘어오는 길과 같게 맞춘 것이다 - 두 칸이 다 찼는데도
|
||||
/// [비교]를 한 번 더 눌러야 하면 놓은 보람이 없다.
|
||||
/// </summary>
|
||||
public void DropFolder(string folder, bool left)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(folder)) return;
|
||||
|
||||
if (left) LeftFolder = folder;
|
||||
else RightFolder = folder;
|
||||
|
||||
if (Directory.Exists(LeftFolder) && Directory.Exists(RightFolder)) _ = CompareAsync();
|
||||
}
|
||||
|
||||
|
||||
// ================= 폴더 전체 검색 =================
|
||||
|
||||
/// <summary>찾은 줄. 파일 차례로 늘어선다.</summary>
|
||||
|
||||
@ -1444,6 +1444,24 @@ namespace MergeHub.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 끌어다 놓은 파일을 한쪽 칸에 넣고 <b>바로 다시 견준다.</b>
|
||||
///
|
||||
/// 칸 값만 바꾸고 두면 화면은 옛 파일을 그대로 보여 준다 - "놓았는데 아무 일도 없다"로 읽힌다.
|
||||
/// 파일 고르기 단추와 같은 길(<c>RequestPlainCompare</c>)로 보내는 까닭은 그 길이
|
||||
/// Git 모드를 끄는 것까지 함께 하기 때문이다. 저장소를 열어 둔 채로 파일을 끌어다 놓으면
|
||||
/// 사용자가 보고 싶은 것은 그 두 파일이지 커밋 이력이 아니다.
|
||||
/// </summary>
|
||||
public void DropFile(string path, bool left)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path)) return;
|
||||
|
||||
var newLeft = left ? path : LeftFile;
|
||||
var newRight = left ? RightFile : path;
|
||||
|
||||
_workspace.RequestPlainCompare(newLeft, newRight);
|
||||
}
|
||||
|
||||
// ================= 결과 내보내기 =================
|
||||
|
||||
private bool CanExportReport() => Lines.Count > 0;
|
||||
|
||||
@ -102,14 +102,14 @@
|
||||
<Button Grid.Column="0" Content="왼쪽 폴더..." Command="{Binding PickLeftFolderCommand}"
|
||||
Height="28" Padding="10,2" FontSize="11" Margin="0,0,6,0"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding LeftFolder, UpdateSourceTrigger=PropertyChanged}"
|
||||
AllowDrop="True" DragOver="View_DragOver" Drop="LeftFolder_Drop"
|
||||
AllowDrop="True" PreviewDragOver="View_DragOver" PreviewDrop="LeftFolder_Drop"
|
||||
FontFamily="Consolas" FontSize="11" Height="28" VerticalContentAlignment="Center"
|
||||
Margin="0,0,14,0" ToolTip="비교 기준이 되는 폴더"/>
|
||||
|
||||
<Button Grid.Column="2" Content="오른쪽 폴더..." Command="{Binding PickRightFolderCommand}"
|
||||
Height="28" Padding="10,2" FontSize="11" Margin="0,0,6,0"/>
|
||||
<TextBox Grid.Column="3" Text="{Binding RightFolder, UpdateSourceTrigger=PropertyChanged}"
|
||||
AllowDrop="True" DragOver="View_DragOver" Drop="RightFolder_Drop"
|
||||
AllowDrop="True" PreviewDragOver="View_DragOver" PreviewDrop="RightFolder_Drop"
|
||||
FontFamily="Consolas" FontSize="11" Height="28" VerticalContentAlignment="Center"
|
||||
ToolTip="견줄 폴더"/>
|
||||
</Grid>
|
||||
@ -302,40 +302,70 @@
|
||||
찾은 줄. 검색하기 전에는 접혀 있어 목록이 자리를 다 쓴다.
|
||||
높이를 묶어 두는 까닭 - 결과가 수천 줄이어도 목록을 화면 밖으로 밀면 안 된다.
|
||||
-->
|
||||
<Border Grid.Row="1" BorderThickness="1,0,1,1" Margin="0,0,0,0"
|
||||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}"
|
||||
Visibility="{Binding HasSearched, Converter={StaticResource BoolToVis}}">
|
||||
<ListBox x:Name="HitList" ItemsSource="{Binding SearchHits}"
|
||||
SelectedItem="{Binding SelectedHit}"
|
||||
MinHeight="90" MaxHeight="260" BorderThickness="0"
|
||||
MouseDoubleClick="HitList_MouseDoubleClick"
|
||||
KeyDown="HitList_KeyDown"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
VirtualizingPanel.IsVirtualizing="True"
|
||||
VirtualizingPanel.VirtualizationMode="Recycling">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="52"/>
|
||||
<ColumnDefinition Width="320"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Row="1"
|
||||
Visibility="{Binding HasSearched, Converter={StaticResource BoolToVis}}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Text="{Binding SideText}" FontSize="11"
|
||||
FontWeight="Bold"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Where}" FontFamily="Consolas"
|
||||
FontSize="11" TextTrimming="CharacterEllipsis"
|
||||
ToolTip="{Binding RelativePath}"/>
|
||||
<TextBlock Grid.Column="2" Text="{Binding Preview}" FontFamily="Consolas"
|
||||
FontSize="11" TextTrimming="CharacterEllipsis"
|
||||
Style="{StaticResource Muted}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
<!-- 결과 칸 머리글. 위 목록과 같은 짜임이라 여기도 무슨 칸인지 적어 준다. -->
|
||||
<Border Grid.Row="0" Padding="8,4" BorderThickness="1,1,1,0"
|
||||
Background="{DynamicResource Ubisam.Brush.Sidebar.Background}"
|
||||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||||
<Grid Margin="6,0,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="52"/>
|
||||
<ColumnDefinition Width="280"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="어디" FontSize="11" FontWeight="Bold"
|
||||
ToolTip="양쪽 = 두 폴더에 똑같이 있는 줄"/>
|
||||
<TextBlock Grid.Column="1" Text="파일 · 줄" FontSize="11" FontWeight="Bold"/>
|
||||
<TextBlock Grid.Column="2" Text="찾은 줄" FontSize="11" FontWeight="Bold"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" BorderThickness="1,0,1,1"
|
||||
BorderBrush="{DynamicResource Ubisam.Brush.Input.Border}">
|
||||
<ListBox x:Name="HitList" ItemsSource="{Binding SearchHits}"
|
||||
SelectedItem="{Binding SelectedHit}"
|
||||
MinHeight="90" MaxHeight="260" BorderThickness="0"
|
||||
MouseDoubleClick="HitList_MouseDoubleClick"
|
||||
KeyDown="HitList_KeyDown"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
VirtualizingPanel.IsVirtualizing="True"
|
||||
VirtualizingPanel.VirtualizationMode="Recycling">
|
||||
<!-- 기본 여백을 그대로 두면 줄이 성기게 벌어져 위 목록과 딴판으로 보인다. -->
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="Padding" Value="6,1"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="52"/>
|
||||
<ColumnDefinition Width="280"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Text="{Binding SideText}" FontSize="11"
|
||||
FontWeight="Bold"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding Where}" FontFamily="Consolas"
|
||||
FontSize="11" TextTrimming="CharacterEllipsis"
|
||||
ToolTip="{Binding RelativePath}"/>
|
||||
<TextBlock Grid.Column="2" Text="{Binding Preview}" FontFamily="Consolas"
|
||||
FontSize="11" TextTrimming="CharacterEllipsis"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- ⑤ 요약 · 동작 -->
|
||||
|
||||
@ -139,7 +139,15 @@ namespace MergeHub.Views
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>왼쪽·오른쪽 칸에 바로 놓으면 <b>그 자리에만</b> 들어간다.</summary>
|
||||
/// <summary>
|
||||
/// 왼쪽·오른쪽 칸에 바로 놓으면 <b>그 자리에만</b> 들어간다.
|
||||
///
|
||||
/// XAML 에서 <c>PreviewDrop</c> 으로 받는 까닭 - 경로 칸이 <c>TextBox</c> 라서
|
||||
/// <c>TextBoxBase</c> 의 클래스 처리기가 <c>DragOver</c>·<c>Drop</c> 을 먼저 먹는다.
|
||||
/// 그쪽은 글자 끌어다 놓기만 알아서 파일 목록은 버리고 <c>Handled</c> 로 막아 버린다.
|
||||
/// 실제로 화면에서 칸 위에 놓아 봤더니 아무 일도 일어나지 않았다.
|
||||
/// 터널링(Preview)은 클래스 처리기보다 먼저 도므로 이쪽이 먼저 받는다.
|
||||
/// </summary>
|
||||
private void LeftFolder_Drop(object sender, DragEventArgs e) => DropIntoSlot(e, left: true);
|
||||
|
||||
private void RightFolder_Drop(object sender, DragEventArgs e) => DropIntoSlot(e, left: false);
|
||||
@ -154,9 +162,6 @@ namespace MergeHub.Views
|
||||
if (folder.Length == 0) folder = Services.PathUtil.FolderOfFile(paths[0]);
|
||||
if (folder.Length == 0) return;
|
||||
|
||||
if (left) vm.LeftFolder = folder;
|
||||
else vm.RightFolder = folder;
|
||||
|
||||
// 두 개를 한꺼번에 놓았으면 나머지 하나는 반대쪽에 넣는다.
|
||||
if (paths.Length > 1)
|
||||
{
|
||||
@ -170,6 +175,9 @@ namespace MergeHub.Views
|
||||
}
|
||||
}
|
||||
|
||||
// 넣고 나서 양쪽이 다 찼으면 그 자리에서 견준다.
|
||||
vm.DropFolder(folder, left);
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
@ -386,6 +386,7 @@
|
||||
<TextBlock Text="{Binding LeftFile}" Style="{StaticResource Muted}" FontSize="11"
|
||||
MaxWidth="260" TextTrimming="CharacterEllipsis" Margin="4,0,10,0"
|
||||
ToolTip="{Binding LeftFile}"
|
||||
Background="Transparent"
|
||||
AllowDrop="True" DragOver="View_DragOver" Drop="LeftFile_Drop"/>
|
||||
<Button Content="내 파일..." Command="{Binding PickRightFileCommand}"
|
||||
Height="26" MinHeight="26" Padding="8,2" FontSize="11"
|
||||
@ -393,6 +394,7 @@
|
||||
<TextBlock Text="{Binding RightFile}" Style="{StaticResource Muted}" FontSize="11"
|
||||
MaxWidth="260" TextTrimming="CharacterEllipsis" Margin="4,0,0,0"
|
||||
ToolTip="{Binding RightFile}"
|
||||
Background="Transparent"
|
||||
AllowDrop="True" DragOver="View_DragOver" Drop="RightFile_Drop"/>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@ -936,6 +936,16 @@ namespace MergeHub.Views
|
||||
if (DataContext is not HomeViewModel vm) return;
|
||||
if (DroppedPaths(e) is not { Length: > 0 } paths) return;
|
||||
|
||||
// 파일 하나를 놓았는데 왼쪽만 차 있으면 오른쪽을 채운다.
|
||||
// 그러지 않으면 하나씩 끌어다 놓아서는 짝을 만들 수 없다 - 두 번째가 첫 번째를 밀어낸다.
|
||||
if (paths.Length == 1 && System.IO.File.Exists(paths[0]) &&
|
||||
!string.IsNullOrWhiteSpace(vm.LeftFile) && string.IsNullOrWhiteSpace(vm.RightFile))
|
||||
{
|
||||
vm.DropFile(paths[0], left: false);
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
vm.Workspace.RouteDroppedPaths(paths);
|
||||
e.Handled = true;
|
||||
}
|
||||
@ -958,9 +968,6 @@ namespace MergeHub.Views
|
||||
return;
|
||||
}
|
||||
|
||||
if (left) vm.LeftFile = paths[0];
|
||||
else vm.RightFile = paths[0];
|
||||
|
||||
// 두 개를 한꺼번에 놓았으면 나머지 하나는 반대쪽에 넣는다.
|
||||
if (paths.Length > 1 && !System.IO.Directory.Exists(paths[1]))
|
||||
{
|
||||
@ -968,6 +975,9 @@ namespace MergeHub.Views
|
||||
else vm.LeftFile = paths[1];
|
||||
}
|
||||
|
||||
// 칸 값만 바꾸면 화면은 옛 파일을 그대로 보여 준다. 넣고 바로 다시 견준다.
|
||||
vm.DropFile(paths[0], left);
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user