Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 218 additions & 0 deletions src/Myra/Graphics2D/UI/File/FileDialog.PlatformDependent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MonoGame.Utilities;

namespace Myra.Graphics2D.UI.File
{
// === Platform dependent code for FileDialog class
public partial class FileDialog
{
/// <summary>
/// Platform specific code for <see cref="FileDialog"/>
/// </summary>
protected static class Platform
{
private static IReadOnlyList<string> _userPaths;
/// <summary>
/// Return a predetermined list of directories under the user's HOME folder, depending on OS.
/// </summary>
public static IReadOnlyList<string> SystemUserPlacePaths
{
get
{
if (_userPaths == null)
{
switch (CurrentPlatform.OS)
{
case OS.Windows:
_userPaths = _GetWindowsPlaces();
break;
case OS.MacOSX:
_userPaths = _GetWindowsPlaces(); //TODO Mac/OSX specific - using old windows code for now!
break;
case OS.Linux:
_userPaths = _GetLinuxPlaces();
break;
default:
throw new PlatformNotSupportedException(CurrentPlatform.OS.ToString());
}
}
return _userPaths;
}
}

private static string _homePath = string.Empty;
public static string UserHomePath
{
get
{
if (string.IsNullOrEmpty(_homePath))
{
_homePath = (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX)
? Environment.GetEnvironmentVariable("HOME")
: Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");
}
return _homePath;
}
}

private static string _osUser = string.Empty;
/// <summary>
/// Returns the name of the user logged into the system
/// </summary>
public static string SystemUsername
{
get
{
if (string.IsNullOrEmpty(_osUser))
_osUser = UserHomePath.Split(new char[]{Path.DirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries).Last();
return _osUser;
}
}

/// <summary>
/// Append <see cref="Location"/> directories under the user's HOME directory.
/// </summary>
/// <param name="placeList">What folders to try to add relative to the HOME directory.</param>
public static void AppendUserPlacesOnSystem(List<Location> appendResult, IReadOnlyList<string> placeList)
{
ThrowIfNull(appendResult);

string homePath = UserHomePath;
var places = new List<string>(placeList.Count);

// Special label for HOME directory
if (CurrentPlatform.OS != OS.Windows)
appendResult.Add(new Location("Home", SystemUsername, homePath, false ));
else
places.Add(homePath);

foreach (string folder in placeList)
{
places.Add(Path.Combine(homePath, folder));
}

foreach (string path in places)
{
if (!Directory.Exists(path))
continue;

//TODO check permissions for those places here
//Location.TryAccess(path);

appendResult.Add(new Location(string.Empty, Path.GetFileName(path), path, false ));
}
}

/// <summary>
/// Append a list of <see cref="Location"/> for devices we can visit, depending on platform.
/// </summary>
/// <exception cref="PlatformNotSupportedException"></exception>
public static void AppendDrivesOnSystem(List<Location> appendResult)
{
ThrowIfNull(appendResult);

switch (CurrentPlatform.OS)
{
case OS.Windows:
_GetWindowsDrives(appendResult);
return;
case OS.MacOSX:
_GetWindowsDrives(appendResult); //TODO Mac/OSX specific - using old windows code for now!
return;
case OS.Linux:
_GetLinuxDrives(appendResult);
return;
default:
throw new PlatformNotSupportedException(CurrentPlatform.OS.ToString());
}
}

#region Windows
private static void _GetWindowsDrives(List<Location> appendResult)
{
foreach (DriveInfo d in DriveInfo.GetDrives())
{
switch (d.DriveType)
{
case DriveType.CDRom: //Acceptable
case DriveType.Fixed:
case DriveType.Network:
case DriveType.Removable:
break;
case DriveType.NoRootDirectory: //Skip These
case DriveType.Unknown:
case DriveType.Ram:
default:
continue;
}

try
{
string vol = string.Empty;
if (!string.IsNullOrEmpty(d.VolumeLabel) && d.VolumeLabel != d.RootDirectory.FullName)
vol = d.VolumeLabel;

appendResult.Add(new Location(vol, d.Name, d.RootDirectory.FullName, true));
}
catch (Exception)
{
}
}
}
private static IReadOnlyList<string> _GetWindowsPlaces()
{
return new[] { "Desktop", "Downloads", "Documents", "Pictures" };
}
#endregion Windows
#region Linux
private static void _GetLinuxDrives(List<Location> appendResult)
{
string tmpFileName = Path.GetTempFileName();
string[] bashResult;
try
{
// The all caps words after o directly corelate to output string indexes. Some strings may return empty.
BashRunner.Run($"lsblk -no TYPE,NAME,LABEL,MOUNTPOINT --raw > {tmpFileName}");
bashResult = System.IO.File.ReadAllLines(tmpFileName);
}
finally
{
System.IO.File.Delete(tmpFileName);
}

const string RawSpace = @"\x20";
foreach (string deviceLine in bashResult)
{
string[] splits = deviceLine.Split(new[] { ' ' }, StringSplitOptions.None);

if(splits[0] != "part") //TYPE
continue; // We only want partitioned file systems.

splits[2] = splits[2].Replace(RawSpace, " ");
if(string.Equals(splits[2], "System Reserved")) //LABEL
continue;

if(string.IsNullOrEmpty(splits[3]) || string.Equals(splits[3], "/boot"))
continue;
splits[3] = splits[3].Replace(RawSpace, " ");; //MOUNTPOINT

appendResult.Add(new Location(splits[1], splits[2], splits[3], true));
}
}
private static IReadOnlyList<string> _GetLinuxPlaces()
{
return new[] { "Desktop", "Downloads", "Documents", "Pictures" };
}
#endregion Linux

private static void ThrowIfNull(List<Location> obj)
{
if (obj == null)
throw new NullReferenceException();
}
}
}
}
127 changes: 58 additions & 69 deletions src/Myra/Graphics2D/UI/File/FileDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Myra.Graphics2D.UI.File
{
public partial class FileDialog
{
private class PathInfo
protected class PathInfo
{
public string Path { get; }
public bool IsDrive { get; }
Expand All @@ -19,14 +19,33 @@ public PathInfo(string path, bool isDrive)
IsDrive = isDrive;
}
}

private const int ImageTextSpacing = 4;

private static readonly string[] Folders =
/// <summary>
/// Container for info about a browsable file system or device.
/// </summary>
protected class Location
{
"Desktop", "Downloads"
};
public Location(string volume, string label, string path, bool isDrive)
{
VolumeLabel = volume;
Label = label;
Path = path;
IsDrive = isDrive;
}

public readonly string VolumeLabel;
public readonly string Label;
public readonly string Path;
public readonly bool IsDrive;

public bool TryAccess() => TryAccess(this.Path);
public static bool TryAccess(string path)
{
throw new NotImplementedException();
}
}

private const int ImageTextSpacing = 4;

private readonly List<string> _paths = new List<string>();
private readonly List<string> _history = new List<string>();
private int _historyPosition;
Expand Down Expand Up @@ -134,68 +153,16 @@ public FileDialog(FileDialogMode mode) : base(null)
_buttonBack.Background = null;
_buttonForward.Background = null;
_buttonParent.Background = null;
_listPlaces.Background = null;

PopulatePlacesListUI(_listPlaces);

_listPlaces.Background = null;

var homePath = (Environment.OSVersion.Platform == PlatformID.Unix ||
Environment.OSVersion.Platform == PlatformID.MacOSX)
? Environment.GetEnvironmentVariable("HOME")
: Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");

var places = new List<string>
{
homePath
};

foreach (var f in Folders)
{
places.Add(Path.Combine(homePath, f));
}

foreach (var p in places)
{
if (!Directory.Exists(p))
{
continue;
}

var item = CreateListItem(Path.GetFileName(p), p, false);
_listPlaces.Widgets.Add(item);
}

if (_listPlaces.Widgets.Count > 0)
if (_listPlaces.Widgets.Count > 0) //Set starting folder
{
var pathInfo = (PathInfo)_listPlaces.Widgets[0].Tag;
SetFolder(pathInfo.Path, false);
}

_listPlaces.Widgets.Add(new HorizontalSeparator());

var drives = DriveInfo.GetDrives();
foreach (var d in drives)
{
if (d.DriveType == DriveType.Ram || d.DriveType == DriveType.Unknown)
{
continue;
}

try
{
var s = d.RootDirectory.FullName;

if (!string.IsNullOrEmpty(d.VolumeLabel) && d.VolumeLabel != d.RootDirectory.FullName)
{
s += " (" + d.VolumeLabel + ")";
}

var item = CreateListItem(s, d.RootDirectory.FullName, true);
_listPlaces.Widgets.Add(item);
}
catch (Exception)
{
}
}


_listPlaces.SelectedIndexChanged += OnPlacesSelectedIndexChanged;

_gridFiles.SelectedIndexChanged += OnGridFilesSelectedIndexChanged;
Expand All @@ -215,20 +182,42 @@ public FileDialog(FileDialogMode mode) : base(null)
SetStyle(Stylesheet.DefaultStyleName);
}

