|
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Xml;
// Part of RJConfig V1.3
// Classes for the config variable
namespace RJConfig
{
/// <summary>
/// Delegate signature for the ConfigFileVariableChanged event. This event is raised when FileWatchEnabled is
/// set to true and some external source has changed the value for the Variable where the event is subscribed.
/// </summary>
/// <param name="sender">The CfgVarNode base class for the Variable where the event is subscribed.</param>
/// <param name="e">CfgEventArgs</param>
public delegate void ConfigFileVariableChanged (object sender, CfgEventArgs e);
/// <summary>
/// Delegate signature for the VariableValueChanged event. This event is fired when there are several
/// Variable instances that shares the same value instance. It is raised for all the Variable instances
/// except the one that made the change.
/// </summary>
/// <param name="sender">The CfgVar base class instance for the Variable which has had its value changed.</param>
/// <param name="e">CfgEventArgs</param>
public delegate void VariableValueChanged (object sender, CfgEventArgs e); /// <remarks>
/// This class is the base class for a Variable. Besides holding information about the variable it is
/// also the common base type used to reference the variable with a comman class type, for function
/// arguments, type in linked list and dictionaries, for example.
/// This class does not hold the actual variable value which means that it does not have to be a generic class.
/// It is the class that is derived from this that holds the actual variable value.
/// </remarks>
public abstract class CfgVarNode
{
/// <summary>
/// Public FileVariableChanged event, raised when the FileVariable for this config
/// variable is changed.
/// </summary>
public event ConfigFileVariableChanged OnConfigFileVariableChanged;
/// <summary>
/// The Config object where the Variable exists.
/// </summary>
public Config cfg;
/// <summary>
/// The Section name for this Variable.
/// </summary>
protected string mSectionName;
/// <summary>
/// The Item name for this Variable.
/// </summary>
protected string mItemName;
/// <summary>
/// The name of this Variable.
/// </summary>
protected string mVariableName;
/// <summary>
/// Public read only property for the Section name for this variable.
/// </summary>
public string SectionName
{
get
{
return mSectionName;
}
}
/// <summary>
/// Public read only property for the Item name for this Variable.
/// </summary>
public string ItemName
{
get
{
return mItemName;
}
}
/// <summary>
/// Public read only property for the name of this Variable.
/// </summary>
public string VariableName
{
get
{
return mVariableName;
}
}
/// <summary>
/// Public read only property for the Section instance for this Variable.
/// </summary>
public Section Section
{
get
{
return cfg.Sections[mSectionName];
}
}
/// <summary>
/// Public read only property for the Item instance for this Variable.
/// </summary>
public Item Item
{
get
{
return Section[mItemName];
}
}
/// <summary>
/// Protected parameterless constructor.
/// </summary>
protected CfgVarNode ()
{
}
/// <summary>
/// Public constructor used to create a CfgVarNode object.
/// </summary>
/// <param name="c">Config object where the Variable exists</param>
/// <param name="SectionName">The name of the Section where the Variable exists</param>
/// <param name="ItemName">The name of the Item where the Variable exists</param>
/// <param name="VariableName">The name of the Variable</param>
public CfgVarNode (Config c, string SectionName, string ItemName, string VariableName)
{
cfg = c;
mSectionName = SectionName;
mItemName = ItemName;
mVariableName = VariableName;
}
/// <summary>
/// Abstract function which must be implemented in the derived Variable class. This function converts the
/// value of a variable in string format to its actual type.
/// </summary>
/// <param name="str">The string representation of the Variables valus as it is in the config file</param>
public abstract void ParseString (string str);
/// <summary>
/// Abstract function which must be implemented in the derived Variable class. This function converts the
/// value for a Variable to a string.
/// </summary>
/// <returns>The string representation of the value for this Variable as it is stored in the config file</returns>
public abstract string MakeString ();
/// <summary>
/// Abstract function which must be implemented in the derived Variable class. This function checks if
/// the value for the variable in the RJFileConfig for this variable is equal to the value for this
/// config variable. Used after a file change event for the associated XML file.
/// </summary>
/// <returns></returns>
public abstract bool IsFileValueEqual ();
/// <summary>
/// This function is called for all Variables for a Config object when its underlying file has been
/// changed and FileWatchEnabled is set to true.
/// If the Variable and the File Variable does not match, the ConfigFileVariableChanged event is raised.
/// Note that the value for this Variable isn't changed to the value of the Variable in the file. This
/// has to be done with the Config.FromFileConfig function. This way the subscriber can check both the
/// current and changed values.
/// </summary>
/// <returns>true if the Variable has a different value than its corresponding FileConfig Variable.</returns>
public bool CheckFileVariableChange ()
{
if (!IsFileValueEqual()) {
if (OnConfigFileVariableChanged != null) {
OnConfigFileVariableChanged(this, new CfgEventArgs());
}
return true;
}
return false;
}
/// <summary>
/// Abstract function to restore the value for this Variable to the default it was originally
/// created with. This is used if an external source has removed the File Variable and the Variable
/// should be set to reflect this.
/// </summary>
public abstract void RestoreToDefault ();
/// <summary>
/// Save the variable value to the FileConfig variable. Note that nothing is saved to
/// file until Config.Flush() is called.
/// </summary>
public void FromFileConfig ()
{
cfg.FromFileConfig(this);
}
/// <summary>
/// Load the FileConfig variable value to Config variable.
/// </summary>
public void ToFileConfig ()
{
cfg.ToFileConfig(this);
}
}
/// <remarks>
/// The generic base class for a Variable which is used to access the actual value of the Variable.
/// The value class CfgTypeT must be derived from generic class CfgType
/// See RJConfigTypes.cs for examples on how to use this for different types of variables.
/// </remarks>
/// <typeparam name="CfgValueTypeT">The value class derived from the generic class CfgValueType that holds the Variable value of type T.</typeparam>
/// <typeparam name="T">The actual type of the value for this Variable.</typeparam>
public class CfgVar<CfgValueTypeT, T> : CfgVarNode where CfgValueTypeT : CfgValueType<T>, new()
{
/// <summary>
/// This is the instance of a value class derived from the generic class CfgValueType
/// that holds the value of the Variable.
/// </summary>
protected CfgValueTypeT cfgValueType;
/// <summary>
/// Property to access the Variable value through the generic CfgValueTypeT class.
/// </summary>
public virtual T CfgData
{
get
{
return cfgValueType.Data;
}
set
{
Changer = true;
// Set this instance as the changer for the value
// Needed in order to only raise the value changed event to other
// variable instances that shares this value.
try {
cfgValueType.Data = value;
} finally {
Changer = false;
}
}
}
/// <summary>
/// Internal member for the default value for this variable.
/// </summary>
protected T _defValue;
/// <summary>
/// Public read only property for the default value for this variable.
/// </summary>
public T DefValue
{
get
{
return _defValue;
}
}
/// <summary>
/// Constructor used to connect the Variable to the file. Def is the default value
/// the variable will get if it doesn't exist in the file.
/// </summary>
/// <param name="c">Config objet for this variable.</param>
/// <param name="SectionName">Name of the Section for this Variable.</param>
/// <param name="ItemName">Name of the Item for this Variable.</param>
/// <param name="VariableName">The name of this Variable.</param>
/// <param name="Def">Default value for the Variable if it doesn't exist in the file.</param>
public CfgVar (Config c, string SectionName, string ItemName, string VariableName, T Def)
: base(c, SectionName, ItemName, VariableName)
{
_defValue = Def;
CfgVarNode cvn;
cvn = c.Sections.FindVariable(SectionName, ItemName, VariableName);
if (cvn != null) {
// If this variable already exists, the same instance of the CfgTypeT class is used.
// which means that the instance of the CfgVar actually uses the same FileConfig variable.
// Two different objects can then have two separate CfgVar objects (for the same variable)
// that uses the same FileConfig value. No need to share the CfgVar between several objects,
// just create two or more instances of CfgVar's for the same variable (same type, sectionname,
// itemname and variablename).
//
// This could also be used to share variables between objects with no other connection
// than the config class.
CfgVar<CfgValueTypeT, T> other = cvn as CfgVar<CfgValueTypeT, T>;
cfgValueType = other.cfgValueType;
} else {
cfgValueType = new CfgValueTypeT();
CfgData = Def;
c.AddVariable(this);
}
}
/// <summary>
/// Implementation of the abstract function ParseString in the CfgVarNode base class.
/// </summary>
/// <param name="str">The value for this Variable as a string. As it is represented in the config file.</param>
public override void ParseString (string str)
{
cfgValueType.ParseString(str);
}
/// <summary>
/// Implementation of the abstract function MakeString() in the CfgVarNode base class.
/// </summary>
/// <returns>The value for this Variable as a string. As it is represented in the config file.</returns>
public override string MakeString ()
{
return cfgValueType.MakeString();
}
/// <summary>
/// Private member to indicate that it is this instance of the variable that is changing the value
/// of the variable in order to be able to only raise the value changed event to all other variable
/// instances that shares this value.
/// </summary>
private bool Changer = false;
/// <summary>
/// Internal VariableValueChanged event. Used to keep track of the public OnValueChanged
/// event so that this class can add the ValueChanged event handler to its value class when event handlers
/// for the VariableValueChanged event.
/// <seealso cref="OnValueChanged"/>
/// </summary>
private event VariableValueChanged _e;
/// <summary>
/// Event that is raised when the value of this variable has been changed by another variable instance
/// that shares the same value object. The event is only raised for the instances that hasn't changed
/// the value.
/// </summary>
public event VariableValueChanged OnValueChanged
{
add
{
_e += value;
cfgValueType.OnValueChanged += cfgValueChanged;
}
remove
{
_e -= value;
cfgValueType.OnValueChanged -= cfgValueChanged;
}
}
/// <summary>
/// Event handler for the ValueChanged event for the value of this variable.
/// This raises the VariableValueChanged event for all instances for this
/// varaible value except the one that changed the value.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void cfgValueChanged (object sender, CfgEventArgs e)
{
if (_e != null && !Changer) {
_e(this, new CfgEventArgs());
}
}
/// <summary>
/// Implementation of the abstract base class function that compares if the value in the RJFileConfig object
/// for this variable is equal to the value of this config variable.
/// This is used to check if the file variable has changed due to a file change event in order
/// to be able to take action on a changed variable from an external source.
/// </summary>
/// <returns>true if the filevalue in the RJFileConfig object for this variable is equal to
/// the value of this variable.</returns>
public override bool IsFileValueEqual ()
{
FileVariable fv = cfg.fc.FindVariable(SectionName, ItemName, VariableName);
if (fv != null) { // FileVariable exists.
return (fv.Data.CompareTo(MakeString()) == 0);
} else { // FileVariable does not exist (or is removed). Compare with the default value.
return CfgData.Equals(_defValue);
}
}
/// <summary>
/// Implementation of the abstract base class function to restore the value to the default value.
/// </summary>
public override void RestoreToDefault ()
{
CfgData = _defValue;
}
}
/// <remarks>
/// VariableDict is a class that extends a Dictionary for Variables. The key is the name of the Variable
/// and the value (in the dictionary) is the CfgVarNode base class for the Variable object.
/// </remarks>
public class VariableDict : Dictionary<string, CfgVarNode>
{
/// <summary>
/// Adds a variable, referenced through its CfgVarNode base class, to the dictionary.
/// </summary>
/// <param name="cfgn">the Variable object which is derived from a CfgVar generic class which in turn is
/// derived from CfgVarNode which is used as the least common denominator in the dictionary</param>
public void AddCfgVarNode (CfgVarNode cfgn)
{
if (!ContainsKey(cfgn.VariableName)) {
Add(cfgn.VariableName, cfgn);
}
}
/// <summary>
/// Find a Variable in the dictionary from its name.
/// </summary>
/// <param name="VariableName">The name of the Variable</param>
/// <returns>The CfgVarNode base class for the Variable if it exists, otherwize null.</returns>
public CfgVarNode FindVariable (string VariableName)
{
CfgVarNode v;
if (TryGetValue(VariableName, out v))
return v;
return null;
}
/// <summary>
/// Save all Variables in the dictionary to the config file.
/// </summary>
public void SaveToFileConf ()
{
foreach (KeyValuePair<string, CfgVarNode> kvp in this) {
kvp.Value.cfg.ToFileConfig(kvp.Value);
}
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.