Refactor shortcut validity

Moved the logic to the right places.
Removed the need for the separate
error and warning lookup arrays.
This commit is contained in:
Terry MacDonald 2021-03-07 13:45:49 +13:00
parent 7b9a676cb6
commit 5260d8a087
4 changed files with 218 additions and 95 deletions

View File

@ -67,6 +67,12 @@ namespace DisplayMagician
public bool GameArgumentsRequired;
}
public struct ShortcutError
{
public string Name;
public ShortcutValidity Validity;
public string Message;
}
public class ShortcutItem : IComparable
{
@ -99,7 +105,8 @@ namespace DisplayMagician
private ShortcutPermanence _audioPermanence = ShortcutPermanence.Temporary;
private ShortcutPermanence _capturePermanence = ShortcutPermanence.Temporary;
private bool _autoName = true;
private bool _isPossible;
private ShortcutValidity _isValid;
private List<ShortcutError> _shortcutErrors = new List<ShortcutError>();
private List<StartProgram> _startPrograms;
private Bitmap _shortcutBitmap, _originalLargeBitmap, _originalSmallBitmap;
[JsonIgnore]
@ -1142,16 +1149,30 @@ namespace DisplayMagician
}
}
[JsonIgnore]
public bool IsPossible
public ShortcutValidity IsValid
{
get
{
return _isPossible;
return _isValid;
}
set
{
_isPossible = value;
_isValid = value;
}
}
[JsonIgnore]
public List<ShortcutError> Errors
{
get
{
return _shortcutErrors;
}
set
{
_shortcutErrors = value;
}
}
@ -1741,7 +1762,8 @@ namespace DisplayMagician
shortcut.OriginalLargeBitmap = OriginalLargeBitmap;
shortcut.ShortcutBitmap = ShortcutBitmap;
shortcut.SavedShortcutIconCacheFilename = SavedShortcutIconCacheFilename;
shortcut.IsPossible = IsPossible;
shortcut.IsValid = IsValid;
shortcut.Errors.AddRange(Errors);
shortcut.StartPrograms = StartPrograms;
shortcut.ChangeAudioDevice = ChangeAudioDevice;
shortcut.AudioDevice = AudioDevice;
@ -1935,21 +1957,35 @@ namespace DisplayMagician
return multiIcon;
}
public (ShortcutValidity, string) IsValid()
public void RefreshValidity()
{
// Do some validation checks to make sure the shortcut is sensible
// And that we have enough to try and action within the shortcut
// (in other words check everything in the shortcut is still valid)
ShortcutValidity worstError = ShortcutValidity.Valid;
// Does the profile we want to Use still exist?
// Is the profile still valid right now? i.e. are all the screens available?
if (ProfileToUse == null)
if (!ProfileRepository.ContainsProfile(ProfileUUID))
{
return (ShortcutValidity.Error, string.Format("The profile does not exist (probably deleted) and cannot be used."));
ShortcutError error = new ShortcutError();
error.Name = "ProfileNotExist";
error.Validity = ShortcutValidity.Error;
error.Message = $"The profile does not exist (probably deleted) and cannot be used.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
if (!ProfileToUse.IsPossible)
// Is the profile still valid right now? i.e. are all the screens available?
if (ProfileToUse != null && !ProfileToUse.IsPossible)
{
return (ShortcutValidity.Warning, string.Format("The profile '{0}' is not valid right now and cannot be used.", ProfileToUse.Name));
ShortcutError error = new ShortcutError();
error.Name = "InvalidProfile";
error.Validity = ShortcutValidity.Warning;
error.Message = $"The profile '{ProfileToUse.Name}' is not valid right now and cannot be used.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Warning;
}
// Is the main application still installed?
if (Category.Equals(ShortcutCategory.Application))
@ -1957,7 +1993,13 @@ namespace DisplayMagician
// We need to check if the Application still exists
if (!System.IO.File.Exists(ExecutableNameAndPath))
{
return (ShortcutValidity.Warning, string.Format("The application executable '{0}' does not exist, or cannot be accessed by DisplayMagician.", ExecutableNameAndPath));
ShortcutError error = new ShortcutError();
error.Name = "InvalidExecutableNameAndPath";
error.Validity = ShortcutValidity.Error;
error.Message = $"The application executable '{ExecutableNameAndPath}' does not exist, or cannot be accessed by DisplayMagician.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
}
@ -1971,34 +2013,55 @@ namespace DisplayMagician
// Check if Steam is installed and error if it isn't
if (!SteamLibrary.IsSteamInstalled)
{
return (ShortcutValidity.Error, Language.Steam_executable_file_not_found);
ShortcutError error = new ShortcutError();
error.Name = "SteamNotInstalled";
error.Validity = ShortcutValidity.Error;
error.Message = $"Steam is not installed on this computer.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
// We need to look up details about the game
if (!SteamLibrary.ContainsSteamGame(GameAppId))
{
return (ShortcutValidity.Error, string.Format("The Steam Game with AppID '{0}' is not installed on this computer.", GameAppId));
ShortcutError error = new ShortcutError();
error.Name = "SteamGameNotInstalled";
error.Validity = ShortcutValidity.Error;
error.Message = $"The Steam Game with AppID '{GameAppId}' is not installed on this computer.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
}
// If the game is a Uplay Game we check for that
else if (GameLibrary.Equals(SupportedGameLibrary.Uplay))
{
// First check if Steam is installed
// Check if Steam is installed and error if it isn't
// First check if Uplay is installed
// Check if Uplay is installed and error if it isn't
if (!UplayLibrary.IsUplayInstalled)
{
return (ShortcutValidity.Error, "Cannot find the Uplay executable! Uplay doesn't appear to be installed");
ShortcutError error = new ShortcutError();
error.Name = "UplayNotInstalled";
error.Validity = ShortcutValidity.Error;
error.Message = $"Uplay is not installed on this computer.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
// We need to look up details about the game
if (!UplayLibrary.ContainsUplayGame(GameAppId))
{
return (ShortcutValidity.Error, string.Format("The Uplay Game with AppID '{0}' is not installed on this computer.", GameAppId));
ShortcutError error = new ShortcutError();
error.Name = "UplayGameNotInstalled";
error.Validity = ShortcutValidity.Error;
error.Message = $"The Uplay Game with AppID '{GameAppId}' is not installed on this computer.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
}
}
// Check the Audio Device is still valid (if one is specified)
if (ChangeAudioDevice)
@ -2010,11 +2073,35 @@ namespace DisplayMagician
if (audioDevice.FullName.Equals(AudioDevice))
{
if (audioDevice.State == AudioSwitcher.AudioApi.DeviceState.Disabled)
return (ShortcutValidity.Warning, $"The Audio Device {AudioDevice} is disabled, so the shortcut '{Name}' cannot be used. You need to enable the audio device to use this shortcut, or edit the shortcut to change the audio device.");
{
ShortcutError error = new ShortcutError();
error.Name = "AudioDeviceDisabled";
error.Validity = ShortcutValidity.Warning;
error.Message = $"The Audio Device { AudioDevice} is disabled, so the shortcut '{Name}' cannot be used.You need to enable the audio device to use this shortcut, or edit the shortcut to change the audio device.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Warning;
}
if (audioDevice.State == AudioSwitcher.AudioApi.DeviceState.NotPresent)
return (ShortcutValidity.Warning, $"The Audio Device {AudioDevice} is not present, so the shortcut '{Name}' cannot be used.");
{
ShortcutError error = new ShortcutError();
error.Name = "AudioDeviceNotPresent";
error.Validity = ShortcutValidity.Error;
error.Message = $"The Audio Device {AudioDevice} is not present, so the shortcut '{Name}' cannot be used.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
if (audioDevice.State == AudioSwitcher.AudioApi.DeviceState.Unplugged)
return (ShortcutValidity.Warning, $"The Audio Device {AudioDevice} is unplugged, so the shortcut '{Name}' cannot be used. You need to plug in the audio device to use this shortcut, or edit the shortcut to change the audio device.");
{
ShortcutError error = new ShortcutError();
error.Name = "AudioDeviceUnplugged";
error.Validity = ShortcutValidity.Warning;
error.Message = $"The Audio Device {AudioDevice} is unplugged, so the shortcut '{Name}' cannot be used. You need to plug in the audio device to use this shortcut, or edit the shortcut to change the audio device.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Warning;
}
}
}
}
@ -2028,18 +2115,43 @@ namespace DisplayMagician
if (captureDevice.FullName.Equals(CaptureDevice))
{
if (captureDevice.State == AudioSwitcher.AudioApi.DeviceState.Disabled)
return (ShortcutValidity.Warning, $"The Capture Device {CaptureDevice} is disabled, so the shortcut '{Name}' cannot be used. You need to enable the capture device to use this shortcut, or edit the shortcut to change the capture device.");
{
ShortcutError error = new ShortcutError();
error.Name = "CaptureDeviceDisabled";
error.Validity = ShortcutValidity.Warning;
error.Message = $"The Capture Device {CaptureDevice} is disabled, so the shortcut '{Name}' cannot be used. You need to enable the capture device to use this shortcut, or edit the shortcut to change the capture device.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Warning;
}
if (captureDevice.State == AudioSwitcher.AudioApi.DeviceState.NotPresent)
return (ShortcutValidity.Warning, $"The Capture Device {CaptureDevice} is not present, so the shortcut '{Name}' cannot be used.");
{
ShortcutError error = new ShortcutError();
error.Name = "CaptureDeviceNotPresent";
error.Validity = ShortcutValidity.Error;
error.Message = $"The Capture Device {CaptureDevice} is not present, so the shortcut '{Name}' cannot be used.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
if (captureDevice.State == AudioSwitcher.AudioApi.DeviceState.Unplugged)
return (ShortcutValidity.Warning, $"The Capture Device {CaptureDevice} is unplugged, so the shortcut '{Name}' cannot be used. You need to plug in the capture device to use this shortcut, or edit the shortcut to change the capture device.");
{
ShortcutError error = new ShortcutError();
error.Name = "CaptureDeviceUnplugged";
error.Validity = ShortcutValidity.Warning;
error.Message = $"The Capture Device {CaptureDevice} is unplugged, so the shortcut '{Name}' cannot be used. You need to plug in the capture device to use this shortcut, or edit the shortcut to change the capture device.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Warning;
}
}
}
}
// TODO Do all the specified pre-start apps still exist?
return (ShortcutValidity.Valid, "Shortcut is valid");
// Save the worst error level to IsValid property
IsValid = worstError;
}

View File

@ -26,8 +26,8 @@ namespace DisplayMagician
#region Class Variables
// Common items to the class
private static List<ShortcutItem> _allShortcuts = new List<ShortcutItem>();
public static Dictionary<string, bool> _shortcutWarningLookup = new Dictionary<string, bool>();
public static Dictionary<string, bool> _shortcutErrorLookup = new Dictionary<string, bool>();
//public static Dictionary<string, bool> _shortcutWarningLookup = new Dictionary<string, bool>();
//public static Dictionary<string, bool> _shortcutErrorLookup = new Dictionary<string, bool>();
private static bool _shortcutsLoaded = false;
// Other constants that are useful
private static string AppShortcutStoragePath = Path.Combine(Program.AppDataPath, $"Shortcuts");
@ -76,7 +76,6 @@ namespace DisplayMagician
// Load the Shortcuts from storage
LoadShortcuts();
IsValidRefresh();
}
#endregion
@ -94,7 +93,7 @@ namespace DisplayMagician
}
}
public static Dictionary<string, bool> ShortcutWarningLookup
/*public static Dictionary<string, bool> ShortcutWarningLookup
{
get
{
@ -116,7 +115,7 @@ namespace DisplayMagician
return _shortcutErrorLookup;
}
}
}*/
public static int ShortcutCount
{
@ -163,7 +162,7 @@ namespace DisplayMagician
{
// Save the shortcuts JSON as it's different
SaveShortcuts();
IsValidRefresh();
return true;
}
else
@ -199,6 +198,7 @@ namespace DisplayMagician
if (numRemoved == 1)
{
SaveShortcuts();
IsValidRefresh();
logger.Debug($"ShortcutRepository/RemoveShortcut: Our shortcut repository does contain a shortcut we were looking for");
return true;
}
@ -254,6 +254,7 @@ namespace DisplayMagician
if (numRemoved == 1)
{
SaveShortcuts();
IsValidRefresh();
logger.Debug($"ShortcutRepository/RemoveShortcut2: Our shortcut repository does contain a shortcut with Name or UUID {shortcutNameOrUuid}");
return true;
}
@ -392,7 +393,7 @@ namespace DisplayMagician
}
SaveShortcuts();
IsValidRefresh();
return true;
}
@ -447,7 +448,6 @@ namespace DisplayMagician
{
// And assign the matching Profile if we find it.
updatedShortcut.ProfileToUse = profile;
updatedShortcut.IsPossible = true;
break;
}
}
@ -455,7 +455,6 @@ namespace DisplayMagician
// We should only get here if there isn't a profile to match to.
logger.Debug($"ShortcutRepository/LoadShortcuts: Couldn't find the profile with UUID {updatedShortcut.ProfileUUID} so couldn't link it to a profile! We can't use this shortcut.");
updatedShortcut.ProfileToUse = null;
updatedShortcut.IsPossible = false;
}
// Sort the shortcuts alphabetically
@ -544,19 +543,9 @@ namespace DisplayMagician
// We need to refresh the cached answer
// Get the list of connected devices
_shortcutWarningLookup.Clear();
_shortcutErrorLookup.Clear();
foreach (ShortcutItem loadedShortcut in AllShortcuts)
{
_shortcutWarningLookup[loadedShortcut.Name] = false;
_shortcutErrorLookup[loadedShortcut.Name] = false;
(ShortcutValidity result, string thing) = (loadedShortcut.IsValid());
if (result == ShortcutValidity.Warning)
ShortcutWarningLookup[loadedShortcut.Name] = true;
if (result == ShortcutValidity.Error)
ShortcutErrorLookup[loadedShortcut.Name] = true;
loadedShortcut.RefreshValidity();
}
}
@ -573,12 +562,15 @@ namespace DisplayMagician
if (!(shortcutToUse is ShortcutItem))
return;
(ShortcutValidity valid, string reason) = shortcutToUse.IsValid();
if (valid == ShortcutValidity.Error || valid == ShortcutValidity.Warning)
// Check the shortcut is still valid.
shortcutToUse.RefreshValidity();
if (shortcutToUse.IsValid == ShortcutValidity.Error || shortcutToUse.IsValid == ShortcutValidity.Warning)
{
logger.Error($"ShortcutRepository/RunShortcut: Cannot run the shortcut {shortcutToUse.Name} as it isn't valid");
string errorReasons = String.Join(", ", (from error in shortcutToUse.Errors select error.Message));
MessageBox.Show(
$"Unable to run the shortcut '{shortcutToUse.Name}': {reason}",
$"Unable to run the shortcut '{shortcutToUse.Name}': {errorReasons}",
@"Cannot run the Shortcut",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);

View File

@ -96,7 +96,8 @@ namespace DisplayMagician.UIForms
{
Rectangle pos = Utility.GetSizedImageBounds(img, new Rectangle(bounds.Location + itemPadding, ImageListView.ThumbnailSize));
if (ShortcutRepository.ShortcutErrorLookup[item.Text])
ShortcutItem shortcutToRender = ShortcutRepository.GetShortcut(item.Text);
if (shortcutToRender.IsValid == ShortcutValidity.Error)
{
// The shortcut is permanently invalid (game removed or profile deleted)
// so we make the image grayscale
@ -107,7 +108,7 @@ namespace DisplayMagician.UIForms
// right in the centre
g.DrawImage(Properties.Resources.Error, pos.X + 30, pos.Y + 30, 40, 40);
}
else if (ShortcutRepository.ShortcutWarningLookup[item.Text])
else if (shortcutToRender.IsValid == ShortcutValidity.Warning)
{
// The shortcut is temporaily invalid (e.g. screens aren't right at the moment)
// so we make the image grayscale
@ -266,7 +267,13 @@ namespace DisplayMagician.UIForms
{
Rectangle pos = Utility.GetSizedImageBounds(img, new Rectangle(bounds.Location + itemPadding, ImageListView.ThumbnailSize));
if (ProfileRepository.ProfileWarningLookup[item.Text])
ProfileItem profileToRender = ProfileRepository.GetProfile(item.Text);
if (profileToRender.IsPossible)
{
// Draw the full color image as the shortcuts is not invalid
g.DrawImage(img, pos);
}
else
{
// THe shortcut is invalid
// so we make the image grayscale
@ -277,11 +284,7 @@ namespace DisplayMagician.UIForms
// right in the centre
g.DrawImage(Properties.Resources.Warning, pos.X + 30, pos.Y + 30, 40, 40);
}
else
{
// Draw the full color image as the shortcuts is not invalid
g.DrawImage(img, pos);
}
// Draw image border
if (Math.Min(pos.Width, pos.Height) > 32)

View File

@ -38,6 +38,12 @@ namespace DisplayMagician.UIForms
private void ShortcutLibraryForm_Load(object sender, EventArgs e)
{
// Refresh the profiles and the shortcut validity to start
// The rest of the refreshing happens as the shortcuts are added
// and deleted.
ProfileRepository.IsPossibleRefresh();
ShortcutRepository.IsValidRefresh();
// Refresh the Shortcut Library UI
RefreshShortcutLibraryUI();
@ -52,15 +58,11 @@ namespace DisplayMagician.UIForms
if (ShortcutRepository.ShortcutCount == 0)
return;
ProfileRepository.IsPossibleRefresh();
// Temporarily stop updating the saved_profiles listview
ilv_saved_shortcuts.SuspendLayout();
ImageListViewItem newItem = null;
ilv_saved_shortcuts.Items.Clear();
ShortcutRepository.IsValidRefresh();
foreach (ShortcutItem loadedShortcut in ShortcutRepository.AllShortcuts.OrderBy(s => s.Name))
{
@ -68,7 +70,21 @@ namespace DisplayMagician.UIForms
// Select it if its the selectedProfile
if (_selectedShortcut is ShortcutItem && _selectedShortcut.Equals(loadedShortcut))
{
newItem.Selected = true;
// Hide the run button if the shortcut isn't valid
if (_selectedShortcut.IsValid == ShortcutValidity.Warning || _selectedShortcut.IsValid == ShortcutValidity.Error)
{
btn_run.Visible = false;
cms_shortcuts.Items[1].Enabled = false;
}
else
{
btn_run.Visible = true;
cms_shortcuts.Items[1].Enabled = true;
}
}
//ilv_saved_profiles.Items.Add(newItem);
ilv_saved_shortcuts.Items.Add(newItem, _shortcutAdaptor);
@ -95,8 +111,7 @@ namespace DisplayMagician.UIForms
// if shortcut is not valid then ask if the user
// really wants to save it to desktop
(ShortcutValidity valid, string reason) = _selectedShortcut.IsValid();
if (valid == ShortcutValidity.Error || valid == ShortcutValidity.Warning)
if (_selectedShortcut.IsValid == ShortcutValidity.Error || _selectedShortcut.IsValid == ShortcutValidity.Warning)
{
// We ask the user of they still want to save the desktop shortcut
if (MessageBox.Show($"The shortcut '{_selectedShortcut.Name}' isn't valid for some reason so a desktop shortcut wouldn't work until the shortcut is fixed. Has your hardware or screen layout changed from when the shortcut was made? We recommend that you edit the shortcut to make it valid again, or reverse the hardware changes you made. Do you still want to save the desktop shortcut?", $"Still save the '{_selectedShortcut.Name}' Desktop Shortcut?", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.No)
@ -166,35 +181,11 @@ namespace DisplayMagician.UIForms
private void ilv_saved_shortcuts_ItemClick(object sender, ItemClickEventArgs e)
{
// This is the single click to select
_selectedShortcut = GetShortcutFromName(e.Item.Text);
SetRunOption();
if (e.Buttons == MouseButtons.Right)
{
cms_shortcuts.Show(ilv_saved_shortcuts,e.Location);
}
}
private void ilv_saved_shortcuts_ItemDoubleClick(object sender, ItemClickEventArgs e)
{
_selectedShortcut = GetShortcutFromName(e.Item.Text);
SetRunOption();
if (_selectedShortcut == null)
return;
if (!ShortcutRepository.ShortcutWarningLookup[_selectedShortcut.Name])
return;
// Run the selected shortcut
btn_run.PerformClick();
}
private void SetRunOption()
{
if (ShortcutRepository.ShortcutWarningLookup[_selectedShortcut.Name] || ShortcutRepository.ShortcutErrorLookup[_selectedShortcut.Name])
// Hide the run button if the shortcut isn't valid
if (_selectedShortcut.IsValid == ShortcutValidity.Warning || _selectedShortcut.IsValid == ShortcutValidity.Error)
{
btn_run.Visible = false;
cms_shortcuts.Items[1].Enabled = false;
@ -205,7 +196,33 @@ namespace DisplayMagician.UIForms
btn_run.Visible = true;
cms_shortcuts.Items[1].Enabled = true;
}
if (e.Buttons == MouseButtons.Right)
{
cms_shortcuts.Show(ilv_saved_shortcuts,e.Location);
}
}
private void ilv_saved_shortcuts_ItemDoubleClick(object sender, ItemClickEventArgs e)
{
// This is the double click to run
_selectedShortcut = GetShortcutFromName(e.Item.Text);
// Hide the run button if the shortcut isn't valid
if (_selectedShortcut.IsValid == ShortcutValidity.Warning || _selectedShortcut.IsValid == ShortcutValidity.Error)
{
btn_run.Visible = false;
cms_shortcuts.Items[1].Enabled = false;
}
else
{
btn_run.Visible = true;
cms_shortcuts.Items[1].Enabled = true;
}
// Run the selected shortcut
btn_run.PerformClick();
}
private void btn_new_Click(object sender, EventArgs e)
@ -273,8 +290,7 @@ namespace DisplayMagician.UIForms
return;
// Only run the if shortcut is valid
(ShortcutValidity valid, string reason) = _selectedShortcut.IsValid();
if (valid == ShortcutValidity.Error || valid == ShortcutValidity.Warning)
if (_selectedShortcut.IsValid == ShortcutValidity.Warning || _selectedShortcut.IsValid == ShortcutValidity.Error)
{
// We tell the user the reason that we couldnt run the shortcut
if (MessageBox.Show($"The shortcut '{_selectedShortcut.Name}' isn't valid for some reason so we cannot run the application or game. Has your hardware or screen layout changed from when the shortcut was made? We recommend that you edit the shortcut to make it valid again, or reverse the hardware changes you made. Do you want to do that now?", $"Edit the '{_selectedShortcut.Name}' Shortcut?", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.No)