Skip to content

Commit

Permalink
Make open/save file dialog settings more consistent
Browse files Browse the repository at this point in the history
  • Loading branch information
mysteryx93 committed Jul 1, 2022
1 parent fa508a3 commit 617e20f
Show file tree
Hide file tree
Showing 10 changed files with 22 additions and 180 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

All notable changes to this project will be documented in this file.

## 1.3.1
## 1.3.1 - 2022-07-01

- File dialog filters can now take extensions with or without the dot
- FluentAvalonia TaskDialog now supports default buttons
- Handle the following settings in Avalonia framework dialogs: DefaultExtension, CheckFileExists, CheckPathExists, CreatePrompt, OverwritePrompt.
- Open/save file framework dialog settings are now more consistent in Avalonia and WPF

## 1.3.0 - 2022-06-16

Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -452,12 +452,10 @@ Here are the differences:
## Contributions Are Welcomed

Todo:
- Avalonia Open/Save dialogs need to display validation messages based on settings.
- Implement for WinUI 3 (I'll leave this task to someone who is going to use it)
- Implement for Blazor (I'm excited about this one)
- Implement for UWP (this thing is dead... not worth implementing IMO)
- Unit tests? (with extensive demos, this might be duplicate and overkill)
- Automated builds
- Implement for Blazor?
- Automated builds?

### Author

Expand Down
5 changes: 1 addition & 4 deletions samples/Avalonia/Demo.OpenFileDialog/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ private async Task OpenFilesAsync()
".exe", ".dll"
}),
new FileFilter("All Files", "*")
},
CheckFileExists = true,
CheckPathExists = true,
DefaultExtension = ".mp3"
}
};
}
5 changes: 2 additions & 3 deletions samples/Avalonia/Demo.SaveFileDialog/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ private async Task SaveFileAsync()
InitialDirectory = IOPath.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!,
Filters = new List<FileFilter>()
{
new FileFilter("Text Documents", "txt"),
new FileFilter("Text Documents", new[] { "txt", "md" }),
new FileFilter("All Files", "*")
},
CreatePrompt = true,
DefaultExtension = ".mp3"
DefaultExtension = "mp3"
};

var result = await dialogService.ShowSaveFileDialogAsync(this, settings);
Expand Down
2 changes: 1 addition & 1 deletion samples/Wpf/Demo.OpenFileDialog/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Threading.Tasks;
Expand Down
137 changes: 7 additions & 130 deletions src/MvvmDialogs.Avalonia/DialogFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,27 +68,7 @@ private async Task<string[]> ShowOpenFileDialogAsync(WindowWrapper owner, OpenFi
};
AddSharedSettings(apiSettings, settings);

string[] result;
bool resultValid;
do
{
resultValid = true;
result = await _api.ShowOpenFileDialogAsync(owner.Ref, apiSettings).ConfigureAwait(true) ?? Array.Empty<string>();
for (var i = 0; i < result.Length; i++)
{
// Work around the limitation that async method cannot return ref. We may add DefaultExtension to the result.
var refItem = new RefClass<string>(result[i]);
resultValid = await CheckResultAsync(owner, refItem, settings, appSettings).ConfigureAwait(true);
result[i] = refItem.Value;
if (!resultValid)
{
apiSettings.InitialFileName = result[i];
break;
}
}
} while (!resultValid);

return result;
return await _api.ShowOpenFileDialogAsync(owner.Ref, apiSettings).ConfigureAwait(true) ?? Array.Empty<string>();
}

private async Task<string?> ShowSaveFileDialogAsync(WindowWrapper owner, SaveFileDialogSettings settings, AppDialogSettings appSettings)
Expand All @@ -99,26 +79,13 @@ private async Task<string[]> ShowOpenFileDialogAsync(WindowWrapper owner, OpenFi
};
AddSharedSettings(apiSettings, settings);

