Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions app/Sentinel.NLogViewer.App/ImportDestinationWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<Window x:Class="Sentinel.NLogViewer.App.ImportDestinationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:helpers="clr-namespace:Sentinel.NLogViewer.App.Helpers"
mc:Ignorable="d"
Title="{helpers:Resource Key=ImportDestination_Title, DefaultValue=Import destination}"
Height="440"
Width="480"
MinHeight="340"
MinWidth="380"
WindowStartupLocation="CenterOwner"
ResizeMode="CanResize">
<Grid Margin="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<TextBlock Grid.Row="0"
TextWrapping="Wrap"
Margin="0,0,0,12"
Text="{helpers:Resource Key=ImportDestination_Instructions, DefaultValue=Choose where to load the selected file(s).}" />

<StackPanel Grid.Row="1">
<RadioButton x:Name="ExistingTabRadio"
GroupName="ImportDest"
Margin="0,0,0,8"
Content="{helpers:Resource Key=ImportDestination_ExistingTab, DefaultValue=Append to an existing tab}"
Checked="ModeRadio_Checked" />
<ListBox x:Name="TabsListBox"
DisplayMemberPath="Header"
MinHeight="120"
Margin="24,0,0,12"
SelectionChanged="TabsListBox_SelectionChanged" />
<RadioButton x:Name="SingleNewTabRadio"
GroupName="ImportDest"
Margin="0,0,0,8"
Content="{helpers:Resource Key=ImportDestination_SingleNewTab, DefaultValue=One new tab for all file(s)}"
Checked="ModeRadio_Checked" />
<RadioButton x:Name="PerFileNewTabRadio"
GroupName="ImportDest"
Margin="0,0,0,0"
Content="{helpers:Resource Key=ImportDestination_PerFileNewTab, DefaultValue=New tab for each file}"
Checked="ModeRadio_Checked" />
</StackPanel>

<StackPanel Grid.Row="3"
Orientation="Horizontal"
HorizontalAlignment="Right"
Margin="0,16,0,0">
<Button x:Name="OkButton"
Content="{helpers:Resource Key=ImportDestination_OK, DefaultValue=_OK}"
Width="92"
Margin="0,0,8,0"
IsDefault="True"
Click="OkButton_Click" />
<Button Content="{helpers:Resource Key=ImportDestination_Cancel, DefaultValue=_Cancel}"
Width="92"
IsCancel="True" />
</StackPanel>
</Grid>
</Window>
176 changes: 176 additions & 0 deletions app/Sentinel.NLogViewer.App/ImportDestinationWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Extensions.DependencyInjection;
using Sentinel.NLogViewer.App.Models;
using Sentinel.NLogViewer.App.Services;

namespace Sentinel.NLogViewer.App;

/// <summary>
/// Dialog for choosing how imported log files are routed to tabs.
/// </summary>
public partial class ImportDestinationWindow : Window
{
private readonly IList<LogTabViewModel> _tabs;
private readonly bool _showExistingTabOption;
private readonly bool _showPerFileNewTabOption;
private readonly LogTabViewModel? _preferredExistingTab;

/// <summary>
/// The user's choice when <see cref="Window.DialogResult"/> is true.
/// </summary>
public LogFileImportBatchContext.DestinationMode SelectedMode { get; private set; }

/// <summary>
/// When <see cref="SelectedMode"/> is <see cref="LogFileImportBatchContext.DestinationMode.ExistingTab"/>, the tab to append to.
/// </summary>
public LogTabViewModel? SelectedExistingTab { get; private set; }

/// <summary>
/// Creates the import destination picker.
/// </summary>
/// <param name="tabs">Open tabs used for "existing tab" mode.</param>
/// <param name="preferredExistingTab">Tab to pre-select when enabling existing-tab mode.</param>
/// <param name="showExistingTabOption">When false (no open tabs yet), hides existing-tab UI.</param>
/// <param name="showPerFileNewTabOption">When false (single file only), hides the "new tab per file" choice.</param>
public ImportDestinationWindow(IList<LogTabViewModel> tabs, LogTabViewModel? preferredExistingTab,
bool showExistingTabOption, bool showPerFileNewTabOption = true)
{
if (tabs == null)
throw new ArgumentNullException(nameof(tabs));

_tabs = tabs;
_showExistingTabOption = showExistingTabOption;
_showPerFileNewTabOption = showPerFileNewTabOption;
_preferredExistingTab = preferredExistingTab;

InitializeComponent();

TabsListBox.ItemsSource = _tabs;
UpdateExistingTabAvailability();
UpdatePerFileNewTabOptionVisibility();
ApplyInitialSelection();
UpdateOkEnabled();

KeyDown += (_, e) =>
{
if (e.Key == System.Windows.Input.Key.Escape)
DialogResult = false;
};
}

private void ApplyInitialSelection()
{
if (_showExistingTabOption && _tabs.Count > 0)
{
var fallback = _tabs.First();
TabsListBox.SelectedItem =
_preferredExistingTab != null && _tabs.Contains(_preferredExistingTab)
? _preferredExistingTab
: fallback;
ExistingTabRadio.IsChecked = true;
TabsListBox.IsEnabled = true;
SingleNewTabRadio.IsChecked = false;
PerFileNewTabRadio.IsChecked = false;
}
else
{
SingleNewTabRadio.IsChecked = true;
ExistingTabRadio.IsChecked = false;
PerFileNewTabRadio.IsChecked = false;
TabsListBox.IsEnabled = false;
if (_tabs.Count > 0 && TabsListBox.SelectedItem == null)
TabsListBox.SelectedItem = _tabs.First();
}
}

private void UpdateExistingTabAvailability()
{
if (!_showExistingTabOption)
{
ExistingTabRadio.Visibility = Visibility.Collapsed;
TabsListBox.Visibility = Visibility.Collapsed;
return;
}

ExistingTabRadio.Visibility = Visibility.Visible;
TabsListBox.Visibility = Visibility.Visible;
TabsListBox.IsEnabled = ExistingTabRadio.IsChecked == true;
}

/// <summary>
/// Hides "new tab per file" when only one file is being imported (option is redundant).
/// </summary>
private void UpdatePerFileNewTabOptionVisibility()
{
PerFileNewTabRadio.Visibility = _showPerFileNewTabOption ? Visibility.Visible : Visibility.Collapsed;
}

private void ModeRadio_Checked(object sender, RoutedEventArgs e)
{
if (TabsListBox == null || ExistingTabRadio == null || OkButton == null)
return;

TabsListBox.IsEnabled = ExistingTabRadio.IsChecked == true;
if (!TabsListBox.IsEnabled && TabsListBox.Items.Count > 0 && TabsListBox.SelectedItem == null)
TabsListBox.SelectedIndex = 0;

UpdateOkEnabled();
}

private void TabsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
UpdateOkEnabled();
}

