2017-02-26 19:23:31 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Text;
|
|
|
|
using System.Threading;
|
2018-10-20 00:23:43 +00:00
|
|
|
using System.Windows.Forms;
|
2020-05-15 08:52:16 +00:00
|
|
|
using System.Diagnostics;
|
2017-02-26 19:23:31 +00:00
|
|
|
using WindowsDisplayAPI.DisplayConfig;
|
2020-04-23 08:16:16 +00:00
|
|
|
using HeliosPlus.Shared.Resources;
|
2018-10-20 00:13:40 +00:00
|
|
|
using Newtonsoft.Json;
|
2017-02-26 19:23:31 +00:00
|
|
|
using NvAPIWrapper.Mosaic;
|
|
|
|
using NvAPIWrapper.Native.Mosaic;
|
2020-05-09 13:02:07 +00:00
|
|
|
using HeliosPlus.Shared.Topology;
|
|
|
|
using System.Drawing;
|
|
|
|
using System.Drawing.Imaging;
|
2020-05-12 10:46:23 +00:00
|
|
|
using WindowsDisplayAPI;
|
2020-06-14 04:20:52 +00:00
|
|
|
using System.Text.RegularExpressions;
|
2020-09-18 10:52:18 +00:00
|
|
|
using NvAPIWrapper.Display;
|
2017-02-26 19:23:31 +00:00
|
|
|
|
2020-04-23 08:16:16 +00:00
|
|
|
namespace HeliosPlus.Shared
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-06-07 08:48:45 +00:00
|
|
|
public class ProfileItem
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-06-07 08:48:45 +00:00
|
|
|
private static List<ProfileItem> _allSavedProfiles = new List<ProfileItem>();
|
2020-05-09 13:02:07 +00:00
|
|
|
private ProfileIcon _profileIcon;
|
2020-06-07 08:48:45 +00:00
|
|
|
private Bitmap _profileBitmap, _profileShortcutBitmap;
|
2020-08-19 06:55:50 +00:00
|
|
|
private List<string> _profileDisplayIdentifiers = new List<string>();
|
2020-09-18 10:52:18 +00:00
|
|
|
private static List<WindowsDisplayAPI.Display> _availableDisplays;
|
|
|
|
private static List<WindowsDisplayAPI.UnAttachedDisplay> _unavailableDisplays;
|
2017-02-26 19:23:31 +00:00
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
internal static string AppDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "HeliosPlus");
|
|
|
|
|
2020-06-15 09:57:46 +00:00
|
|
|
private string _uuid = "";
|
2020-06-14 04:20:52 +00:00
|
|
|
private Version _version;
|
|
|
|
private bool _isActive = false;
|
|
|
|
private bool _isPossible = false;
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
|
|
|
|
#region JsonConverterBitmap
|
|
|
|
internal class CustomBitmapConverter : JsonConverter
|
|
|
|
{
|
|
|
|
public override bool CanConvert(Type objectType)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//convert from byte to bitmap (deserialize)
|
|
|
|
|
|
|
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
|
|
|
{
|
|
|
|
string image = (string)reader.Value;
|
|
|
|
|
|
|
|
byte[] byteBuffer = Convert.FromBase64String(image);
|
|
|
|
MemoryStream memoryStream = new MemoryStream(byteBuffer);
|
|
|
|
memoryStream.Position = 0;
|
|
|
|
|
|
|
|
return (Bitmap)Bitmap.FromStream(memoryStream);
|
|
|
|
}
|
|
|
|
|
|
|
|
//convert bitmap to byte (serialize)
|
|
|
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
|
|
|
{
|
|
|
|
Bitmap bitmap = (Bitmap)value;
|
|
|
|
|
|
|
|
ImageConverter converter = new ImageConverter();
|
|
|
|
writer.WriteValue((byte[])converter.ConvertTo(bitmap, typeof(byte[])));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static System.Drawing.Imaging.ImageFormat GetImageFormat(Bitmap bitmap)
|
|
|
|
{
|
|
|
|
ImageFormat img = bitmap.RawFormat;
|
|
|
|
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Jpeg;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Bmp))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Bmp;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Png))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Png;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Emf))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Emf;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Exif))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Exif;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Gif))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Gif;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Icon))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Icon;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.MemoryBmp))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.MemoryBmp;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Tiff))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Tiff;
|
|
|
|
else
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Wmf;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
2020-06-15 09:57:46 +00:00
|
|
|
public ProfileItem()
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-07-24 01:11:42 +00:00
|
|
|
/*try
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-08-19 06:55:50 +00:00
|
|
|
// Generate the DeviceIdentifiers ready to be used
|
|
|
|
ProfileDisplayIdentifiers = DisplayIdentifier.GetDisplayIdentification();
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
2020-07-15 08:11:38 +00:00
|
|
|
catch (Exception ex)
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-07-24 04:51:48 +00:00
|
|
|
Console.WriteLine($"ShortcutItem/Instansiation exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
|
2017-02-26 19:23:31 +00:00
|
|
|
// ignored
|
2020-07-24 01:11:42 +00:00
|
|
|
}*/
|
2020-05-09 13:02:07 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
public static Version Version = new Version(2, 1);
|
|
|
|
|
2020-06-14 04:20:52 +00:00
|
|
|
#region Instance Properties
|
2018-10-23 23:34:49 +00:00
|
|
|
|
2020-06-14 04:20:52 +00:00
|
|
|
public string UUID
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2020-06-14 04:20:52 +00:00
|
|
|
if (String.IsNullOrWhiteSpace(_uuid))
|
2020-08-18 22:16:04 +00:00
|
|
|
_uuid = Guid.NewGuid().ToString("D");
|
2020-06-14 04:20:52 +00:00
|
|
|
return _uuid;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
2020-08-18 22:16:04 +00:00
|
|
|
string uuidV4Regex = @"[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}";
|
2020-06-14 04:20:52 +00:00
|
|
|
Match match = Regex.Match(value, uuidV4Regex, RegexOptions.IgnoreCase);
|
|
|
|
if (match.Success)
|
|
|
|
_uuid = value;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-20 00:13:40 +00:00
|
|
|
[JsonIgnore]
|
2017-02-26 19:23:31 +00:00
|
|
|
public bool IsPossible
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2020-09-18 08:35:49 +00:00
|
|
|
|
2020-09-30 09:49:02 +00:00
|
|
|
// Check each display in this profile and make sure it's currently available
|
2020-10-02 05:10:34 +00:00
|
|
|
int validDisplayCount = 0;
|
2020-09-30 09:49:02 +00:00
|
|
|
foreach (string profileDisplayIdentifier in ProfileDisplayIdentifiers)
|
2020-09-18 08:35:49 +00:00
|
|
|
{
|
2020-09-30 09:49:02 +00:00
|
|
|
// If this profile has a display that isn't currently available then we need to say it's a no!
|
2020-10-02 05:10:34 +00:00
|
|
|
if (ProfileRepository.CurrentProfile.ProfileDisplayIdentifiers.Contains(profileDisplayIdentifier))
|
|
|
|
validDisplayCount++;
|
2020-05-13 11:04:18 +00:00
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2020-10-02 05:10:34 +00:00
|
|
|
if (validDisplayCount == ProfileDisplayIdentifiers.Count)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
2020-07-24 09:46:53 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
2020-05-12 10:46:23 +00:00
|
|
|
public ProfileViewport[] Viewports { get; set; } = new ProfileViewport[0];
|
2017-02-26 19:23:31 +00:00
|
|
|
|
2020-06-15 09:57:46 +00:00
|
|
|
[JsonIgnore]
|
2020-05-09 13:02:07 +00:00
|
|
|
public ProfileIcon ProfileIcon
|
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_profileIcon != null)
|
|
|
|
return _profileIcon;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_profileIcon = new ProfileIcon(this);
|
|
|
|
return _profileIcon;
|
|
|
|
}
|
|
|
|
}
|
2020-05-09 13:02:07 +00:00
|
|
|
set
|
|
|
|
{
|
|
|
|
_profileIcon = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-06-14 04:20:52 +00:00
|
|
|
public string SavedProfileIconCacheFilename { get; set; }
|
2020-05-10 10:47:18 +00:00
|
|
|
|
2020-09-18 10:52:18 +00:00
|
|
|
public List<string> ProfileDisplayIdentifiers
|
2020-08-19 06:55:50 +00:00
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_profileDisplayIdentifiers.Count == 0)
|
|
|
|
{
|
2020-09-18 10:52:18 +00:00
|
|
|
_profileDisplayIdentifiers = this.GenerateDisplayIdentifiers();
|
2020-08-19 06:55:50 +00:00
|
|
|
}
|
|
|
|
return _profileDisplayIdentifiers;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
if (value is List<string>)
|
|
|
|
_profileDisplayIdentifiers = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
[JsonConverter(typeof(CustomBitmapConverter))]
|
|
|
|
public Bitmap ProfileBitmap
|
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_profileBitmap != null)
|
|
|
|
return _profileBitmap;
|
|
|
|
else
|
|
|
|
{
|
2020-06-07 08:48:45 +00:00
|
|
|
_profileBitmap = this.ProfileIcon.ToBitmap(256, 256);
|
2020-05-12 10:46:23 +00:00
|
|
|
return _profileBitmap;
|
|
|
|
}
|
|
|
|
}
|
2020-05-09 13:02:07 +00:00
|
|
|
set
|
|
|
|
{
|
|
|
|
_profileBitmap = value;
|
|
|
|
}
|
|
|
|
|
2018-10-20 00:13:40 +00:00
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
2020-06-07 08:48:45 +00:00
|
|
|
[JsonConverter(typeof(CustomBitmapConverter))]
|
|
|
|
public Bitmap ProfileTightestBitmap
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_profileShortcutBitmap != null)
|
|
|
|
return _profileShortcutBitmap;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_profileShortcutBitmap = this.ProfileIcon.ToTightestBitmap();
|
|
|
|
return _profileShortcutBitmap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
_profileShortcutBitmap = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-06-14 04:20:52 +00:00
|
|
|
#endregion
|
2017-02-26 19:23:31 +00:00
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
public static bool IsValidName(string testName)
|
|
|
|
{
|
2020-06-07 08:48:45 +00:00
|
|
|
foreach (ProfileItem loadedProfile in _allSavedProfiles)
|
2020-05-09 13:02:07 +00:00
|
|
|
{
|
|
|
|
if (loadedProfile.Name == testName)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-15 09:57:46 +00:00
|
|
|
public static bool IsValidUUID(string testId)
|
2020-05-09 13:02:07 +00:00
|
|
|
{
|
2020-06-14 04:20:52 +00:00
|
|
|
string uuidV4Regex = @"/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i";
|
|
|
|
Match match = Regex.Match(testId, uuidV4Regex, RegexOptions.IgnoreCase);
|
|
|
|
if (match.Success)
|
2020-05-10 10:47:18 +00:00
|
|
|
return true;
|
2020-06-14 04:20:52 +00:00
|
|
|
else
|
|
|
|
return false;
|
2020-05-10 10:47:18 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 06:55:50 +00:00
|
|
|
public bool IsValid()
|
|
|
|
{
|
|
|
|
|
|
|
|
if (Viewports != null &&
|
|
|
|
ProfileIcon is Bitmap &&
|
|
|
|
File.Exists(SavedProfileIconCacheFilename) &&
|
|
|
|
ProfileBitmap is Bitmap &&
|
|
|
|
ProfileTightestBitmap is Bitmap &&
|
|
|
|
ProfileDisplayIdentifiers.Count > 0)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2020-09-18 10:52:18 +00:00
|
|
|
public List<string> GenerateDisplayIdentifiers()
|
|
|
|
{
|
|
|
|
List<string> displayIdentifiers = new List<string>();
|
|
|
|
|
|
|
|
// If the Video Card is an NVidia, then we should generate specific NVidia displayIdentifiers
|
|
|
|
NvAPIWrapper.GPU.LogicalGPU[] myLogicalGPUs = NvAPIWrapper.GPU.LogicalGPU.GetLogicalGPUs();
|
|
|
|
if (myLogicalGPUs.Length > 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
foreach (NvAPIWrapper.GPU.LogicalGPU myLogicalGPU in myLogicalGPUs)
|
|
|
|
{
|
|
|
|
NvAPIWrapper.GPU.PhysicalGPU[] myPhysicalGPUs = myLogicalGPU.CorrespondingPhysicalGPUs;
|
|
|
|
foreach (NvAPIWrapper.GPU.PhysicalGPU myPhysicalGPU in myPhysicalGPUs)
|
|
|
|
{
|
|
|
|
// get a list of all physical outputs attached to the GPUs
|
|
|
|
NvAPIWrapper.GPU.GPUOutput[] myGPUOutputs = myPhysicalGPU.ActiveOutputs;
|
|
|
|
foreach (NvAPIWrapper.GPU.GPUOutput aGPUOutput in myGPUOutputs)
|
|
|
|
{
|
|
|
|
// Figure out the displaydevice attached to the output
|
|
|
|
NvAPIWrapper.Display.DisplayDevice aConnectedDisplayDevice = myPhysicalGPU.GetDisplayDeviceByOutput(aGPUOutput);
|
|
|
|
|
|
|
|
// Create an array of all the important display info we need to record
|
|
|
|
string[] displayInfo = {
|
|
|
|
"NVIDIA",
|
|
|
|
myLogicalGPU.ToString(),
|
|
|
|
myPhysicalGPU.ToString(),
|
|
|
|
myPhysicalGPU.ArchitectInformation.ShortName.ToString(),
|
|
|
|
myPhysicalGPU.ArchitectInformation.Revision.ToString(),
|
|
|
|
myPhysicalGPU.Board.ToString(),
|
|
|
|
myPhysicalGPU.Foundry.ToString(),
|
|
|
|
myPhysicalGPU.GPUId.ToString(),
|
|
|
|
myPhysicalGPU.GPUType.ToString(),
|
|
|
|
aGPUOutput.OutputId.ToString(),
|
|
|
|
aConnectedDisplayDevice.ConnectionType.ToString(),
|
|
|
|
aConnectedDisplayDevice.DisplayId.ToString(),
|
|
|
|
};
|
|
|
|
|
|
|
|
// Create a display identifier out of it
|
|
|
|
string displayIdentifier = String.Join("|", displayInfo);
|
|
|
|
// Add it to the list of display identifiers so we can return it
|
|
|
|
displayIdentifiers.Add(displayIdentifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// else videocard is not NVIdia so we just use the WindowsAPI access method
|
|
|
|
// Note: This won't support any special AMD EyeFinity profiles unfortunately.....
|
|
|
|
// TODO: Add the detection and generation of the device ids using an AMD library
|
|
|
|
// so that we can match valid AMD Eyefinity profiles with valid AMD standard profiles.
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
// Then go through the displays in the profile and check they are made of displays
|
|
|
|
// that currently are available.
|
|
|
|
foreach (ProfileViewport profileViewport in Viewports)
|
|
|
|
{
|
|
|
|
// For each profile, we want to make sure all TargetDisplays.DevicePath are in the list of
|
|
|
|
// availableDevicePaths
|
|
|
|
//foreach (WindowsDisplayAPI.DisplayConfig.PathTargetInfo profilePathTargetInfo in profileViewport.ToPathInfo().TargetsInfo)
|
|
|
|
foreach (ProfileViewportTargetDisplay profileTargetDisplay in profileViewport.TargetDisplays)
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
WindowsDisplayAPI.DisplayConfig.PathTargetInfo profilePathTargetInfo = profileTargetDisplay.ToPathTargetInfo();
|
|
|
|
|
|
|
|
// Create an array of all the important display info we need to record
|
|
|
|
string[] displayInfo = {
|
|
|
|
"WINAPI",
|
|
|
|
profileViewport.SourceId.ToString(),
|
|
|
|
profilePathTargetInfo.DisplayTarget.Adapter.AdapterId.HighPart.ToString(),
|
|
|
|
profilePathTargetInfo.DisplayTarget.Adapter.AdapterId.LowPart.ToString(),
|
|
|
|
profilePathTargetInfo.OutputTechnology.ToString(),
|
|
|
|
profilePathTargetInfo.DisplayTarget.EDIDManufactureCode.ToString(),
|
|
|
|
profilePathTargetInfo.DisplayTarget.FriendlyName,
|
|
|
|
profilePathTargetInfo.DisplayTarget.EDIDManufactureId.ToString(),
|
|
|
|
profilePathTargetInfo.DisplayTarget.EDIDProductCode.ToString(),
|
|
|
|
profilePathTargetInfo.DisplayTarget.ConnectorInstance.ToString(),
|
|
|
|
profileTargetDisplay.DevicePath,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Create a display identifier out of it
|
|
|
|
string displayIdentifier = String.Join("|", displayInfo);
|
|
|
|
// Add it to the list of display identifiers so we can return it
|
|
|
|
displayIdentifiers.Add(displayIdentifier);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return displayIdentifiers;
|
|
|
|
}
|
|
|
|
|
2020-06-15 09:57:46 +00:00
|
|
|
public bool CopyTo(ProfileItem profile, bool overwriteId = true)
|
2020-06-14 04:20:52 +00:00
|
|
|
{
|
|
|
|
if (!(profile is ProfileItem))
|
|
|
|
return false;
|
2020-05-09 13:02:07 +00:00
|
|
|
|
2020-06-15 09:57:46 +00:00
|
|
|
if (overwriteId == true)
|
2020-06-14 04:20:52 +00:00
|
|
|
profile.UUID = UUID;
|
|
|
|
|
|
|
|
// Copy all our profile data over to the other profile
|
|
|
|
profile.Name = Name;
|
|
|
|
profile.Viewports = Viewports;
|
|
|
|
profile.ProfileIcon = ProfileIcon;
|
|
|
|
profile.SavedProfileIconCacheFilename = SavedProfileIconCacheFilename;
|
|
|
|
profile.ProfileBitmap = ProfileBitmap;
|
|
|
|
profile.ProfileTightestBitmap = ProfileTightestBitmap;
|
2020-08-19 06:55:50 +00:00
|
|
|
profile.ProfileDisplayIdentifiers = ProfileDisplayIdentifiers;
|
2020-06-14 04:20:52 +00:00
|
|
|
return true;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 06:55:50 +00:00
|
|
|
public bool PreSave()
|
|
|
|
{
|
|
|
|
// Prepare our profile data for saving
|
|
|
|
if (_profileDisplayIdentifiers.Count == 0)
|
|
|
|
{
|
2020-09-18 10:52:18 +00:00
|
|
|
_profileDisplayIdentifiers = GenerateDisplayIdentifiers();
|
2020-08-19 06:55:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return if it is valid and we should continue
|
|
|
|
return IsValid();
|
|
|
|
}
|
|
|
|
|
2020-05-13 11:04:18 +00:00
|
|
|
|
|
|
|
// The public override for the Object.Equals
|
2017-02-26 19:23:31 +00:00
|
|
|
public override bool Equals(object obj)
|
|
|
|
{
|
2020-06-07 08:48:45 +00:00
|
|
|
return this.Equals(obj as ProfileItem);
|
2020-05-13 11:04:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 09:57:46 +00:00
|
|
|
// Profiles are equal if their Viewports are equal
|
2020-06-07 08:48:45 +00:00
|
|
|
public bool Equals(ProfileItem other)
|
2020-05-13 11:04:18 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
// If parameter is null, return false.
|
|
|
|
if (Object.ReferenceEquals(other, null))
|
2018-10-20 00:27:25 +00:00
|
|
|
return false;
|
|
|
|
|
2020-05-13 11:04:18 +00:00
|
|
|
// Optimization for a common success case.
|
|
|
|
if (Object.ReferenceEquals(this, other))
|
2018-10-20 00:27:25 +00:00
|
|
|
return true;
|
|
|
|
|
2020-05-13 11:04:18 +00:00
|
|
|
// If run-time types are not exactly the same, return false.
|
|
|
|
if (this.GetType() != other.GetType())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check whether the profiles' properties are equal
|
|
|
|
// We need to exclude the name as the name is solely for saving to disk
|
|
|
|
// and displaying to the user.
|
|
|
|
// Two profiles are equal only when they have the same viewport data
|
2020-05-14 10:38:31 +00:00
|
|
|
if (Viewports.SequenceEqual(other.Viewports))
|
2020-05-13 11:04:18 +00:00
|
|
|
return true;
|
|
|
|
else
|
2018-10-20 00:27:25 +00:00
|
|
|
return false;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-13 11:04:18 +00:00
|
|
|
// If Equals() returns true for this object compared to another
|
|
|
|
// then GetHashCode() must return the same value for these objects.
|
2017-02-26 19:23:31 +00:00
|
|
|
public override int GetHashCode()
|
|
|
|
{
|
2020-05-13 11:04:18 +00:00
|
|
|
|
|
|
|
// Get hash code for the Viewports field if it is not null.
|
|
|
|
int hashViewports = Viewports == null ? 0 : Viewports.GetHashCode();
|
|
|
|
|
|
|
|
//Calculate the hash code for the product.
|
|
|
|
return hashViewports;
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-13 11:04:18 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
public override string ToString()
|
|
|
|
{
|
2020-05-16 03:58:59 +00:00
|
|
|
return (Name ?? Language.UN_TITLED_PROFILE);
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
private static string GetValidFilename(string uncheckedFilename)
|
|
|
|
{
|
|
|
|
string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
|
|
|
|
foreach (char c in invalid)
|
|
|
|
{
|
|
|
|
uncheckedFilename = uncheckedFilename.Replace(c.ToString(), "");
|
|
|
|
}
|
|
|
|
return uncheckedFilename;
|
|
|
|
}
|
2020-07-23 06:31:00 +00:00
|
|
|
|
2020-05-13 11:04:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Custom comparer for the Profile class
|
|
|
|
// Allows us to use 'Contains'
|
2020-06-07 08:48:45 +00:00
|
|
|
class ProfileComparer : IEqualityComparer<ProfileItem>
|
2020-05-13 11:04:18 +00:00
|
|
|
{
|
|
|
|
// Products are equal if their names and product numbers are equal.
|
2020-06-07 08:48:45 +00:00
|
|
|
public bool Equals(ProfileItem x, ProfileItem y)
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2020-05-13 11:04:18 +00:00
|
|
|
//Check whether the compared objects reference the same data.
|
|
|
|
if (Object.ReferenceEquals(x, y)) return true;
|
2018-10-23 23:52:18 +00:00
|
|
|
|
2020-05-13 11:04:18 +00:00
|
|
|
//Check whether any of the compared objects is null.
|
|
|
|
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check whether the profiles' properties are equal
|
|
|
|
// We need to exclude the name as the name is solely for saving to disk
|
|
|
|
// and displaying to the user.
|
|
|
|
// Two profiles are equal only when they have the same viewport data
|
|
|
|
if (x.Viewports.Equals(y.Viewports))
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
2020-05-13 11:04:18 +00:00
|
|
|
|
|
|
|
// If Equals() returns true for a pair of objects
|
|
|
|
// then GetHashCode() must return the same value for these objects.
|
2020-06-07 08:48:45 +00:00
|
|
|
public int GetHashCode(ProfileItem profile)
|
2020-05-13 11:04:18 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
// Check whether the object is null
|
|
|
|
if (Object.ReferenceEquals(profile, null)) return 0;
|
|
|
|
|
|
|
|
// Get hash code for the Viewports field if it is not null.
|
|
|
|
int hashViewports = profile.Viewports == null ? 0 : profile.Viewports.GetHashCode();
|
|
|
|
|
|
|
|
//Calculate the hash code for the product.
|
|
|
|
return hashViewports;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
}
|