string? result;
bool resultValid;
do
{
resultValid = true;
result = await _api.ShowSaveFileDialogAsync(owner.Ref, apiSettings).ConfigureAwait(true);
if (result != null)
{
// Work around the limitation that async method cannot return ref. We may add DefaultExtension to the result.
var refItem = new RefClass<string>(result);
resultValid = await CheckResultAsync(owner, refItem, settings, appSettings).ConfigureAwait(true);
result = refItem.Value;
if (!resultValid)
{
apiSettings.InitialFileName = result;
apiSettings.Directory = Path.GetDirectoryName(result);
}
}
} while (!resultValid);
var result = await _api.ShowSaveFileDialogAsync(owner.Ref, apiSettings).ConfigureAwait(true);

// Add DefaultExtension.
if (result != null && !string.IsNullOrEmpty(settings.DefaultExtension) && !_pathInfo.GetFileInfo(result).Exists && !result.Contains('.'))
{
result += "." + settings.DefaultExtension.TrimStart('.');
}
return result;
}

Expand All @@ -138,94 +105,4 @@ private static List<FileDialogFilter> SyncFilters(List<FileFilter> filters) =>
Name = x.NameToString(x.ExtensionsToString()),
Extensions = x.Extensions.Select(y => y.TrimStart('.')).ToList()
}).ToList();

private async Task<bool> CheckResultAsync(WindowWrapper owner, RefClass<string> value, FileDialogSettings settings, AppDialogSettings appSettings)
{
var fileInfo = _pathInfo.GetFileInfo(value.Value);

// DefaultExtension.
if (!string.IsNullOrEmpty(settings.DefaultExtension) && !fileInfo.Exists && !value.Value.Contains('.'))
{
value.Value += "." + settings.DefaultExtension.TrimStart('.');
fileInfo = _pathInfo.GetFileInfo(value.Value);
}

// CheckFileExists.
if (settings.CheckFileExists && !fileInfo.Exists)
{
var msgSettings = new MessageBoxSettings()
{
Title = "File Not Found",
Text = "Selected file does not exist:" + Environment.NewLine + value.Value,
Icon = MessageBoxImage.Exclamation
};
await ChainTop.ShowDialogAsync(owner, msgSettings, appSettings).ConfigureAwait(true);
return false;
}

// CheckPathExists.
var path = Path.GetDirectoryName(value.Value)!;
var pathInfo = _pathInfo.GetDirectoryInfo(path);
if (settings.CheckPathExists && !pathInfo.Exists)
{
var msgSettings = new MessageBoxSettings()
{
Title = "Folder Not Found",
Text = "Selected folder does not exist." + Environment.NewLine + path,
Icon = MessageBoxImage.Exclamation
};
await ChainTop.ShowDialogAsync(owner, msgSettings, appSettings).ConfigureAwait(true);
return false;
}

if (settings is SaveFileDialogSettings saveSettings)
{
// CreatePrompt.
if (saveSettings.CreatePrompt && !fileInfo.Exists)
{
var msgSettings = new MessageBoxSettings()
{
Title = "Create Confirmation",
Text = "File doesn't exist, do you want to create it?" + Environment.NewLine + value.Value,
Button = MessageBoxButton.YesNo,
DefaultValue = true
};
var result = (bool?)await ChainTop.ShowDialogAsync(owner, msgSettings, appSettings).ConfigureAwait(true);
if (result != true)
{
return false;
}
}

// OverwritePrompt.
if (saveSettings.OverwritePrompt && fileInfo.Exists)
{
var msgSettings = new MessageBoxSettings()
{
Title = "Overwrite Confirmation",
Text = "File already exists, do you want to overwrite it?" + Environment.NewLine + value.Value,
Button = MessageBoxButton.YesNo,
DefaultValue = true
};
var result = (bool?)await ChainTop.ShowDialogAsync(owner, msgSettings, appSettings).ConfigureAwait(true);
if (result != true)
{
return false;
}
}
}

return true;
}

