/// 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 = "";
}
}
}