/// Copyright (c) 2021 Iiro Iivanainen, Harri Linna, Jere Pakkanen, Riikka Vilavaara /// /// Permission is hereby granted, free of charge, to any person obtaining /// a copy of this software and associated documentation files (the /// "Software"), to deal in the Software without restriction, including /// without limitation the rights to use, copy, modify, merge, publish, /// distribute, sublicense, and/or sell copies of the Software, and to /// permit persons to whom the Software is furnished to do so, subject to /// the following conditions: /// /// The above copyright notice and this permission notice shall be included /// in all copies or substantial portions of the Software. /// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, /// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF /// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. /// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY /// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, /// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE /// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /// using System; using System.Data; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using ExcelDataReader.Exceptions; using System.IO; namespace GroundhogApp.UserControls { /// /// Interaction logic for DisplayAttachedData.xaml. /// public partial class DisplayAttachedData : UserControl { private string path; private string[][,] excelSheets; private string[,] CSV; public bool FirstRowHeaders { get; set; } public string CustomSeparator { get; set; } public bool AutoDetectSeparator { get; set; } public DisplayAttachedData(String filePath) { InitializeComponent(); DataContext = this; FirstRowHeaders = false; AutoDetectSeparator = true; path = filePath; PathTextBlock.Text = path; TryToOpenFile(); } /// /// Attempts to open the file as an csv, excel, image or text file. /// private void TryToOpenFile() { try { if (!CheckIfFileExists()) return; string ext = Path.GetExtension(path); if (ext.Equals(".csv", StringComparison.OrdinalIgnoreCase)) { if (SeparatorTextBox.Text.Length == 1 && !AutoDetectSeparator) CSV = Utilities.ReadCSVToMatrix(path, (char)SeparatorTextBox.Text[0]); else CSV = Utilities.ReadCSVToMatrix(path); HeaderCheckBox.Visibility = Visibility.Visible; AutoDetectCheckBox.Visibility = Visibility.Visible; SeparatorSelection.Visibility = Visibility.Visible; PopulateDatagrid(CSV); return; } var supportedExcelFormats = new[] { ".xlsx", ".xlsb", ".xls" }; if (supportedExcelFormats.Contains(ext, StringComparer.OrdinalIgnoreCase)) { excelSheets = Utilities.ReadExcel(path); PopulateDatagrid(excelSheets[0]); SheetNames = Utilities.GetExcelSheetNames(path); SheetComboBox.Visibility = Visibility.Visible; HeaderCheckBox.Visibility = Visibility.Visible; return; } var supportedImageFormats = new[] {".bmp", ".gif", ".ico", ".jpg", ".jpeg", ".png", ".tif", ".tiff"}; if (supportedImageFormats.Contains(ext, StringComparer.OrdinalIgnoreCase)) { var image = new BitmapImage(); image.BeginInit(); image.CreateOptions = BitmapCreateOptions.IgnoreImageCache; image.CacheOption = BitmapCacheOption.OnLoad; image.UriSource = new Uri(path); image.EndInit(); Image.Source = image; Image.Visibility = Visibility.Visible; return; } // If the file is neither a spreadsheet nor an image read it as text. TextBox.Text = File.ReadAllText(path); TextBox.Visibility = Visibility.Visible; } // If an image or Excel file failed to be read or ReadAllText failed. catch(Exception e) when ( e is NotSupportedException or ExcelReaderException or IOException) { ErrorTextBlock.Text = "Failed to open attached data file \"" + path + "\". " + e.Message.ToString(); } } /// /// Populates a datagrid with given 2D matrix. /// /// 2D matrix values private void PopulateDatagrid(String[,] values) { var dt = new DataTable(); int nCol = values.GetLength(1); int nRow = values.GetLength(0); int r = 0; // The row where you start reading the table as data. string defaultHeader = "Column"; // Should be a trimmed string without forbidden header characters // "( ) [ ] / \ .". if (FirstRowHeaders) { for (int h = 0; h < nCol; h++) { string colName = values[0, h]; colName = Utilities.PrepareHeader(colName, defaultHeader) + " (" + (h + 1) + ")"; // All headers should be unique with (i) value at the end. dt.Columns.Add(colName, typeof(string)); } r = 1; // First row isn't read as data. } else { for (int h = 0; h < nCol; h++) { dt.Columns.Add(defaultHeader + " (" + (h + 1) + ")", typeof(string)); // Define column name and type. } } for (; r < nRow; r++) { DataRow dr = dt.NewRow(); for (int c = 0; c < nCol; c++) { dr[c] = values[r, c]; } dt.Rows.Add(dr); } DataGrid.ItemsSource = dt.DefaultView; DataGrid.Visibility = Visibility.Visible; } /// /// Resets the visibility of attached data displaying elements. /// private void ResetView() { Image.Visibility = Visibility.Hidden; DataGrid.Visibility = Visibility.Hidden; TextBox.Visibility = Visibility.Hidden; ShowReloadPrompt(false); SheetComboBox.SelectedIndex = 0; CheckIfFileExists(); } /// /// Informs the user if the filepath does not point to a file. /// /// Does the file exist. private bool CheckIfFileExists() { ErrorTextBlock.Text = ""; if (!File.Exists(path)) { ErrorTextBlock.Text = "File does not exists in the specified location \"" + path + "\"."; PathTextBlock.Foreground = Brushes.Red; return false; } PathTextBlock.Foreground = Brushes.Blue; return true; } /// /// Reloads the attached data. /// /// /// private void ReloadFile(object sender, RoutedEventArgs e) { ResetView(); TryToOpenFile(); } /// /// Opens the file in explorer. /// /// /// private void OpenPath(object sender, RoutedEventArgs e) { Utilities.OpenFolderFileSelected(path); } /// /// Underlying value that the slider is changing. /// public string[] SheetNames { get { return (string[])GetValue(SheetNamesProperty); } set { SetValue(SheetNamesProperty, value); } } public static readonly DependencyProperty SheetNamesProperty = DependencyProperty.Register("SheetNames", typeof(string[]), typeof(DisplayAttachedData), new PropertyMetadata(default(string))); /// /// Selects the Excel sheet to be displayed. /// /// /// private void SheetComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { int i = SheetComboBox.SelectedIndex; if (i > -1) { PopulateDatagrid(excelSheets[i]); } else { SheetComboBox.SelectedIndex = 0; } } /// /// Re-populates the datagrid with Excel or CSV values with first row as /// headers. /// /// /// private void ChangeHeaders(object sender, RoutedEventArgs e) { if (excelSheets == null) { PopulateDatagrid(CSV); return; } int i = SheetComboBox.SelectedIndex; if (i > -1) { // Value of FirstRowAsHeaders changed. PopulateDatagrid(excelSheets[i]); } else { SheetComboBox.SelectedIndex = 0; } } /// /// Enables and disables the custom separator textbox. /// /// /// private void ChangeSeparator(object sender, RoutedEventArgs e) { SeparatorTextBox.IsEnabled = !AutoDetectSeparator; } /// /// If a character is given shows the reload prompt. /// /// /// private void SeparatorTextBoxTextChanged(object sender, RoutedEventArgs e) { if (SeparatorTextBox.Text.Length > 0) ShowReloadPrompt(true); else ShowReloadPrompt(false); } /// /// Shows the reload prompt. /// /// Is the reload prompt showing. private void ShowReloadPrompt(bool show) { if (show) ReloadPrompt.Text = "Reload required"; else ReloadPrompt.Text = ""; } } }