Browse Source

Merge branch 'v2_develop' into v2_2491-Arrangement-Overlapped

Tig 11 months ago
parent
commit
e8e4305b7b

+ 13 - 12
Terminal.Gui/Drawing/ColorStrings.cs

@@ -1,7 +1,6 @@
 #nullable enable
 using System.Collections;
 using System.Globalization;
-using System.Resources;
 using Terminal.Gui.Resources;
 
 namespace Terminal.Gui;
@@ -11,8 +10,6 @@ namespace Terminal.Gui;
 /// </summary>
 public static class ColorStrings
 {
-    private static readonly ResourceManager _resourceManager = new (typeof (Strings));
-
     /// <summary>
     ///     Gets the W3C standard string for <paramref name="color"/>.
     /// </summary>
@@ -21,7 +18,7 @@ public static class ColorStrings
     public static string? GetW3CColorName (Color color)
     {
         // Fetch the color name from the resource file
-        return _resourceManager.GetString ($"#{color.R:X2}{color.G:X2}{color.B:X2}", CultureInfo.CurrentUICulture);
+        return GlobalResources.GetString ($"#{color.R:X2}{color.G:X2}{color.B:X2}", CultureInfo.CurrentUICulture);
     }
 
     /// <summary>
@@ -30,14 +27,18 @@ public static class ColorStrings
     /// <returns></returns>
     public static IEnumerable<string> GetW3CColorNames ()
     {
-        foreach (DictionaryEntry entry in _resourceManager.GetResourceSet (CultureInfo.CurrentUICulture, true, true)!)
-        {
-            string keyName = entry.Key.ToString () ?? string.Empty;
+        foreach (DictionaryEntry entry in GlobalResources.GetResourceSet (
+                                                                          CultureInfo.CurrentUICulture,
+                                                                          true,
+                                                                          true,
+                                                                          e =>
+                                                                          {
+                                                                              string keyName = e.Key.ToString () ?? string.Empty;
 
-            if (entry.Value is string colorName && keyName.StartsWith ('#'))
-            {
-                yield return colorName;
-            }
+                                                                              return e.Value is string && keyName.StartsWith ('#');
+                                                                          })!)
+        {
+            yield return (entry.Value as string)!;
         }
     }
 
@@ -50,7 +51,7 @@ public static class ColorStrings
     public static bool TryParseW3CColorName (string name, out Color color)
     {
         // Iterate through all resource entries to find the matching color name
-        foreach (DictionaryEntry entry in _resourceManager.GetResourceSet (CultureInfo.CurrentUICulture, true, true)!)
+        foreach (DictionaryEntry entry in GlobalResources.GetResourceSet (CultureInfo.CurrentUICulture, true, true)!)
         {
             if (entry.Value is string colorName && colorName.Equals (name, StringComparison.OrdinalIgnoreCase))
             {

+ 70 - 0
Terminal.Gui/Resources/GlobalResources.cs

@@ -0,0 +1,70 @@
+#nullable enable
+
+using System.Collections;
+using System.Globalization;
+using System.Resources;
+
+namespace Terminal.Gui.Resources;
+
+/// <summary>
+///     Provide static access to the ResourceManagerWrapper
+/// </summary>
+public static class GlobalResources
+{
+    private static readonly ResourceManagerWrapper _resourceManagerWrapper;
+
+    static GlobalResources ()
+    {
+        // Initialize the ResourceManagerWrapper once
+        var resourceManager = new ResourceManager (typeof (Strings));
+        _resourceManagerWrapper = new (resourceManager);
+    }
+
+    /// <summary>
+    ///     Looks up a resource value for a particular name.  Looks in the specified CultureInfo, and if not found, all parent
+    ///     CultureInfos.
+    /// </summary>
+    /// <param name="name"></param>
+    /// <param name="culture"></param>
+    /// <returns>Null if the resource was not found in the current culture or the invariant culture.</returns>
+    public static object GetObject (string name, CultureInfo culture = null!) { return _resourceManagerWrapper.GetObject (name, culture); }
+
+    /// <summary>
+    ///     Looks up a set of resources for a particular CultureInfo. This is not useful for most users of the ResourceManager
+    ///     - call GetString() or GetObject() instead. The parameters let you control whether the ResourceSet is created if it
+    ///     hasn't yet been loaded and if parent CultureInfos should be loaded as well for resource inheritance.
+    /// </summary>
+    /// <param name="culture"></param>
+    /// <param name="createIfNotExists"></param>
+    /// <param name="tryParents"></param>
+    /// <returns></returns>
+    public static ResourceSet? GetResourceSet (CultureInfo culture, bool createIfNotExists, bool tryParents)
+    {
+        return _resourceManagerWrapper.GetResourceSet (culture, createIfNotExists, tryParents)!;
+    }
+
+    /// <summary>
+    ///     Looks up a set of resources for a particular CultureInfo. This is not useful for most users of the ResourceManager
+    ///     - call GetString() or GetObject() instead. The parameters let you control whether the ResourceSet is created if it
+    ///     hasn't yet been loaded and if parent CultureInfos should be loaded as well for resource inheritance. Allows
+    ///     filtering of resources.
+    /// </summary>
+    /// <param name="culture"></param>
+    /// <param name="createIfNotExists"></param>
+    /// <param name="tryParents"></param>
+    /// <param name="filter"></param>
+    /// <returns></returns>
+    public static ResourceSet? GetResourceSet (CultureInfo culture, bool createIfNotExists, bool tryParents, Func<DictionaryEntry, bool>? filter)
+    {
+        return _resourceManagerWrapper.GetResourceSet (culture, createIfNotExists, tryParents, filter)!;
+    }
+
+    /// <summary>
+    ///     Looks up a resource value for a particular name. Looks in the specified CultureInfo, and if not found, all parent
+    ///     CultureInfos.
+    /// </summary>
+    /// <param name="name"></param>
+    /// <param name="culture"></param>
+    /// <returns>Null if the resource was not found in the current culture or the invariant culture.</returns>
+    public static string GetString (string name, CultureInfo? culture = null!) { return _resourceManagerWrapper.GetString (name, culture); }
+}

+ 112 - 0
Terminal.Gui/Resources/ResourceManagerWrapper.cs

@@ -0,0 +1,112 @@
+#nullable enable
+
+using System.Collections;
+using System.Globalization;
+using System.Resources;
+
+namespace Terminal.Gui.Resources;
+
+internal class ResourceManagerWrapper (ResourceManager resourceManager)
+{
+    private readonly ResourceManager _resourceManager = resourceManager ?? throw new ArgumentNullException (nameof (resourceManager));
+
+    // Optionally, expose other ResourceManager methods as needed
+    public object GetObject (string name, CultureInfo culture = null!)
+    {
+        object value = _resourceManager.GetObject (name, culture)!;
+
+        if (Equals (culture, CultureInfo.InvariantCulture))
+        {
+            return value;
+        }
+
+        if (value is null)
+        {
+            value = _resourceManager.GetObject (name, CultureInfo.InvariantCulture)!;
+        }
+
+        return value;
+    }
+
+    public ResourceSet? GetResourceSet (CultureInfo culture, bool createIfNotExists, bool tryParents)
+    {
+        ResourceSet value = _resourceManager.GetResourceSet (culture, createIfNotExists, tryParents)!;
+
+        if (Equals (culture, CultureInfo.InvariantCulture))
+        {
+            return value;
+        }
+
+        if (value!.Cast<DictionaryEntry> ().Any ())
+        {
+            value = _resourceManager.GetResourceSet (CultureInfo.InvariantCulture, createIfNotExists, tryParents)!;
+        }
+
+        return value;
+    }
+
+    public ResourceSet? GetResourceSet (CultureInfo culture, bool createIfNotExists, bool tryParents, Func<DictionaryEntry, bool>? filter)
+    {
+        ResourceSet value = _resourceManager.GetResourceSet (culture, createIfNotExists, tryParents)!;
+
+        IEnumerable<DictionaryEntry> filteredEntries = value.Cast<DictionaryEntry> ().Where (filter ?? (_ => true));
+
+        ResourceSet? filteredValue = ConvertToResourceSet (filteredEntries);
+
+        if (Equals (culture, CultureInfo.InvariantCulture))
+        {
+            return filteredValue;
+        }
+
+        if (!filteredValue!.Cast<DictionaryEntry> ().Any ())
+        {
+            filteredValue = GetResourceSet (CultureInfo.InvariantCulture, createIfNotExists, tryParents, filter)!;
+        }
+
+        return filteredValue;
+    }
+
+    public string GetString (string name, CultureInfo? culture = null!)
+    {
+        // Attempt to get the string for the specified culture
+        string value = _resourceManager.GetString (name, culture)!;
+
+        // If it's already using the invariant culture return
+        if (Equals (culture, CultureInfo.InvariantCulture))
+        {
+            return value;
+        }
+
+        // If the string is empty or null, fall back to the invariant culture
+        if (string.IsNullOrEmpty (value))
+        {
+            value = _resourceManager.GetString (name, CultureInfo.InvariantCulture)!;
+        }
+
+        return value;
+    }
+
+    private static ResourceSet? ConvertToResourceSet (IEnumerable<DictionaryEntry> entries)
+    {
+        using var memoryStream = new MemoryStream ();
+
+        using var resourceWriter = new ResourceWriter (memoryStream);
+
+        // Add each DictionaryEntry to the ResourceWriter
+        foreach (DictionaryEntry entry in entries)
+        {
+            resourceWriter.AddResource ((string)entry.Key, entry.Value);
+        }
+
+        // Finish writing to the stream
+        resourceWriter.Generate ();
+
+        // Reset the stream position to the beginning
+        memoryStream.Position = 0;
+
+        // Create a ResourceSet from the MemoryStream
+        var resourceSet = new ResourceSet (memoryStream);
+
+        return resourceSet;
+    }
+}

+ 4 - 4
Terminal.Gui/Views/HistoryTextItem.cs → Terminal.Gui/Views/HistoryTextItemEventArgs.cs

@@ -4,23 +4,23 @@ namespace Terminal.Gui;
 
 internal partial class HistoryText
 {
-    public class HistoryTextItem : EventArgs
+    public class HistoryTextItemEventArgs : EventArgs
     {
         public Point CursorPosition;
         public Point FinalCursorPosition;
         public bool IsUndoing;
         public List<List<RuneCell>> Lines;
         public LineStatus LineStatus;
-        public HistoryTextItem RemovedOnAdded;
+        public HistoryTextItemEventArgs RemovedOnAdded;
 
-        public HistoryTextItem (List<List<RuneCell>> lines, Point curPos, LineStatus linesStatus)
+        public HistoryTextItemEventArgs (List<List<RuneCell>> lines, Point curPos, LineStatus linesStatus)
         {
             Lines = lines;
             CursorPosition = curPos;
             LineStatus = linesStatus;
         }
 
-        public HistoryTextItem (HistoryTextItem historyTextItem)
+        public HistoryTextItemEventArgs (HistoryTextItemEventArgs historyTextItem)
         {
             Lines = new List<List<RuneCell>> (historyTextItem.Lines);
             CursorPosition = new Point (historyTextItem.CursorPosition.X, historyTextItem.CursorPosition.Y);

+ 1 - 1
Terminal.Gui/Views/TableView/DataTableSource.cs

@@ -25,5 +25,5 @@ public class DataTableSource : ITableSource
     public int Columns => DataTable.Columns.Count;
 
     /// <inheritdoc/>
-    public string [] ColumnNames => DataTable.Columns.Cast<DataColumn> ().Select (c => c.ColumnName).ToArray ();
+    public string [] ColumnNames => DataTable.Columns.Cast<DataColumn> ().Select (c => c.Caption).ToArray ();
 }

+ 2 - 2
Terminal.Gui/Views/TextField.cs

@@ -593,7 +593,7 @@ public class TextField : View
         SetNeedsDisplay ();
     }
 
-    /// <summary>Allows clearing the <see cref="HistoryText.HistoryTextItem"/> items updating the original text.</summary>
+    /// <summary>Allows clearing the <see cref="HistoryText.HistoryTextItemEventArgs"/> items updating the original text.</summary>
     public void ClearHistoryChanges () { _historyText.Clear (Text); }
 
     /// <summary>Copy the selected text to the clipboard.</summary>
@@ -1390,7 +1390,7 @@ public class TextField : View
         return new Attribute (cs.Disabled.Foreground, cs.Focus.Background);
     }
 
-    private void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItem obj)
+    private void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItemEventArgs obj)
     {
         if (obj is null)
         {

+ 9 - 9
Terminal.Gui/Views/TextView.cs

@@ -1269,7 +1269,7 @@ internal partial class HistoryText
         Added
     }
 
-    private readonly List<HistoryTextItem> _historyTextItems = new ();
+    private readonly List<HistoryTextItemEventArgs> _historyTextItems = new ();
     private int _idxHistoryText = -1;
     private string? _originalText;
     public bool HasHistoryChanges => _idxHistoryText > -1;
@@ -1304,7 +1304,7 @@ internal partial class HistoryText
         _idxHistoryText++;
     }
 
-    public event EventHandler<HistoryTextItem>? ChangeText;
+    public event EventHandler<HistoryTextItemEventArgs>? ChangeText;
 
     public void Clear (string text)
     {
@@ -1324,7 +1324,7 @@ internal partial class HistoryText
 
             _idxHistoryText++;
 
-            var historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]) { IsUndoing = false };
+            var historyTextItem = new HistoryTextItemEventArgs (_historyTextItems [_idxHistoryText]) { IsUndoing = false };
 
             ProcessChanges (ref historyTextItem);
 
@@ -1334,7 +1334,7 @@ internal partial class HistoryText
 
     public void ReplaceLast (List<List<RuneCell>> lines, Point curPos, LineStatus lineStatus)
     {
-        HistoryTextItem? found = _historyTextItems.FindLast (x => x.LineStatus == lineStatus);
+        HistoryTextItemEventArgs? found = _historyTextItems.FindLast (x => x.LineStatus == lineStatus);
 
         if (found is { })
         {
@@ -1351,7 +1351,7 @@ internal partial class HistoryText
 
             _idxHistoryText--;
 
-            var historyTextItem = new HistoryTextItem (_historyTextItems [_idxHistoryText]) { IsUndoing = true };
+            var historyTextItem = new HistoryTextItemEventArgs (_historyTextItems [_idxHistoryText]) { IsUndoing = true };
 
             ProcessChanges (ref historyTextItem);
 
@@ -1359,9 +1359,9 @@ internal partial class HistoryText
         }
     }
 
-    private void OnChangeText (HistoryTextItem? lines) { ChangeText?.Invoke (this, lines!); }
+    private void OnChangeText (HistoryTextItemEventArgs? lines) { ChangeText?.Invoke (this, lines!); }
 
-    private void ProcessChanges (ref HistoryTextItem historyTextItem)
+    private void ProcessChanges (ref HistoryTextItemEventArgs historyTextItem)
     {
         if (historyTextItem.IsUndoing)
         {
@@ -2869,7 +2869,7 @@ public class TextView : View
     }
 
 
-    /// <summary>Allows clearing the <see cref="HistoryText.HistoryTextItem"/> items updating the original text.</summary>
+    /// <summary>Allows clearing the <see cref="HistoryText.HistoryTextItemEventArgs"/> items updating the original text.</summary>
     public void ClearHistoryChanges () { _historyText?.Clear (Text); }
 
     /// <summary>Closes the contents of the stream into the <see cref="TextView"/>.</summary>
@@ -4665,7 +4665,7 @@ public class TextView : View
         return new ValueTuple<int, int> (line, col);
     }
 
-    private void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItem obj)
+    private void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItemEventArgs obj)
     {
         SetWrapModel ();
 

+ 165 - 0
UnitTests/Resources/ResourceManagerTests.cs

@@ -0,0 +1,165 @@
+#nullable enable
+
+using System.Collections;
+using System.Globalization;
+using System.Resources;
+using Terminal.Gui.Resources;
+
+namespace Terminal.Gui.ResourcesTests;
+
+public class ResourceManagerTests
+{
+    private const string DODGER_BLUE_COLOR_KEY = "#1E90FF";
+    private const string DODGER_BLUE_COLOR_NAME = "DodgerBlue";
+    private const string EXISTENT_CULTURE = "pt-PT";
+    private const string NO_EXISTENT_CULTURE = "de-DE";
+    private const string NO_EXISTENT_KEY = "blabla";
+    private const string NO_TRANSLATED_KEY = "fdDeleteTitle";
+    private const string NO_TRANSLATED_VALUE = "Delete {0}";
+    private const string TRANSLATED_KEY = "ctxSelectAll";
+    private const string TRANSLATED_VALUE = "_Selecionar Tudo";
+    private static readonly string _stringsNoTranslatedKey = Strings.fdDeleteTitle;
+    private static readonly string _stringsTranslatedKey = Strings.ctxSelectAll;
+    private static readonly CultureInfo _savedCulture = CultureInfo.CurrentCulture;
+    private static readonly CultureInfo _savedUICulture = CultureInfo.CurrentUICulture;
+
+    [Fact]
+    public void GetObject_Does_Not_Overflows_If_Key_Does_Not_Exist () { Assert.Null (GlobalResources.GetObject (NO_EXISTENT_KEY, CultureInfo.CurrentCulture)); }
+
+    [Fact]
+    public void GetObject_FallBack_To_Default_For_No_Existent_Culture_File ()
+    {
+        CultureInfo.CurrentCulture = new (NO_EXISTENT_CULTURE);
+        CultureInfo.CurrentUICulture = new (NO_EXISTENT_CULTURE);
+
+        Assert.Equal (NO_TRANSLATED_VALUE, GlobalResources.GetObject (NO_TRANSLATED_KEY, CultureInfo.CurrentCulture));
+
+        RestoreCurrentCultures ();
+    }
+
+    [Fact]
+    public void GetObject_FallBack_To_Default_For_Not_Translated_Existent_Culture_File ()
+    {
+        CultureInfo.CurrentCulture = new (NO_EXISTENT_CULTURE);
+        CultureInfo.CurrentUICulture = new (NO_EXISTENT_CULTURE);
+
+        Assert.Equal (NO_TRANSLATED_VALUE, GlobalResources.GetObject (NO_TRANSLATED_KEY, CultureInfo.CurrentCulture));
+
+        RestoreCurrentCultures ();
+    }
+
+    [Fact]
+    public void GetResourceSet_FallBack_To_Default_For_No_Existent_Culture_File ()
+    {
+        CultureInfo.CurrentCulture = new (NO_EXISTENT_CULTURE);
+        CultureInfo.CurrentUICulture = new (NO_EXISTENT_CULTURE);
+
+        // W3CColors.GetColorNames also calls ColorStrings.GetW3CColorNames
+        string [] colorNames = new W3CColors ().GetColorNames ().ToArray ();
+        Assert.Contains (DODGER_BLUE_COLOR_NAME, colorNames);
+        Assert.DoesNotContain (NO_TRANSLATED_VALUE, colorNames);
+
+        RestoreCurrentCultures ();
+    }
+
+    [Fact]
+    public void GetResourceSet_FallBack_To_Default_For_Not_Translated_Existent_Culture_File ()
+    {
+        CultureInfo.CurrentCulture = new (EXISTENT_CULTURE);
+        CultureInfo.CurrentUICulture = new (EXISTENT_CULTURE);
+
+        // These aren't already translated
+        // ColorStrings.GetW3CColorNames method uses GetResourceSet method to retrieve color names
+        IEnumerable<string> colorNames = ColorStrings.GetW3CColorNames ();
+        Assert.NotEmpty (colorNames);
+
+        // W3CColors.GetColorNames also calls ColorStrings.GetW3CColorNames
+        colorNames = new W3CColors ().GetColorNames ().ToArray ();
+        Assert.Contains (DODGER_BLUE_COLOR_NAME, colorNames);
+        Assert.DoesNotContain (NO_TRANSLATED_VALUE, colorNames);
+
+        // ColorStrings.TryParseW3CColorName method uses GetResourceSet method to retrieve a color value
+        Assert.True (ColorStrings.TryParseW3CColorName (DODGER_BLUE_COLOR_NAME, out Color color));
+        Assert.Equal (DODGER_BLUE_COLOR_KEY, color.ToString ());
+
+        RestoreCurrentCultures ();
+    }
+
+    [Fact]
+    public void GetResourceSet_With_Filter_Does_Not_Overflows_If_Key_Does_Not_Exist ()
+    {
+        ResourceSet value = GlobalResources.GetResourceSet (CultureInfo.CurrentCulture, true, true, d => (string)d.Key == NO_EXISTENT_KEY)!;
+        Assert.NotNull (value);
+        Assert.Empty (value.Cast<DictionaryEntry> ());
+    }
+
+    [Fact]
+    public void GetResourceSet_Without_Filter_Does_Not_Overflows_If_Key_Does_Not_Exist ()
+    {
+        ResourceSet value = GlobalResources.GetResourceSet (CultureInfo.CurrentCulture, true, true)!;
+        Assert.NotNull (value);
+        Assert.NotEmpty (value.Cast<DictionaryEntry> ());
+    }
+
+    [Fact]
+    public void GetString_Does_Not_Overflows_If_Key_Does_Not_Exist () { Assert.Null (GlobalResources.GetString (NO_EXISTENT_KEY, CultureInfo.CurrentCulture)); }
+
+    [Fact]
+    public void GetString_FallBack_To_Default_For_No_Existent_Culture_File ()
+    {
+        CultureInfo.CurrentCulture = new (NO_EXISTENT_CULTURE);
+        CultureInfo.CurrentUICulture = new (NO_EXISTENT_CULTURE);
+
+        Assert.Equal (NO_TRANSLATED_VALUE, GlobalResources.GetString (NO_TRANSLATED_KEY, CultureInfo.CurrentCulture));
+
+        RestoreCurrentCultures ();
+    }
+
+    [Fact]
+    public void GetString_FallBack_To_Default_For_Not_Translated_Existent_Culture_File ()
+    {
+        CultureInfo.CurrentCulture = new (EXISTENT_CULTURE);
+        CultureInfo.CurrentUICulture = new (EXISTENT_CULTURE);
+
+        // This is really already translated
+        Assert.Equal (TRANSLATED_VALUE, GlobalResources.GetString (TRANSLATED_KEY, CultureInfo.CurrentCulture));
+
+        // These aren't already translated
+        // Calling Strings.fdDeleteBody return always the invariant culture
+        Assert.Equal (NO_TRANSLATED_VALUE, GlobalResources.GetString (NO_TRANSLATED_KEY, CultureInfo.CurrentCulture));
+
+        RestoreCurrentCultures ();
+    }
+
+    [Fact]
+    public void Strings_Always_FallBack_To_Default_For_No_Existent_Culture_File ()
+    {
+        CultureInfo.CurrentCulture = new (NO_EXISTENT_CULTURE);
+        CultureInfo.CurrentUICulture = new (NO_EXISTENT_CULTURE);
+
+        Assert.Equal (NO_TRANSLATED_VALUE, _stringsNoTranslatedKey);
+
+        RestoreCurrentCultures ();
+    }
+
+    [Fact]
+    public void Strings_Always_FallBack_To_Default_For_Not_Translated_Existent_Culture_File ()
+    {
+        CultureInfo.CurrentCulture = new (EXISTENT_CULTURE);
+        CultureInfo.CurrentUICulture = new (EXISTENT_CULTURE);
+
+        // This is really already translated
+        Assert.Equal (TRANSLATED_VALUE, _stringsTranslatedKey);
+
+        // This isn't already translated
+        Assert.Equal (NO_TRANSLATED_VALUE, _stringsNoTranslatedKey);
+
+        RestoreCurrentCultures ();
+    }
+
+    private void RestoreCurrentCultures ()
+    {
+        CultureInfo.CurrentCulture = _savedCulture;
+        CultureInfo.CurrentUICulture = _savedUICulture;
+    }
+}

+ 23 - 0
UnitTests/Views/TableViewTests.cs

@@ -3168,6 +3168,29 @@ A B C
         Assert.Equal (8, tableView.GetAllSelectedCells ().Count ());
     }
 
+    [Fact]
+    public void TestDataColumnCaption()
+    {
+        var tableView = new TableView ();
+
+        var dt = new DataTable ();
+        dt.Columns.Add (new DataColumn ()
+        {
+            Caption = "Caption 1",
+            ColumnName = "Column Name 1"
+        });
+        dt.Columns.Add (new DataColumn ()
+        {
+            ColumnName = "Column Name 2"
+        });
+
+        var dts = new DataTableSource (dt);
+        var cn = dts.ColumnNames;
+
+        Assert.Equal ("Caption 1", cn [0]);
+        Assert.Equal ("Column Name 2", cn [1]);
+    }
+
     private TableView GetABCDEFTableView (out DataTable dt)
     {
         var tableView = new TableView ();