Skip to content

Commit f9e463b

Browse files
committed
refactor: Split out property settings functionality for sharing
1 parent 20e879b commit f9e463b

File tree

3 files changed

+191
-150
lines changed

3 files changed

+191
-150
lines changed

Source/Contrib/SimulatorTester/UserSettings.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// along with Open Rails. If not, see <http://www.gnu.org/licenses/>.
1717

1818
using System.Collections.Generic;
19-
using ORTS.Settings;
19+
using ORTS.Common;
2020

2121
namespace SimulatorTester
2222
{
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
// COPYRIGHT 2009 - 2024 by the Open Rails project.
2+
//
3+
// This file is part of Open Rails.
4+
//
5+
// Open Rails is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// Open Rails is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU General Public License
16+
// along with Open Rails. If not, see <http://www.gnu.org/licenses/>.
17+
18+
using System;
19+
using System.Collections.Generic;
20+
using System.IO;
21+
using System.Linq;
22+
using System.Reflection;
23+
24+
namespace ORTS.Common
25+
{
26+
[AttributeUsage(AttributeTargets.Property)]
27+
public sealed class DefaultAttribute : Attribute
28+
{
29+
public readonly object Value;
30+
public DefaultAttribute(object value)
31+
{
32+
Value = value;
33+
}
34+
}
35+
36+
[AttributeUsage(AttributeTargets.Property)]
37+
public sealed class DoNotSaveAttribute : Attribute
38+
{
39+
}
40+
41+
public abstract class PropertySettingsBase : SettingsBase
42+
{
43+
public PropertySettingsBase(SettingsStore settingsStore)
44+
: base(settingsStore)
45+
{
46+
}
47+
48+
/// <summary>
49+
/// Get a saving property from this instance by name.
50+
/// </summary>
51+
public SavingProperty<T> GetSavingProperty<T>(string name)
52+
{
53+
var property = GetProperty(name);
54+
if (property == null)
55+
return null;
56+
else
57+
return new SavingProperty<T>(this, property, AllowUserSettings);
58+
}
59+
60+
public override object GetDefaultValue(string name)
61+
{
62+
var property = GetType().GetProperty(name);
63+
64+
if (property.GetCustomAttributes(typeof(DefaultAttribute), false).Length > 0)
65+
return (property.GetCustomAttributes(typeof(DefaultAttribute), false)[0] as DefaultAttribute).Value;
66+
67+
throw new InvalidDataException(String.Format("UserSetting {0} has no default value.", property.Name));
68+
}
69+
70+
public PropertyInfo GetProperty(string name)
71+
{
72+
return GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
73+
}
74+
75+
PropertyInfo[] GetProperties()
76+
{
77+
// Skip any properties that implement SettingsBase; they are child setting classes and not individual user settings.
78+
return GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy).Where(pi => !typeof(SettingsBase).IsAssignableFrom(pi.PropertyType)).ToArray();
79+
}
80+
81+
protected override object GetValue(string name)
82+
{
83+
return GetProperty(name).GetValue(this, null);
84+
}
85+
86+
protected override void SetValue(string name, object value)
87+
{
88+
GetProperty(name).SetValue(this, value, null);
89+
}
90+
91+
protected override void Load(Dictionary<string, string> optionsDictionary)
92+
{
93+
foreach (var property in GetProperties())
94+
Load(optionsDictionary, property.Name, property.PropertyType);
95+
}
96+
97+
public override void Save()
98+
{
99+
foreach (var property in GetProperties())
100+
{
101+
if (property.GetCustomAttributes(typeof(DoNotSaveAttribute), false).Length == 0)
102+
{
103+
Console.WriteLine(property.Name, property.PropertyType);
104+
Save(property.Name, property.PropertyType);
105+
}
106+
}
107+
}
108+
109+
public override void Save(string name)
110+
{
111+
var property = GetProperty(name);
112+
if (property.GetCustomAttributes(typeof(DoNotSaveAttribute), false).Length == 0)
113+
Save(property.Name, property.PropertyType);
114+
}
115+
116+
public override void Reset()
117+
{
118+
foreach (var property in GetProperties())
119+
Reset(property.Name);
120+
}
121+
122+
public void Log()
123+
{
124+
foreach (var property in GetProperties().OrderBy(p => p.Name))
125+
{
126+
var value = property.GetValue(this, null);
127+
var source = Sources[property.Name] == Source.CommandLine ? "(command-line)" : Sources[property.Name] == Source.User ? "(user set)" : "";
128+
if (property.PropertyType == typeof(string[]))
129+
Console.WriteLine("{0,-30} = {2,-14} {1}", property.Name, String.Join(", ", ((string[])value).Select(v => v.ToString()).ToArray()), source);
130+
else if (property.PropertyType == typeof(int[]))
131+
Console.WriteLine("{0,-30} = {2,-14} {1}", property.Name, String.Join(", ", ((int[])value).Select(v => v.ToString()).ToArray()), source);
132+
else
133+
Console.WriteLine("{0,-30} = {2,-14} {1}", property.Name, value, source);
134+
}
135+
}
136+
}
137+
138+
/// <summary>
139+
/// A wrapper for a PropertySettingsBase property that saves any new values immediately.
140+
/// </summary>
141+
/// <typeparam name="T">Cast values to this type.</typeparam>
142+
public class SavingProperty<T>
143+
{
144+
private readonly PropertySettingsBase Settings;
145+
private readonly PropertyInfo Property;
146+
private readonly bool DoSave;
147+
148+
internal SavingProperty(PropertySettingsBase settings, PropertyInfo property, bool allowSave = true)
149+
{
150+
Settings = settings;
151+
Property = property;
152+
DoSave = allowSave;
153+
}
154+
155+
/// <summary>
156+
/// Get or set the current value of this property.
157+
/// </summary>
158+
public T Value
159+
{
160+
get => GetValue();
161+
set => SetValue(value);
162+
}
163+
164+
/// <summary>
165+
/// Get the current value of this property.
166+
/// </summary>
167+
public T GetValue()
168+
=> Property.GetValue(Settings) is T cast ? cast : default;
169+
170+
/// <summary>
171+
/// Set the current value of this property.
172+
/// </summary>
173+
public void SetValue(T value)
174+
{
175+
if (!GetValue().Equals(value))
176+
{
177+
Property.SetValue(Settings, value);
178+
if (DoSave)
179+
Settings.Save(Property.Name);
180+
}
181+
}
182+
}
183+
}

