diff --git a/SabreTools.Library/DatFiles/ItemDictionary.cs b/SabreTools.Library/DatFiles/ItemDictionary.cs index d12309dd..00f03938 100644 --- a/SabreTools.Library/DatFiles/ItemDictionary.cs +++ b/SabreTools.Library/DatFiles/ItemDictionary.cs @@ -125,6 +125,12 @@ namespace SabreTools.Library.DatFiles [JsonIgnore] public long DiskCount { get; private set; } = 0; + /// + /// Number of Feature items + /// + [JsonIgnore] + public long FeatureCount { get; private set; } = 0; + /// /// Number of Media items /// @@ -533,6 +539,9 @@ namespace SabreTools.Library.DatFiles NodumpCount += ((item as Disk).ItemStatus == ItemStatus.Nodump ? 1 : 0); VerifiedCount += ((item as Disk).ItemStatus == ItemStatus.Verified ? 1 : 0); break; + case ItemType.Feature: + FeatureCount++; + break; case ItemType.Media: MediaCount++; MD5Count += (string.IsNullOrWhiteSpace((item as Media).MD5) ? 0 : 1); @@ -686,6 +695,9 @@ namespace SabreTools.Library.DatFiles NodumpCount -= ((item as Disk).ItemStatus == ItemStatus.Nodump ? 1 : 0); VerifiedCount -= ((item as Disk).ItemStatus == ItemStatus.Verified ? 1 : 0); break; + case ItemType.Feature: + FeatureCount--; + break; case ItemType.Media: MediaCount--; MD5Count -= (string.IsNullOrWhiteSpace((item as Media).MD5) ? 0 : 1); diff --git a/SabreTools.Library/DatFiles/Json.cs b/SabreTools.Library/DatFiles/Json.cs index 7aaa8be0..a413d138 100644 --- a/SabreTools.Library/DatFiles/Json.cs +++ b/SabreTools.Library/DatFiles/Json.cs @@ -235,6 +235,9 @@ namespace SabreTools.Library.DatFiles case ItemType.Disk: datItem = datItemObj.ToObject(); break; + case ItemType.Feature: + datItem = datItemObj.ToObject(); + break; case ItemType.Media: datItem = datItemObj.ToObject(); break; @@ -257,7 +260,7 @@ namespace SabreTools.Library.DatFiles datItem = datItemObj.ToObject(); break; case ItemType.Sound: - datItem = datItemObj.ToObject(); + datItem = datItemObj.ToObject(); break; } } diff --git a/SabreTools.Library/DatFiles/Listxml.cs b/SabreTools.Library/DatFiles/Listxml.cs index d2e8d5c4..b27e5e75 100644 --- a/SabreTools.Library/DatFiles/Listxml.cs +++ b/SabreTools.Library/DatFiles/Listxml.cs @@ -289,6 +289,17 @@ namespace SabreTools.Library.DatFiles reader.Read(); break; + case "feature": + datItems.Add(new Feature + { + Type = reader.GetAttribute("type"), + Status = reader.GetAttribute("status"), + Overall = reader.GetAttribute("overall"), + }); + + reader.Read(); + break; + case "rom": datItems.Add(new Rom { @@ -481,21 +492,6 @@ namespace SabreTools.Library.DatFiles reader.Read(); break; - case "feature": - var feature = new Feature(); - feature.Type = reader.GetAttribute("type"); - feature.Status = reader.GetAttribute("status"); - feature.Overall = reader.GetAttribute("overall"); - - // Ensure the list exists - if (machine.Features == null) - machine.Features = new List(); - - machine.Features.Add(feature); - - reader.Read(); - break; - case "device": var device = new Device(); device.Type = reader.GetAttribute("type"); @@ -1318,20 +1314,6 @@ namespace SabreTools.Library.DatFiles xtw.WriteEndElement(); } } - if (datItem.Machine.Features != null) - { - foreach (var feature in datItem.Machine.Features) - { - xtw.WriteStartElement("feature"); - - xtw.WriteOptionalAttributeString("type", feature.Type); - xtw.WriteOptionalAttributeString("status", feature.Status); - xtw.WriteOptionalAttributeString("overall", feature.Overall); - - // End feature - xtw.WriteEndElement(); - } - } if (datItem.Machine.Devices != null) { foreach (var device in datItem.Machine.Devices) @@ -1584,6 +1566,15 @@ namespace SabreTools.Library.DatFiles xtw.WriteEndElement(); break; + case ItemType.Feature: + var feature = datItem as Feature; + xtw.WriteStartElement("feature"); + xtw.WriteOptionalAttributeString("type", feature.Type); + xtw.WriteOptionalAttributeString("status", feature.Status); + xtw.WriteOptionalAttributeString("overall", feature.Overall); + xtw.WriteEndElement(); + break; + case ItemType.RamOption: var ramOption = datItem as RamOption; xtw.WriteStartElement("ramoption"); diff --git a/SabreTools.Library/DatFiles/SabreDat.cs b/SabreTools.Library/DatFiles/SabreDat.cs index 8deb4728..9adda339 100644 --- a/SabreTools.Library/DatFiles/SabreDat.cs +++ b/SabreTools.Library/DatFiles/SabreDat.cs @@ -1389,6 +1389,16 @@ namespace SabreTools.Library.DatFiles xtw.WriteEndElement(); break; + case ItemType.Feature: + var feature = datItem as Feature; + xtw.WriteStartElement("file"); + xtw.WriteAttributeString("type", "feature"); + xtw.WriteOptionalAttributeString("type", feature.Type); + xtw.WriteOptionalAttributeString("status", feature.Status); + xtw.WriteOptionalAttributeString("overall", feature.Overall); + xtw.WriteEndElement(); + break; + case ItemType.Media: var media = datItem as Media; xtw.WriteStartElement("file"); diff --git a/SabreTools.Library/DatItems/Auxiliary.cs b/SabreTools.Library/DatItems/Auxiliary.cs index f42cedb2..0d0b6720 100644 --- a/SabreTools.Library/DatItems/Auxiliary.cs +++ b/SabreTools.Library/DatItems/Auxiliary.cs @@ -193,23 +193,6 @@ namespace SabreTools.Library.DatItems public string Name { get; set; } } - /// - /// Represents one ListXML feature - /// - /// TODO: Promote to DatItem level - [JsonObject("feature")] - public class Feature - { - [JsonProperty("type")] - public string Type { get; set; } // TODO: (protection|palette|graphics|sound|controls|keyboard|mouse|microphone|camera|disk|printer|lan|wan|timing) - - [JsonProperty("status")] - public string Status { get; set; } // TODO: (unemulated|imperfect) - - [JsonProperty("overall")] - public string Overall { get; set; } // TODO: (unemulated|imperfect) - } - /// /// Represents one ListXML input /// diff --git a/SabreTools.Library/DatItems/DatItem.cs b/SabreTools.Library/DatItems/DatItem.cs index 0b76e491..16de3d26 100644 --- a/SabreTools.Library/DatItems/DatItem.cs +++ b/SabreTools.Library/DatItems/DatItem.cs @@ -482,6 +482,9 @@ namespace SabreTools.Library.DatItems case ItemType.Disk: return new Disk(); + case ItemType.Feature: + return new Feature(); + case ItemType.Media: return new Media(); @@ -521,6 +524,7 @@ namespace SabreTools.Library.DatItems ItemType.DeviceReference => new DeviceReference(), ItemType.DipSwitch => new DipSwitch(), ItemType.Disk => new Disk(), + ItemType.Feature => new Feature(), ItemType.Media => new Media(), ItemType.RamOption => new RamOption(), ItemType.Release => new Release(), diff --git a/SabreTools.Library/DatItems/Enums.cs b/SabreTools.Library/DatItems/Enums.cs index 5b8bb133..1e9762ed 100644 --- a/SabreTools.Library/DatItems/Enums.cs +++ b/SabreTools.Library/DatItems/Enums.cs @@ -190,12 +190,6 @@ namespace SabreTools.Library.DatItems Machine_Driver_Cocktail, Machine_Driver_SaveState, - // Features - Machine_Features, - Machine_Feature_Type, - Machine_Feature_Status, - Machine_Feature_Overall, - // Devices Machine_Devices, Machine_Device_Type, @@ -378,6 +372,11 @@ namespace SabreTools.Library.DatItems DatItem_Value_Value, DatItem_Value_Default, + // Feature + DatItem_FeatureType, + DatItem_FeatureStatus, + DatItem_FeatureOverall, + // Ram Option DatItem_Content, @@ -440,6 +439,7 @@ namespace SabreTools.Library.DatItems Configuration, DeviceReference, DipSwitch, + Feature, RamOption, Release, Sample, diff --git a/SabreTools.Library/DatItems/Feature.cs b/SabreTools.Library/DatItems/Feature.cs new file mode 100644 index 00000000..a1d9951b --- /dev/null +++ b/SabreTools.Library/DatItems/Feature.cs @@ -0,0 +1,217 @@ +using System.Collections.Generic; +using System.Linq; + +using SabreTools.Library.Filtering; +using Newtonsoft.Json; + +namespace SabreTools.Library.DatItems +{ + /// + /// Represents the a feature of the machine + /// + [JsonObject("feature")] + public class Feature : DatItem + { + #region Fields + + /// + /// Type of feature + /// + [JsonProperty("type")] + public string Type { get; set; } // TODO: (protection|palette|graphics|sound|controls|keyboard|mouse|microphone|camera|disk|printer|lan|wan|timing) + + /// + /// Emulation status + /// + [JsonProperty("status")] + public string Status { get; set; } // TODO: (unemulated|imperfect) + + /// + /// Overall status + /// + [JsonProperty("overall")] + public string Overall { get; set; } // TODO: (unemulated|imperfect) + + #endregion + + #region Accessors + + /// + /// Set fields with given values + /// + /// Mappings dictionary + public override void SetFields(Dictionary mappings) + { + // Set base fields + base.SetFields(mappings); + + // Handle Feature-specific fields + if (mappings.Keys.Contains(Field.DatItem_FeatureType)) + Type = mappings[Field.DatItem_FeatureType]; + + if (mappings.Keys.Contains(Field.DatItem_FeatureStatus)) + Status = mappings[Field.DatItem_FeatureStatus]; + + if (mappings.Keys.Contains(Field.DatItem_FeatureOverall)) + Overall = mappings[Field.DatItem_FeatureOverall]; + } + + #endregion + + #region Constructors + + /// + /// Create a default, empty Feature object + /// + public Feature() + { + ItemType = ItemType.Feature; + } + + #endregion + + #region Cloning Methods + + public override object Clone() + { + return new Feature() + { + ItemType = this.ItemType, + DupeType = this.DupeType, + + AltName = this.AltName, + AltTitle = this.AltTitle, + + Original = this.Original, + OpenMSXSubType = this.OpenMSXSubType, + OpenMSXType = this.OpenMSXType, + Remark = this.Remark, + Boot = this.Boot, + + Part = this.Part, + Features = this.Features, + AreaName = this.AreaName, + AreaSize = this.AreaSize, + AreaWidth = this.AreaWidth, + AreaEndianness = this.AreaEndianness, + Value = this.Value, + LoadFlag = this.LoadFlag, + + Machine = this.Machine.Clone() as Machine, + Source = this.Source.Clone() as Source, + Remove = this.Remove, + + Type = this.Type, + Status = this.Status, + Overall = this.Overall, + }; + } + + #endregion + + #region Comparision Methods + + public override bool Equals(DatItem other) + { + // If we don't have a Feature, return false + if (ItemType != other.ItemType) + return false; + + // Otherwise, treat it as a Feature + Feature newOther = other as Feature; + + // If the Feature information matches + return (Type == newOther.Type && Status == newOther.Status && Overall == newOther.Overall); + } + + #endregion + + #region Filtering + + /// + /// Check to see if a DatItem passes the filter + /// + /// Filter to check against + /// True if the item passed the filter, false otherwise + public override bool PassesFilter(Filter filter) + { + // Check common fields first + if (!base.PassesFilter(filter)) + return false; + + // Filter on type + if (filter.DatItem_FeatureType.MatchesPositiveSet(Type) == false) + return false; + if (filter.DatItem_FeatureType.MatchesNegativeSet(Type) == true) + return false; + + // Filter on status + if (filter.DatItem_FeatureStatus.MatchesPositiveSet(Status) == false) + return false; + if (filter.DatItem_FeatureStatus.MatchesNegativeSet(Status) == true) + return false; + + // Filter on overall + if (filter.DatItem_FeatureOverall.MatchesPositiveSet(Overall) == false) + return false; + if (filter.DatItem_FeatureOverall.MatchesNegativeSet(Overall) == true) + return false; + + return true; + } + + /// + /// Remove fields from the DatItem + /// + /// List of Fields to remove + public override void RemoveFields(List fields) + { + // Remove common fields first + base.RemoveFields(fields); + + // Remove the fields + if (fields.Contains(Field.DatItem_FeatureType)) + Type = null; + + if (fields.Contains(Field.DatItem_FeatureStatus)) + Status = null; + + if (fields.Contains(Field.DatItem_FeatureOverall)) + Overall = null; + } + + #endregion + + #region Sorting and Merging + + /// + /// Replace fields from another item + /// + /// DatItem to pull new information from + /// List of Fields representing what should be updated + public override void ReplaceFields(DatItem item, List fields) + { + // Replace common fields first + base.ReplaceFields(item, fields); + + // If we don't have a Feature to replace from, ignore specific fields + if (item.ItemType != ItemType.Feature) + return; + + // Cast for easier access + Feature newItem = item as Feature; + + // Replace the fields + if (fields.Contains(Field.DatItem_FeatureType)) + Type = newItem.Type; + + if (fields.Contains(Field.DatItem_FeatureStatus)) + Status = newItem.Status; + + if (fields.Contains(Field.DatItem_FeatureOverall)) + Overall = newItem.Overall; + } + + #endregion + } +} diff --git a/SabreTools.Library/DatItems/Machine.cs b/SabreTools.Library/DatItems/Machine.cs index 58a9b3df..e41a8fa9 100644 --- a/SabreTools.Library/DatItems/Machine.cs +++ b/SabreTools.Library/DatItems/Machine.cs @@ -182,12 +182,6 @@ namespace SabreTools.Library.DatItems [JsonProperty("drivers", DefaultValueHandling = DefaultValueHandling.Ignore)] public List Drivers { get; set; } = null; - /// - /// List of associated features - /// - [JsonProperty("features", DefaultValueHandling = DefaultValueHandling.Ignore)] - public List Features { get; set; } = null; - /// /// List of associated devices /// @@ -551,7 +545,6 @@ namespace SabreTools.Library.DatItems Inputs = this.Inputs, Ports = this.Ports, Drivers = this.Drivers, - Features = this.Features, Devices = this.Devices, #endregion diff --git a/SabreTools.Library/Filtering/Filter.cs b/SabreTools.Library/Filtering/Filter.cs index 2eac69ee..8850f014 100644 --- a/SabreTools.Library/Filtering/Filter.cs +++ b/SabreTools.Library/Filtering/Filter.cs @@ -112,12 +112,6 @@ namespace SabreTools.Library.Filtering public FilterItem Machine_Driver_Cocktail { get; private set; } = new FilterItem(); public FilterItem Machine_Driver_SaveState { get; private set; } = new FilterItem(); - // Features - public FilterItem Machine_Features { get; private set; } = new FilterItem() { Neutral = null }; - public FilterItem Machine_Feature_Type { get; private set; } = new FilterItem(); - public FilterItem Machine_Feature_Status { get; private set; } = new FilterItem(); - public FilterItem Machine_Feature_Overall { get; private set; } = new FilterItem(); - // Devices public FilterItem Machine_Devices { get; private set; } = new FilterItem() { Neutral = null }; public FilterItem Machine_Device_Type { get; private set; } = new FilterItem(); @@ -300,6 +294,12 @@ namespace SabreTools.Library.Filtering public FilterItem DatItem_Value_Value { get; private set; } = new FilterItem(); public FilterItem DatItem_Value_Default { get; private set; } = new FilterItem() { Neutral = null }; + // Feature + public FilterItem DatItem_FeatureType { get; private set; } = new FilterItem(); + public FilterItem DatItem_FeatureStatus { get; private set; } = new FilterItem(); + public FilterItem DatItem_FeatureOverall { get; private set; } = new FilterItem(); + + // Ram Option public FilterItem DatItem_Content { get; private set; } = new FilterItem(); @@ -882,35 +882,6 @@ namespace SabreTools.Library.Filtering Machine_Driver_SaveState.PositiveSet.Add(value); break; - // Features - case Field.Machine_Features: - if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) - Machine_Features.Neutral = false; - else - Machine_Features.Neutral = true; - break; - - case Field.Machine_Feature_Type: - if (negate) - Machine_Feature_Type.NegativeSet.Add(value); - else - Machine_Feature_Type.PositiveSet.Add(value); - break; - - case Field.Machine_Feature_Status: - if (negate) - Machine_Feature_Status.NegativeSet.Add(value); - else - Machine_Feature_Status.PositiveSet.Add(value); - break; - - case Field.Machine_Feature_Overall: - if (negate) - Machine_Feature_Overall.NegativeSet.Add(value); - else - Machine_Feature_Overall.PositiveSet.Add(value); - break; - // Devices case Field.Machine_Devices: if (negate || value.Equals("false", StringComparison.OrdinalIgnoreCase)) @@ -1726,6 +1697,28 @@ namespace SabreTools.Library.Filtering DatItem_Value_Default.Neutral = true; break; + // Feature + case Field.DatItem_FeatureType: + if (negate) + DatItem_FeatureType.NegativeSet.Add(value); + else + DatItem_FeatureType.PositiveSet.Add(value); + break; + + case Field.DatItem_FeatureStatus: + if (negate) + DatItem_FeatureStatus.NegativeSet.Add(value); + else + DatItem_FeatureStatus.PositiveSet.Add(value); + break; + + case Field.DatItem_FeatureOverall: + if (negate) + DatItem_FeatureOverall.NegativeSet.Add(value); + else + DatItem_FeatureOverall.PositiveSet.Add(value); + break; + // Ram Option case Field.DatItem_Content: if (negate) diff --git a/SabreTools.Library/Tools/Converters.cs b/SabreTools.Library/Tools/Converters.cs index ab95deb6..9b03d855 100644 --- a/SabreTools.Library/Tools/Converters.cs +++ b/SabreTools.Library/Tools/Converters.cs @@ -596,18 +596,6 @@ namespace SabreTools.Library.Tools case "driver_savestate": return Field.Machine_Driver_SaveState; - case "features": - return Field.Machine_Features; - - case "feature_type": - return Field.Machine_Feature_Type; - - case "feature_status": - return Field.Machine_Feature_Status; - - case "feature_overall": - return Field.Machine_Feature_Overall; - case "devices": return Field.Machine_Devices; @@ -1014,6 +1002,16 @@ namespace SabreTools.Library.Tools case "value_default": return Field.DatItem_Value_Default; + // Feature + case "featuretype": + return Field.DatItem_FeatureType; + + case "featurestatus": + return Field.DatItem_FeatureStatus; + + case "featureoverall": + return Field.DatItem_FeatureOverall; + // Ram Option case "content": return Field.DatItem_Content; @@ -1568,6 +1566,8 @@ namespace SabreTools.Library.Tools return ItemType.DipSwitch; case "disk": return ItemType.Disk; + case "feature": + return ItemType.Feature; case "media": return ItemType.Media; case "ramoption": @@ -1599,6 +1599,7 @@ namespace SabreTools.Library.Tools "device_ref" => ItemType.DeviceReference, "dipswitch" => ItemType.DipSwitch, "disk" => ItemType.Disk, + "feature" => ItemType.Feature, "media" => ItemType.Media, "ramoption" => ItemType.RamOption, "release" => ItemType.Release, @@ -2016,6 +2017,8 @@ namespace SabreTools.Library.Tools return "dipswitch"; case ItemType.Disk: return "disk"; + case ItemType.Feature: + return "feature"; case ItemType.Media: return "media"; case ItemType.RamOption: @@ -2047,6 +2050,7 @@ namespace SabreTools.Library.Tools ItemType.DeviceReference => "device_ref", ItemType.DipSwitch => "dipswitch", ItemType.Disk => "disk", + ItemType.Feature => "feature", ItemType.Media => "media", ItemType.RamOption => "ramoption", ItemType.Release => "release",