FileSystemInfoStats.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.IO.Abstractions;
  5. using System.Linq;
  6. namespace Terminal.Gui {
  7. /// <summary>
  8. /// Wrapper for <see cref="FileSystemInfo"/> that contains additional information
  9. /// (e.g. <see cref="IsParent"/>) and helper methods.
  10. /// </summary>
  11. internal class FileSystemInfoStats {
  12. /* ---- Colors used by the ls command line tool ----
  13. *
  14. * Blue: Directory
  15. * Green: Executable or recognized data file
  16. * Cyan (Sky Blue): Symbolic link file
  17. * Yellow with black background: Device
  18. * Magenta (Pink): Graphic image file
  19. * Red: Archive file
  20. * Red with black background: Broken link
  21. */
  22. private const long ByteConversion = 1024;
  23. private static readonly string [] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
  24. private static readonly List<string> ImageExtensions = new List<string> { ".JPG", ".JPEG", ".JPE", ".BMP", ".GIF", ".PNG" };
  25. private static readonly List<string> ExecutableExtensions = new List<string> { ".EXE", ".BAT" };
  26. /// <summary>
  27. /// Initializes a new instance of the <see cref="FileSystemInfoStats"/> class.
  28. /// </summary>
  29. /// <param name="fsi">The directory of path to wrap.</param>
  30. public FileSystemInfoStats (IFileSystemInfo fsi)
  31. {
  32. this.FileSystemInfo = fsi;
  33. this.LastWriteTime = fsi.LastWriteTime;
  34. if (fsi is IFileInfo fi) {
  35. this.MachineReadableLength = fi.Length;
  36. this.HumanReadableLength = GetHumanReadableFileSize (this.MachineReadableLength);
  37. this.Type = fi.Extension;
  38. } else {
  39. this.HumanReadableLength = string.Empty;
  40. this.Type = "dir";
  41. }
  42. }
  43. /// <summary>
  44. /// Gets the wrapped <see cref="FileSystemInfo"/> (directory or file).
  45. /// </summary>
  46. public IFileSystemInfo FileSystemInfo { get; }
  47. public string HumanReadableLength { get; }
  48. public long MachineReadableLength { get; }
  49. public DateTime? LastWriteTime { get; }
  50. public string Type { get; }
  51. /// <summary>
  52. /// Gets or Sets a value indicating whether this instance represents
  53. /// the parent of the current state (i.e. "..").
  54. /// </summary>
  55. public bool IsParent { get; internal set; }
  56. public string Name => this.IsParent ? ".." : this.FileSystemInfo.Name;
  57. public bool IsDir ()
  58. {
  59. return this.Type == "dir";
  60. }
  61. public bool IsImage ()
  62. {
  63. return this.FileSystemInfo is FileSystemInfo f &&
  64. ImageExtensions.Contains (
  65. f.Extension,
  66. StringComparer.InvariantCultureIgnoreCase);
  67. }
  68. public bool IsExecutable ()
  69. {
  70. // TODO: handle linux executable status
  71. return this.FileSystemInfo is FileSystemInfo f &&
  72. ExecutableExtensions.Contains (
  73. f.Extension,
  74. StringComparer.InvariantCultureIgnoreCase);
  75. }
  76. internal object GetOrderByValue (FileDialog dlg, string columnName)
  77. {
  78. if (dlg.Style.FilenameColumnName == columnName)
  79. return this.FileSystemInfo.Name;
  80. if (dlg.Style.SizeColumnName == columnName)
  81. return this.MachineReadableLength;
  82. if (dlg.Style.ModifiedColumnName == columnName)
  83. return this.LastWriteTime;
  84. if (dlg.Style.TypeColumnName == columnName)
  85. return this.Type;
  86. throw new ArgumentOutOfRangeException ("Unknown column " + nameof (columnName));
  87. }
  88. internal object GetOrderByDefault ()
  89. {
  90. if (this.IsDir ()) {
  91. return -1;
  92. }
  93. return 100;
  94. }
  95. private static string GetHumanReadableFileSize (long value)
  96. {
  97. if (value < 0) {
  98. return "-" + GetHumanReadableFileSize (-value);
  99. }
  100. if (value == 0) {
  101. return "0.0 bytes";
  102. }
  103. int mag = (int)Math.Log (value, ByteConversion);
  104. double adjustedSize = value / Math.Pow (1000, mag);
  105. return string.Format ("{0:n2} {1}", adjustedSize, SizeSuffixes [mag]);
  106. }
  107. }
  108. }