Source/Orts.Settings/UserSettings.cs

Lines changed: 7 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// COPYRIGHT 2012, 2013 by the Open Rails project.
1+
// COPYRIGHT 2009 - 2024 by the Open Rails project.
22
//
33
// This file is part of Open Rails.
44
//
@@ -19,29 +19,13 @@
1919
using System.Collections.Generic;
2020
using System.IO;
2121
using System.Linq;
22-
using System.Reflection;
2322
using System.Security.Cryptography;
2423
using System.Text;
2524
using ORTS.Common;
2625

2726
namespace ORTS.Settings
2827
{
29-
[AttributeUsage(AttributeTargets.Property)]
30-
public sealed class DefaultAttribute : Attribute
31-
{
32-
public readonly object Value;
33-
public DefaultAttribute(object value)
34-
{
35-
Value = value;
36-
}
37-
}
38-
39-
[AttributeUsage(AttributeTargets.Property)]
40-
public sealed class DoNotSaveAttribute : Attribute
41-
{
42-
}
43-
44-
public class UserSettings : SettingsBase
28+
public class UserSettings : PropertySettingsBase
4529
{
4630
public static readonly string RegistryKey; // ie @"SOFTWARE\OpenRails\ORTS"
4731
public static readonly string SettingsFilePath; // ie @"C:\Program Files\Open Rails\OpenRails.ini"
@@ -488,7 +472,7 @@ public string DirectXFeatureLevel
488472
public FolderSettings Folders { get; private set; }
489473
public InputSettings Input { get; private set; }
490474
public RailDriverSettings RailDriver { get; private set; }
491-
public ContentSettings Content { get; private set; }
475+
public ContentSettings Content { get; private set; }
492476

493477
public UserSettings(IEnumerable<string> options)
494478
: base(SettingsStore.GetSettingStore(SettingsFilePath, RegistryKey, null))
@@ -503,29 +487,12 @@ public UserSettings(IEnumerable<string> options)
503487
Content = new ContentSettings(options);
504488
}
505489

506-
/// <summary>
507-
/// Get a saving property from this instance by name.
508-
/// </summary>
509-
public SavingProperty<T> GetSavingProperty<T>(string name)
510-
{
511-
var property = GetProperty(name);
512-
if (property == null)
513-
return null;
514-
else
515-
return new SavingProperty<T>(this, property, AllowUserSettings);
516-
}
517-
518490
public override object GetDefaultValue(string name)
519491
{
520-
var property = GetType().GetProperty(name);
521-
522-
if (CustomDefaultValues.ContainsKey(property.Name))
523-
return CustomDefaultValues[property.Name];
492+
if (CustomDefaultValues.ContainsKey(name))
493+
return CustomDefaultValues[name];
524494

525-
if (property.GetCustomAttributes(typeof(DefaultAttribute), false).Length > 0)
526-
return (property.GetCustomAttributes(typeof(DefaultAttribute), false)[0] as DefaultAttribute).Value;
527-
528-
throw new InvalidDataException(String.Format("UserSetting {0} has no default value.", property.Name));
495+
return base.GetDefaultValue(name);
529496
}
530497

531498
public string GetCacheFilePath(string type, string key)
@@ -542,122 +509,13 @@ public string GetCacheFilePath(string type, string key)
542509
return Path.Combine(directory, hash + ".cache-or");
543510
}
544511

