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
20 changes: 13 additions & 7 deletions src/Myra/Graphics2D/UI/File/FileDialog.PlatformDependent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,8 @@ public static void AppendUserPlacesOnSystem(List<Location> appendResult, IReadOn

foreach (string path in places)
{
if (!Directory.Exists(path))
if (!TryGetFileAttributes(path, out _))
continue;

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

appendResult.Add(new Location(string.Empty, Path.GetFileName(path), path, false ));
}
Expand Down Expand Up @@ -191,13 +188,22 @@ private static void _GetLinuxDrives(List<Location> appendResult)
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
splits[2] = splits[2].Replace(RawSpace, " "); //LABEL
if(string.Equals(splits[2], "System Reserved"))
continue;
if (string.IsNullOrEmpty(splits[2]))
{
//Is this the main system partition?
if (string.Equals(splits[3], "/home") || string.Equals(splits[3], "/"))
{
appendResult.Add(new Location(splits[1], "Linux System", "/", true));
continue;
}
}

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

appendResult.Add(new Location(splits[1], splits[2], splits[3], true));
}
Expand Down
83 changes: 83 additions & 0 deletions src/Myra/Graphics2D/UI/File/FileDialog.Util.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.IO;

namespace Myra.Graphics2D.UI.File
{
// === Static file IO utility methods
public partial class FileDialog
{
/// <summary>
/// Attempt to retrieve folders from the given directory <paramref name="path"/>. Result <paramref name="folders"/> is null if return value is false.
/// </summary>
protected static bool TryEnumerateDirectoryFolders(string path, out IEnumerable<string> folders, out string exceptionMsg)
{
List<string> result = new List<string>(8);
try
{
result.AddRange(Directory.EnumerateDirectories(path));
}
catch (Exception e)
{
exceptionMsg = e.Message;
folders = null;
return false;
}
result.Sort();
folders = result;
exceptionMsg = null;
return true;
}

/// <summary>
/// Attempt to retrieve files from the given directory <paramref name="path"/>. Result <paramref name="files"/> is null if return value is false.
/// <paramref name="searchPattern"/> can be null for a wildcard.
/// </summary>
protected static bool TryEnumerateDirectoryFiles(string path, string searchPattern, out IEnumerable<string> files, out string exceptionMsg)
{
List<string> result = new List<string>(8);
try
{
if (string.IsNullOrEmpty(searchPattern))
result.AddRange(Directory.EnumerateFiles(path));
else
{
foreach (string pattern in searchPattern.Split(new char[]{ '|' }, StringSplitOptions.RemoveEmptyEntries))
result.AddRange(Directory.EnumerateFiles(path, pattern));
}
}
catch (Exception e)
{
exceptionMsg = e.Message;
files = null;
return false;
}
result.Sort();
files = result;
exceptionMsg = null;
return true;
}

/// <summary>
/// Attempt to retreive permissions about a file or directory. Return value is indicative of success and a basic attribute filter.
/// </summary>
protected static bool TryGetFileAttributes(string path, out FileAttributes attributes)
{
try
{
attributes = new FileInfo(path).Attributes;
}
catch
{
attributes = 0;
return false;
}

bool discard =
attributes.HasFlag(FileAttributes.System) |
attributes.HasFlag(FileAttributes.Offline);

return !discard;
}
}
}
133 changes: 82 additions & 51 deletions src/Myra/Graphics2D/UI/File/FileDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,6 @@ public Location(string volume, string label, string path, bool isDrive)
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;
Expand Down Expand Up @@ -117,7 +111,8 @@ public string FilePath
}

public bool AutoAddFilterExtension { get; set; }

public bool ShowHiddenFiles { get; set; }

public IImage IconFolder { get; set; }
public IImage IconDrive { get; set; }

Expand Down Expand Up @@ -182,6 +177,9 @@ public FileDialog(FileDialogMode mode) : base(null)
SetStyle(Stylesheet.DefaultStyleName);
}

/// <summary>
/// Create the navigation menu of places we can visit.
/// </summary>
protected virtual void PopulatePlacesListUI(ListView listView)
{
List<Location> placeList = new List<Location>(8);
Expand All @@ -201,6 +199,9 @@ protected virtual void PopulatePlacesListUI(ListView listView)
listView.Widgets.Add( CreateListItem(placeList[index]) );
}

/// <summary>
/// Create a display widget for the given location
/// </summary>
protected virtual Widget CreateListItem(Location location)
{
var item = new HorizontalStackPanel
Expand All @@ -217,6 +218,44 @@ protected virtual Widget CreateListItem(Location location)
item.Widgets.Add(new Label { Text = label });
return item;
}

/// <summary>
/// Return true if <paramref name="path"/> is a valid directory, and we have permissions to access it.
/// </summary>
protected bool TryAccessDirectory(string path)
{
if (!Directory.Exists(path))
return false;
if (!TryGetFileAttributes(path, out FileAttributes att))
return false;
return FileAttributeFilter(att, _mode, ShowHiddenFiles);
}