private void UpdateOkEnabled()
{
var existingMode = ExistingTabRadio.IsChecked == true;
OkButton.IsEnabled = !existingMode || TabsListBox.SelectedItem is LogTabViewModel;
}

private void OkButton_Click(object sender, RoutedEventArgs e)
{
if (ExistingTabRadio.IsChecked == true)
{
if (TabsListBox.SelectedItem is not LogTabViewModel tab)
{
MessageBox.Show(
this,
GetMessage("ImportDestination_SelectTab", "Please select a tab."));
return;
}

SelectedMode = LogFileImportBatchContext.DestinationMode.ExistingTab;
SelectedExistingTab = tab;
}
else if (_showPerFileNewTabOption && PerFileNewTabRadio.IsChecked == true)
{
SelectedMode = LogFileImportBatchContext.DestinationMode.PerFileNewTab;
SelectedExistingTab = null;
}
else
{
SelectedMode = LogFileImportBatchContext.DestinationMode.SingleNewTab;
SelectedExistingTab = null;
}

DialogResult = true;
}

private static string GetMessage(string key, string fallback)
{
try
{
var loc = App.ServiceProvider?.GetService<LocalizationService>();
return loc != null ? loc.GetString(key, fallback) : fallback;
}
catch
{
return fallback;
}
}
}
28 changes: 24 additions & 4 deletions app/Sentinel.NLogViewer.App/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
<Grid.Resources>
<DataTemplate x:Key="TabControlContentTemplate" DataType="models:LogTabViewModel">
<!-- ReSharper disable once Xaml.BindingWithContextNotResolved -->
<dj:NLogViewer
<dj:NLogViewerBase
x:Name="NLogViewer1"
Tag="{Binding ElementName=NLogViewer1}"
CacheTarget="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ContentPresenter}}"
DataContext="{Binding DataContext.NLogViewer, Mode=OneWayToSource, RelativeSource={RelativeSource AncestorType=ContentPresenter}}"/>
ItemsSource="{Binding DataContext.LogEntries, RelativeSource={RelativeSource AncestorType=ContentPresenter}}"
MaxCount="{Binding DataContext.MaxCount, RelativeSource={RelativeSource AncestorType=ContentPresenter}}"/>
</DataTemplate>
</Grid.Resources>
<Grid.RowDefinitions>
Expand All @@ -48,6 +48,12 @@
InputGestureText="Ctrl+,"/>
</MenuItem>
<MenuItem Header="{helpers:Resource Key=Menu_Logs, DefaultValue=_Logs}">
<MenuItem Header="{helpers:Resource Key=Menu_Logs_Tabs, DefaultValue=_Tabs}">
<MenuItem Header="{helpers:Resource Key=Menu_CloseCurrentTab, DefaultValue=Close _current tab}"
Command="{Binding CloseCurrentTabCommand}"/>
<MenuItem Header="{helpers:Resource Key=Menu_CloseAllTabs, DefaultValue=Close _all tabs}"
Command="{Binding CloseAllTabsCommand}"/>
</MenuItem>
<MenuItem Header="{helpers:Resource Key=Menu_Export, DefaultValue=_Export}">
<MenuItem Header="{helpers:Resource Key=Menu_ExportLogFormat, DefaultValue=*.log format}"
Command="{Binding ExportLogsCommand}"/>
Expand Down Expand Up @@ -76,11 +82,25 @@
</ToolBar>

<!-- Main Content: TabControl with NLogViewers -->
<TabControl Grid.Row="1"
<TabControl x:Name="LogTabsControl"
Grid.Row="1"
ItemsSource="{Binding LogTabs}"
SelectedItem="{Binding SelectedTab}"
AllowDrop="True"
PreviewDragOver="LogTabsArea_PreviewDragOver"
Drop="LogTabsArea_Drop"
attachedProperties:TabContent.IsCached="True"
attachedProperties:TabContent.Template="{StaticResource TabControlContentTemplate}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="AllowDrop" Value="True"/>
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="LogTabItem_PreviewMouseLeftButtonDown"/>
<EventSetter Event="PreviewMouseLeftButtonUp" Handler="LogTabItem_PreviewMouseLeftButtonUp"/>
<EventSetter Event="PreviewMouseMove" Handler="LogTabItem_PreviewMouseMove"/>
<EventSetter Event="PreviewDragOver" Handler="LogTabItem_PreviewDragOver"/>
<EventSetter Event="Drop" Handler="LogTabItem_Drop"/>
</Style>
</TabControl.ItemContainerStyle>
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
Expand Down
Loading
Loading