545-
public PropertyInfo GetProperty(string name)
546-
{
547-
return GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
548-
}
549-
550-
PropertyInfo[] GetProperties()
551-
{
552-
return GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy).
553-
// leave out the properties based on own, non System classes (f.i. RailDriver property)
554-
Where(pi => pi.PropertyType.FullName.Split('.')[0] == "System").
555-
ToArray();
556-
}
557-
558-
protected override object GetValue(string name)
559-
{
560-
return GetProperty(name).GetValue(this, null);
561-
}
562-
563-
protected override void SetValue(string name, object value)
564-
{
565-
GetProperty(name).SetValue(this, value, null);
566-
}
567-
568-
protected override void Load(Dictionary<string, string> optionsDictionary)
569-
{
570-
foreach (var property in GetProperties())
571-
Load(optionsDictionary, property.Name, property.PropertyType);
572-
}
573-
574512
public override void Save()
575513
{
576-
foreach (var property in GetProperties())
577-
if (property.GetCustomAttributes(typeof(DoNotSaveAttribute), false).Length == 0)
578-
{
579-
Console.WriteLine(property.Name, property.PropertyType);
580-
Save(property.Name, property.PropertyType);
581-
}
582-
514+
base.Save();
583515
Folders.Save();
584516
Input.Save();
585517
RailDriver.Save();
586518
Content.Save();
587519
}
588-
589-
public override void Save(string name)
590-
{
591-
var property = GetProperty(name);
592-
if (property.GetCustomAttributes(typeof(DoNotSaveAttribute), false).Length == 0)
593-
Save(property.Name, property.PropertyType);
594-
}
595-
596-
public override void Reset()
597-
{
598-
foreach (var property in GetProperties())
599-
Reset(property.Name);
600-
}
601-
602-
public void Log()
603-
{
604-
foreach (var property in GetProperties().OrderBy(p => p.Name))
605-
{
606-
var value = property.GetValue(this, null);
607-
var source = Sources[property.Name] == Source.CommandLine ? "(command-line)" : Sources[property.Name] == Source.User ? "(user set)" : "";
608-
if (property.PropertyType == typeof(string[]))
609-
Console.WriteLine("{0,-30} = {2,-14} {1}", property.Name, String.Join(", ", ((string[])value).Select(v => v.ToString()).ToArray()), source);
610-
else if (property.PropertyType == typeof(int[]))
611-
Console.WriteLine("{0,-30} = {2,-14} {1}", property.Name, String.Join(", ", ((int[])value).Select(v => v.ToString()).ToArray()), source);
612-
else
613-
Console.WriteLine("{0,-30} = {2,-14} {1}", property.Name, value, source);
614-
}
615-
}
616-
}
617-
618-
/// <summary>
619-
/// A wrapper for a UserSettings property that saves any new values immediately.
620-
/// </summary>
621-
/// <typeparam name="T">Cast values to this type.</typeparam>
622-
public class SavingProperty<T>
623-
{
624-
private readonly UserSettings Settings;
625-
private readonly PropertyInfo Property;
626-
private readonly bool DoSave;
627-
628-
internal SavingProperty(UserSettings settings, PropertyInfo property, bool allowSave = true)
629-
{
630-
Settings = settings;
631-
Property = property;
632-
DoSave = allowSave;
633-
}
634-
635-
/// <summary>
636-
/// Get or set the current value of this property.
637-
/// </summary>
638-
public T Value
639-
{
640-
get => GetValue();
641-
set => SetValue(value);
642-
}
643-
644-
/// <summary>
645-
/// Get the current value of this property.
646-
/// </summary>
647-
public T GetValue()
648-
=> Property.GetValue(Settings) is T cast ? cast : default;
649-
650-
/// <summary>
651-
/// Set the current value of this property.
652-
/// </summary>
653-
public void SetValue(T value)
654-
{
655-
if (!GetValue().Equals(value))
656-
{
657-
Property.SetValue(Settings, value);
658-
if (DoSave)
659-
Settings.Save(Property.Name);
660-
}
661-
}
662520
}
663521
}

0 commit comments

Comments
 (0)