private static Widget CreateListItem(string text, string path, bool isDrive)
protected virtual void PopulatePlacesListUI(ListView listView)
{
List<Location> placeList = new List<Location>(8);
int index = 0;

//Add user directories
Platform.AppendUserPlacesOnSystem(placeList, Platform.SystemUserPlacePaths);
for (; index < placeList.Count; index++)
listView.Widgets.Add( CreateListItem(placeList[index]) );

if (_listPlaces.Widgets.Count > 0)
listView.Widgets.Add(new HorizontalSeparator());

//Add file system drives
Platform.AppendDrivesOnSystem(placeList);
for (; index < placeList.Count; index++)
listView.Widgets.Add( CreateListItem(placeList[index]) );
}

protected virtual Widget CreateListItem(Location location)
{
var item = new HorizontalStackPanel
{
Spacing = ImageTextSpacing,
Tag = new PathInfo(path, isDrive)
Tag = new PathInfo(location.Path, location.IsDrive)
};

string label = string.IsNullOrEmpty(location.VolumeLabel)
? location.Label
: $"[{location.VolumeLabel}] {location.Label}";

item.Widgets.Add(new Image());
item.Widgets.Add(new Label { Text = text });

item.Widgets.Add(new Label { Text = label });
return item;
}

private void UpdateEnabled()
{
var enabled = false;
Expand Down
Loading
Loading