protected virtual bool FileAttributeFilter(FileAttributes attributes, FileDialogMode mode, bool showHidden)
{
bool discard =
attributes.HasFlag(FileAttributes.System) |
attributes.HasFlag(FileAttributes.Offline) |
(attributes.HasFlag(FileAttributes.Hidden) & !showHidden);

switch (mode)
{
case FileDialogMode.SaveFile:
discard |= attributes.HasFlag(FileAttributes.ReadOnly);
break;
case FileDialogMode.ChooseFolder:
discard |= !attributes.HasFlag(FileAttributes.Directory);
break;
default:
break;
}
return !discard;
}

protected void ShowIOError(string path, string exceptionMsg)
{
CreateMessageBox("I/O Error", exceptionMsg);
}

private void UpdateEnabled()
{
Expand Down Expand Up @@ -279,7 +318,7 @@ private void OnButtonForward(object sender, EventArgs args)

private void SetFolder(string value, bool storeInHistory)
{
if (!Directory.Exists(value))
if (!TryAccessDirectory(value))
{
return;
}
Expand Down Expand Up @@ -362,23 +401,28 @@ private void UpdateFolder()
_paths.Clear();

_scrollPane.ScrollPosition = Mathematics.PointZero;

var path = _textFieldPath.Text;
var folders = Directory.EnumerateDirectories(path);


// Enumerate folders in directory
bool success = TryEnumerateDirectoryFolders(path, out IEnumerable<string> collection, out string exceptionMsg);
if (!success)
{
ShowIOError(path, exceptionMsg);
return;
}

var gridY = 0;
foreach (var f in folders)
foreach (string folder in collection)
{
var fileInfo = new FileInfo(f);
if (fileInfo.Attributes.HasFlag(FileAttributes.Hidden))
{
success = TryGetFileAttributes(folder, out FileAttributes att);
if (success)
success &= FileAttributeFilter(att, _mode, ShowHiddenFiles);
if (!success)
continue;
}

var prop = new Proportion();

_gridFiles.RowsProportions.Add(prop);


_gridFiles.RowsProportions.Add(new Proportion());

var image = new Image
{
Renderable = IconFolder,
Expand All @@ -391,14 +435,14 @@ private void UpdateFolder()

var name = new Label
{
Text = Path.GetFileName(f),
Text = Path.GetFileName(folder),
};
Grid.SetColumn(name, 1);
Grid.SetRow(name, gridY);

_gridFiles.Widgets.Add(name);

_paths.Add(f);
_paths.Add(folder);

++gridY;
}
Expand All @@ -408,47 +452,34 @@ private void UpdateFolder()
return;
}

IEnumerable<string> files;

if (string.IsNullOrEmpty(Filter))
// Enumerate files in directory
success = TryEnumerateDirectoryFiles(path, Filter, out collection, out exceptionMsg);
if (!success)
{
files = Directory.EnumerateFiles(path);
}
else
{
var parts = Filter.Split('|');
var result = new List<string>();

foreach (var part in parts)
{
result.AddRange(Directory.EnumerateFiles(path, part));
}

files = result;
ShowIOError(path, exceptionMsg);
return;
}

foreach (var f in files)
foreach (string file in collection)
{
var fileInfo = new FileInfo(f);
if (fileInfo.Attributes.HasFlag(FileAttributes.Hidden))
{
success = TryGetFileAttributes(file, out FileAttributes att);
if (success)
success &= FileAttributeFilter(att, _mode, ShowHiddenFiles);
if (!success)
continue;
}

var prop = new Proportion();

_gridFiles.RowsProportions.Add(prop);

_gridFiles.RowsProportions.Add(new Proportion());

var name = new Label
{
Text = Path.GetFileName(f),
Text = Path.GetFileName(file),
};
Grid.SetColumn(name, 1);
Grid.SetRow(name, gridY);

_gridFiles.Widgets.Add(name);

_paths.Add(f);
_paths.Add(file);

++gridY;
}
Expand Down Expand Up @@ -536,7 +567,7 @@ public void ApplyFileDialogStyle(FileDialogStyle style)
image.Renderable = pathInfo.IsDrive ? IconDrive : IconFolder;
}
}

protected override void InternalSetStyle(Stylesheet stylesheet, string name)
{
ApplyFileDialogStyle(stylesheet.FileDialogStyles.SafelyGetStyle(name));
Expand Down
3 changes: 3 additions & 0 deletions src/Myra/Myra.MonoGame.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
<Compile Update="Graphics2D\UI\File\FileDialog.PlatformDependent.cs">
<DependentUpon>FileDialog.cs</DependentUpon>
</Compile>
<Compile Update="Graphics2D\UI\File\FileDialog.Util.cs">
<DependentUpon>FileDialog.cs</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
Expand Down
Loading