/// 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 ExcelDataReader;
using System;
using System.IO;
using System.Reflection;
namespace GroundhogApp
{
///
/// Common static methods for GUI.
///
class Utilities
{
///
/// Formats raw byte amounts to appropriate unit (B, KB, MB, GB or TB).
///
/// The number of bytes
/// Bytes formatted to appropriate unit
public static string FormatBytes(long bytes)
{
string[] units = { "B", "KB", "MB", "GB", "TB" };
double amountOf = bytes;
int i;
for (i = 0; i < units.Length && bytes >= 1024; i++, bytes /= 1024)
{
amountOf = bytes / 1024.0;
}
return String.Format("{0:0.00} {1}", amountOf, units[i]);
}
///
/// Returns sortable DateTime with universal time coordinate value.
///
/// Datetime
public static string GetDateTime()
{
return DateTime.Now.ToString("yyyy-MM-dd HH:mm:sszzz");
}
///
/// Retrieves the username from the Windows environment.
///
/// Username of the Windows environment
public static string GetEnvironmentUser()
{
return Environment.UserName;
}
///
/// Copies the specified file to specified destination location.
/// If the file already exists in target destination then just
/// returns the file destination of the file.
///
/// File to be copied
/// Created if the folder doesn't already exist
/// The app folder if not specified
/// The destination of the new file
public static string CopyToFolder(string filePath, string folderName,
string copyPath)
{
string completeFolder = Path.Combine(copyPath, folderName);
Directory.CreateDirectory(completeFolder);
FileInfo fileInfo = new(filePath);
string newFile = completeFolder + "\\" + fileInfo.Name;
try
{
File.Copy(filePath, newFile);
}
catch (IOException)
{
// File already exists, no need to copy.
}
return newFile;
}
///
/// Attempts to select the specified file from the explorer.
///
/// Requested file's path
/// Did the specified file exist
public static bool OpenFolderFileSelected(string filePath)
{
if (File.Exists(filePath))
{
string fullPath = Path.GetFullPath(filePath);
System.Diagnostics.Process.Start("explorer.exe",
string.Format("/select,\"{0}\"", fullPath));
return true;
}
return false;
}
///
/// Attempts to open the folder of the file specified in explorer.
///
/// Requested file's path
/// Did the specified folder exist
public static bool OpenFolder(string filePath)
{
string folderPath = Path.GetDirectoryName(filePath);
if (Directory.Exists(folderPath))
{
System.Diagnostics.Process.Start("explorer.exe", folderPath);
return true;
}
return false;
}
///
/// Attempts to open the file specified.
///
/// Requested file's path
/// Did the specified file exist
public static bool OpenFile(string filePath)
{
if (File.Exists(filePath))
{
System.Diagnostics.Process.Start("explorer.exe", filePath);
return true;
}
return false;
}
///
/// Attempts to open the file from the application location.
///
/// Requested file's path
/// Did the specified file exist
public static bool OpenFileAssembly(string filePath)
{
string completepath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @filePath);
if (File.Exists(completepath))
{
System.Diagnostics.Process.Start("explorer.exe", completepath);
return true;
}
return false;
}
///
/// Reads a .csv file to a jagged array ("array of arrays").
///
/// Requested file's path
/// Array of the .csv values
public static string[,] ReadCSVToMatrix(string filePath, char deselector = '\0')
{
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
char[] candidates;
if (deselector == '\0') candidates
= new char[] { ',', ';', '\t', '|', '#', ' ' };
else candidates = new char[] { deselector };
var conf = new ExcelReaderConfiguration();
conf.AutodetectSeparators = candidates;
string[,] matrix;
using (var stream
= File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using var reader = ExcelReaderFactory.CreateCsvReader(stream, conf);
do
{
matrix = new string[reader.RowCount, reader.FieldCount];
for (int r = 0; r < reader.RowCount; r++)
{
reader.Read();
for (int c = 0; c < reader.FieldCount; c++)
{
string value = reader.GetValue(c)?.ToString().Trim();
matrix[r, c] = value;
}
}
} while (reader.NextResult()); // only one result with csv-files
}
return matrix;
}
///
/// Reads an .xls, .xlsx and .xlsb files and returns an array of two dimensional arrays
/// representing the workbook.
///
/// Requested file's path
/// Jagged array where inner arrays represent workbook sheets
public static string[][,] ReadExcel(string filePath)
{
// Required step for using ExcelReader with .NET Core
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
string[][,] workbook;
using (var stream
= File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
// Auto-detect format, supports:
// - Binary Excel files (2.0-2003 format; *.xls)
// - OpenXml Excel files (2007 format; *.xlsx, *.xlsb)
using var reader = ExcelReaderFactory.CreateReader(stream);
workbook = new string[reader.ResultsCount][,];
int s = 0;
do
{
string[,] sheet = new string[reader.RowCount, reader.FieldCount];
for (int r = 0; r < reader.RowCount; r++)
{
reader.Read();
for (int c = 0; c < reader.FieldCount; c++)
{
string value = reader.GetValue(c)?.ToString().Trim();
sheet[r, c] = value;
}
}
workbook[s] = sheet;
s++;
} while (reader.NextResult());
}
return workbook;
}
///
/// Returns the sheet names in the Excel file.
///
/// Requested file's path
/// Sheet names of the Excel file
public static string[] GetExcelSheetNames(string filePath)
{
string[] sheetNames;
using (var stream = File.Open(filePath, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite))
{
using var reader = ExcelReaderFactory.CreateReader(stream);
sheetNames = new string[reader.ResultsCount];
for (int i = 0; i < reader.ResultsCount; i++)
{
sheetNames[i] = reader.Name;
reader.NextResult();
}
}
return sheetNames;
}
///
/// Makes the header appropriate for a WPF datagrid column name.
/// If the header does not exist, returns specified default header.
///
/// Header to be prepared
/// Default value for a null header
/// Prepared header
public static string PrepareHeader(string header, string defaultHeader)
{
if (header == null) return defaultHeader;
// Replace Dot with similar looking One Dot Leader
header = header.Replace(".", "\x2024");
char[] badCharacters = new char[] { '(', ')', '[', ']', '/', '\\' };
foreach (char c in badCharacters)
{
header = header.Replace(c.ToString(), " ");
}
header = header.Trim();
if (header.Length == 0) return defaultHeader;
return header;
}
}
}