diff --git a/src/LogExpert.Core/Config/Preferences.cs b/src/LogExpert.Core/Config/Preferences.cs
index 75a12136..f5206b88 100644
--- a/src/LogExpert.Core/Config/Preferences.cs
+++ b/src/LogExpert.Core/Config/Preferences.cs
@@ -11,6 +11,7 @@ namespace LogExpert.Core.Config;
public class Preferences
{
private SelectionHighlightSettings _selectionHighlight = new();
+ private int[] _highlightCustomColors = [];
public SelectionHighlightSettings SelectionHighlight
{
@@ -18,6 +19,13 @@ public SelectionHighlightSettings SelectionHighlight
set => _selectionHighlight = value ?? new();
}
+ /// Custom-color palette shared by the Highlight Entry color pickers, as ColorDialog.CustomColors values.
+ public int[] HighlightCustomColors
+ {
+ get => _highlightCustomColors;
+ set => _highlightCustomColors = value ?? [];
+ }
+
///
/// List of highlight groups for syntax highlighting and text coloring.
///
diff --git a/src/LogExpert.Resources/Resources.Designer.cs b/src/LogExpert.Resources/Resources.Designer.cs
index ee588c9a..c9a2efa5 100644
--- a/src/LogExpert.Resources/Resources.Designer.cs
+++ b/src/LogExpert.Resources/Resources.Designer.cs
@@ -1009,6 +1009,15 @@ public static string HighlightDialog_UI_Button_Copy {
}
}
+ ///
+ /// Looks up a localized string similar to Co&py.
+ ///
+ public static string HighlightDialog_UI_Button_CopyEntry {
+ get {
+ return ResourceManager.GetString("HighlightDialog_UI_Button_CopyEntry", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Background color.
///
diff --git a/src/LogExpert.Resources/Resources.de.resx b/src/LogExpert.Resources/Resources.de.resx
index acf8879f..2ef41f1c 100644
--- a/src/LogExpert.Resources/Resources.de.resx
+++ b/src/LogExpert.Resources/Resources.de.resx
@@ -1529,6 +1529,9 @@ Ein ausgewähltes Tool erscheint in der Iconbar. Alle anderen verfügbaren Tools
Kopieren
+
+ Ko&pieren
+
Gruppe löschen
diff --git a/src/LogExpert.Resources/Resources.resx b/src/LogExpert.Resources/Resources.resx
index 10f5d9a9..79a319f5 100644
--- a/src/LogExpert.Resources/Resources.resx
+++ b/src/LogExpert.Resources/Resources.resx
@@ -1610,6 +1610,9 @@ Checked tools will appear in the icon bar. All other tools are available in the
&Copy
+
+ Co&py
+
Delete group
diff --git a/src/LogExpert.Resources/Resources.zh-CN.resx b/src/LogExpert.Resources/Resources.zh-CN.resx
index d8127cc8..d8026b56 100644
--- a/src/LogExpert.Resources/Resources.zh-CN.resx
+++ b/src/LogExpert.Resources/Resources.zh-CN.resx
@@ -1434,6 +1434,9 @@
复制(&C)
+
+ 复制(&P)
+
删除分组
diff --git a/src/LogExpert.Tests/ConfigManagerTests/HighlightCustomColorsTests.cs b/src/LogExpert.Tests/ConfigManagerTests/HighlightCustomColorsTests.cs
new file mode 100644
index 00000000..c91dc3cd
--- /dev/null
+++ b/src/LogExpert.Tests/ConfigManagerTests/HighlightCustomColorsTests.cs
@@ -0,0 +1,37 @@
+using LogExpert.Core.Config;
+
+using Newtonsoft.Json;
+
+using NUnit.Framework;
+
+namespace LogExpert.Tests.ConfigManagerTests;
+
+[TestFixture]
+public class HighlightCustomColorsTests
+{
+ [Test]
+ public void Palette_SurvivesRoundTrip ()
+ {
+ var preferences = new Preferences { HighlightCustomColors = [0x00123456, 0x00FFFFFF] };
+
+ var restored = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(preferences));
+
+ Assert.That(restored.HighlightCustomColors, Is.EqualTo(new[] { 0x00123456, 0x00FFFFFF }));
+ }
+
+ [Test]
+ public void OlderSettings_LoadWithAnEmptyPalette ()
+ {
+ var preferences = JsonConvert.DeserializeObject("{}");
+
+ Assert.That(preferences.HighlightCustomColors, Is.Empty);
+ }
+
+ [Test]
+ public void NullPalette_BecomesEmpty ()
+ {
+ var preferences = JsonConvert.DeserializeObject("{\"HighlightCustomColors\":null}");
+
+ Assert.That(preferences.HighlightCustomColors, Is.Empty);
+ }
+}
diff --git a/src/LogExpert.UI.Tests/Dialogs/HighlightDialogEntryTests.cs b/src/LogExpert.UI.Tests/Dialogs/HighlightDialogEntryTests.cs
new file mode 100644
index 00000000..6d640e4e
--- /dev/null
+++ b/src/LogExpert.UI.Tests/Dialogs/HighlightDialogEntryTests.cs
@@ -0,0 +1,216 @@
+using System.Reflection;
+
+using LogExpert.Core.Classes.Highlight;
+using LogExpert.Core.Config;
+using LogExpert.Core.Entities;
+using LogExpert.Core.Interfaces;
+using LogExpert.Dialogs;
+using LogExpert.UI.Dialogs.Highlight;
+
+using Moq;
+
+using NUnit.Framework;
+
+namespace LogExpert.UI.Tests.Dialogs;
+
+[TestFixture]
+[Apartment(ApartmentState.STA)]
+[System.Runtime.Versioning.SupportedOSPlatform("windows")]
+public class HighlightDialogEntryTests
+{
+ private Settings _settings;
+ private HighlightDialog _dialog;
+ private HighlightEntry _source;
+
+ [SetUp]
+ public void SetUp ()
+ {
+ _settings = new Settings();
+ _settings.Preferences.HighlightCustomColors = [0x00102030];
+ var config = new Mock();
+ _ = config.SetupGet(c => c.Settings).Returns(_settings);
+
+ _source = new HighlightEntry
+ {
+ SearchText = "ERR.*",
+ IsRegex = true,
+ IsCaseSensitive = true,
+ ForegroundColor = Color.Red,
+ BackgroundColor = Color.Yellow,
+ IsBold = true,
+ IsSetBookmark = true,
+ BookmarkComment = "note",
+ IsActionEntry = true,
+ ActionEntry = new ActionEntry { PluginName = "plugin", ActionParam = "param" },
+ AlertOnHit = true,
+ CooldownSeconds = 7,
+ };
+
+ _dialog = new HighlightDialog(config.Object)
+ {
+ HighlightGroupList = [new HighlightGroup { GroupName = "G", HighlightEntryList = [_source] }],
+ PreSelectedGroupName = "G",
+ };
+ _dialog.Show();
+ // Shown, which fills the entry list, is posted rather than raised by Show().
+ Application.DoEvents();
+ // The dialog edits clones of the groups it is given.
+ _source = Entries[0];
+ }
+
+ [TearDown]
+ public void TearDown ()
+ {
+ _dialog.Dispose();
+ }
+
+ private List Entries => _dialog.HighlightGroupList[0].HighlightEntryList;
+
+ private ListBox List => Find("listBoxHighlight");
+
+ [Test]
+ public void Copy_IsDisabledWithoutASelectedEntry ()
+ {
+ List.SelectedIndex = -1;
+ Assert.That(Find