/// <summary>
/// Works around the limitation that async method cannot return ref parameter. Classes are by reference.
/// </summary>
/// <typeparam name="T">The data type to pass by reference.</typeparam>
private class RefClass<T>
{
public RefClass(T value) => Value = value;

public T Value { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/MvvmDialogs.Wpf/Api/SaveFileApiSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace HanumanInstitute.MvvmDialogs.Wpf.Api;
internal class SaveFileApiSettings : FileApiSettings
{
public bool CreatePrompt { get; set; }
public bool OverwritePrompt { get; set; }
public bool OverwritePrompt { get; set; } = true;

internal void ApplyTo(System.Windows.Forms.SaveFileDialog d)
{
Expand Down
9 changes: 2 additions & 7 deletions src/MvvmDialogs.Wpf/DialogFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ private string[] ShowOpenFileDialog(WindowWrapper owner, OpenFileDialogSettings
{
var apiSettings = new OpenFileApiSettings()
{
CheckFileExists = true,
Multiselect = settings.AllowMultiple ?? false,
ReadOnlyChecked = settings.ReadOnlyChecked,
ShowReadOnly = settings.ShowReadOnly
Expand All @@ -92,9 +93,7 @@ private string[] ShowOpenFileDialog(WindowWrapper owner, OpenFileDialogSettings
{
var apiSettings = new SaveFileApiSettings()
{
CheckFileExists = settings.CheckFileExists,
CreatePrompt = settings.CreatePrompt,
OverwritePrompt = settings.OverwritePrompt
DefaultExt = settings.DefaultExtension
};
AddSharedSettings(apiSettings, settings);

Expand All @@ -103,10 +102,6 @@ private string[] ShowOpenFileDialog(WindowWrapper owner, OpenFileDialogSettings

private void AddSharedSettings(FileApiSettings d, FileDialogSettings s)
{
d.DefaultExt = s.DefaultExtension;
d.AddExtension = !string.IsNullOrEmpty(s.DefaultExtension);
d.CheckFileExists = s.CheckFileExists;
d.CheckPathExists = s.CheckPathExists;
d.InitialDirectory = s.InitialDirectory;
d.FileName = s.InitialFile;
d.DereferenceLinks = s.DereferenceLinks;
Expand Down
18 changes: 0 additions & 18 deletions src/MvvmDialogs/FrameworkDialogs/FileDialogSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,6 @@ namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs;
/// </summary>
public abstract class FileDialogSettings : DialogSettingsBase
{
/// <summary>
/// Gets or sets the default extension to be used (including the period ".")
/// if not set by the user or by a filter
/// </summary>
public string DefaultExtension { get; set; } = string.Empty;

/// <summary>
/// Gets or sets a value indicating whether a file dialog displays a warning if the user
/// specifies a file name that does not exist.
/// </summary>
public bool CheckFileExists { get; set; } = false;

/// <summary>
/// Gets or sets a value that specifies whether warnings are displayed if the user types
/// invalid paths and file names.
/// </summary>
public bool CheckPathExists { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether a file dialog returns either the location of
/// the file referenced by a shortcut or the location of the shortcut file (.lnk).
Expand Down
14 changes: 4 additions & 10 deletions src/MvvmDialogs/FrameworkDialogs/SaveFileDialogSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,8 @@
public class SaveFileDialogSettings : FileDialogSettings
{
/// <summary>
/// Gets or sets a value indicating whether the dialog box prompts the user for permission
/// to create a file if the user specifies a file that does not exist.
/// Gets or sets the default extension to be used (including the period ".")
/// if not set by the user or by a filter
/// </summary>
public bool CreatePrompt { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the dialog box displays a warning if the user
/// specifies the name of a file that already exists.
/// </summary>
public bool OverwritePrompt { get; set; }
}
public string DefaultExtension { get; set; } = string.Empty;
}

0 comments on commit 617e20f

Please sign in to comment.