rainmeter-studio/RainmeterStudio.Core/Model/Reference.cs

377 lines
11 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
2014-08-31 11:41:24 +00:00
using System.Collections.ObjectModel;
using System.Collections.Specialized;
2014-08-30 07:24:01 +00:00
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
2014-08-31 11:41:24 +00:00
using RainmeterStudio.Core.Utils;
namespace RainmeterStudio.Core.Model
{
/// <summary>
/// Reference to a file or folder
/// </summary>
2014-08-31 11:41:24 +00:00
[DebuggerDisplay("QualifiedName = {QualifiedName}, StoragePath = {StoragePath}")]
public class Reference : INotifyCollectionChanged
{
2014-08-31 11:41:24 +00:00
private Dictionary<string, Reference> _children;
#region Properties
2014-08-30 07:24:01 +00:00
/// <summary>
2014-08-31 11:41:24 +00:00
/// Gets or sets the parent of this reference
/// </summary>
2014-08-31 11:41:24 +00:00
[XmlIgnore]
public Reference Parent { get; set; }
/// <summary>
/// Gets the children references
/// </summary>
[XmlIgnore]
public ReadOnlyDictionary<string, Reference> ChildrenDictionary
2014-08-30 07:24:01 +00:00
{
get
{
2014-08-31 11:41:24 +00:00
return new ReadOnlyDictionary<string,Reference>(_children);
2014-08-30 07:24:01 +00:00
}
}
/// <summary>
2014-08-31 11:41:24 +00:00
/// Gets or sets children
2014-08-30 07:24:01 +00:00
/// </summary>
2014-08-31 11:41:24 +00:00
[XmlArray("children")]
public Reference[] Children
2014-08-30 07:24:01 +00:00
{
get
{
2014-08-31 11:41:24 +00:00
return _children.Values.ToArray();
2014-08-30 07:24:01 +00:00
}
2014-08-31 11:41:24 +00:00
set
{
Clear();
value.ForEach(Add);
}
}
/// <summary>
/// Gets the name of the reference
/// </summary>
[XmlAttribute("name")]
public string Name
{
get; set;
2014-08-30 07:24:01 +00:00
}
/// <summary>
2014-08-31 11:41:24 +00:00
/// Gets the full qualified name of this reference
/// </summary>
2014-08-31 11:41:24 +00:00
[XmlIgnore]
public string QualifiedName
2014-08-30 07:24:01 +00:00
{
get
{
2014-08-31 11:41:24 +00:00
if (Parent == null)
2014-08-30 07:24:01 +00:00
{
2014-08-31 11:41:24 +00:00
// Return name
return Name;
2014-08-30 07:24:01 +00:00
}
2014-08-31 11:41:24 +00:00
else
{
// If it has a parent, get the parent's name
return Parent.QualifiedName + '/' + Name;
}
}
}
2014-08-30 07:24:01 +00:00
2014-08-31 11:41:24 +00:00
/// <summary>
/// Gets the parts of the full qualified name of this reference
/// </summary>
[XmlIgnore]
public IEnumerable<string> QualifiedParts
{
get
{
if (Parent == null)
{
return Enumerable.Repeat(Name, 1);
}
else
{
return Parent.QualifiedParts.Append(Name);
}
2014-08-30 07:24:01 +00:00
}
}
2014-08-31 11:41:24 +00:00
/// <summary>
/// Gets the path to the file on the disk. If reference is in a project, the path should be relative.
/// </summary>
[XmlAttribute("storagePath")]
public string StoragePath
{
get;
set;
}
#endregion
#region Constructors
/// <summary>
/// Initializes the reference
/// </summary>
2014-08-31 11:41:24 +00:00
public Reference()
: this(null, null)
2014-08-30 07:24:01 +00:00
{
2014-08-31 11:41:24 +00:00
}
2014-08-30 07:24:01 +00:00
2014-08-31 11:41:24 +00:00
/// <summary>
/// Initializes the reference
/// </summary>
/// <param name="projectPath">Project path to item referenced</param>
public Reference(string name)
: this(name, null)
{
2014-08-30 07:24:01 +00:00
}
/// <summary>
2014-08-31 11:41:24 +00:00
/// Initializes the reference
2014-08-30 07:24:01 +00:00
/// </summary>
2014-08-31 11:41:24 +00:00
/// <param name="name">Name of reference</param>
/// <param name="storagePath">Path to item on disk</param>
public Reference(string name, string storagePath)
2014-08-30 07:24:01 +00:00
{
2014-08-31 11:41:24 +00:00
StoragePath = storagePath;
Name = name;
_children = new Dictionary<string, Reference>();
2014-08-30 07:24:01 +00:00
}
2014-08-31 11:41:24 +00:00
#endregion
2014-08-30 07:24:01 +00:00
/// <summary>
/// Checks if the reference has a file on disk
/// </summary>
/// <returns></returns>
public bool IsOnStorage()
{
2014-08-31 11:41:24 +00:00
return (StoragePath != null);
}
/// <summary>
/// Adds a child reference
/// </summary>
/// <param name="reference"></param>
public void Add(Reference reference)
{
// Make sure object is not parented yet
if (reference.Parent != null)
throw new ArgumentException("Reference must be removed from its current parent first.");
// Add and parent
reference.Parent = this;
_children.Add(reference.Name, reference);
// Trigger event
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, reference));
}
/// <summary>
/// Removes a reference
/// </summary>
/// <param name="reference">Reference to remove</param>
/// <returns>True if removed successfully</returns>
public bool Remove(Reference reference)
{
// Make sure we are the parent
if (reference.Parent != this)
return false;
// Remove
reference.Parent = null;
bool res = _children.Remove(reference.Name);
// Trigger event
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, reference));
return res;
}
/// <summary>
/// Removes this reference from its parent
/// </summary>
/// <returns>True if unparented successfully</returns>
public bool Unparent()
{
if (Parent != null)
return Parent.Remove(this);
return false;
}
/// <summary>
/// Removes all children
/// </summary>
public void Clear()
{
// Unparent
foreach (var pair in _children)
{
pair.Value.Parent = null;
}
// Clear
_children.Clear();
// Trigger event
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
/// Gets the number of children
/// </summary>
public int Count
{
get
{
return _children.Count;
}
}
/// <summary>
/// Compares a reference to another objects
/// </summary>
/// <param name="obj">Another object</param>
/// <returns>True if objects are equal</returns>
public override bool Equals(object obj)
{
2014-08-30 07:24:01 +00:00
if (obj is Reference)
{
Reference other = (Reference)obj;
2014-08-31 11:41:24 +00:00
return (String.Equals(QualifiedName, other.QualifiedName));
2014-08-30 07:24:01 +00:00
}
return false;
}
/// <summary>
/// Obtains the hash code of this reference
/// </summary>
/// <returns>Hash code</returns>
public override int GetHashCode()
{
2014-08-31 11:41:24 +00:00
return QualifiedName.GetHashCode();
}
/// <summary>
/// Gets the string representation of this reference
/// </summary>
/// <returns>String representation</returns>
public override string ToString()
{
return QualifiedName;
}
2014-08-30 07:24:01 +00:00
2014-08-31 11:41:24 +00:00
/// <summary>
/// Triggered when children are added or removed.
/// </summary>
public event NotifyCollectionChangedEventHandler CollectionChanged;
}
/// <summary>
/// Provides useful methods for references
/// </summary>
public static class ReferenceExtensions
{
/// <summary>
/// Tries to get a reference from the same tree having specified qualified name
/// </summary>
/// <param name="this">Reference contained in the tree</param>
/// <param name="qualifiedName">Full qualified name</param>
/// <param name="output">Found reference</param>
/// <returns>True if succeeded to find the reference</returns>
public static bool TryGetReference(this Reference @this, string qualifiedName, out Reference output)
{
var thisQualifiedName = @this.QualifiedName;
// Am I the reference? return myself
if (qualifiedName.Equals(thisQualifiedName))
2014-08-30 07:24:01 +00:00
{
2014-08-31 11:41:24 +00:00
output = @this;
return true;
2014-08-30 07:24:01 +00:00
}
2014-08-31 11:41:24 +00:00
// Qualified name is a child, look child up
else if (qualifiedName.StartsWith(thisQualifiedName))
2014-08-30 07:24:01 +00:00
{
2014-08-31 11:41:24 +00:00
int startIndex = thisQualifiedName.Length + 1;
int endIndex = qualifiedName.IndexOf('/', startIndex);
string child;
Reference childRef;
if (endIndex < 0)
{
child = qualifiedName.Substring(startIndex);
}
else
{
child = qualifiedName.Substring(startIndex, endIndex - startIndex);
}
// Try to get child
if (@this.ChildrenDictionary.TryGetValue(child, out childRef))
{
return childRef.TryGetReference(qualifiedName, out output);
}
2014-08-30 07:24:01 +00:00
}
2014-08-31 11:41:24 +00:00
// Qualified name is not a child and not 'this', so ask parent to find it
else if (@this.Parent != null)
{
return @this.Parent.TryGetReference(qualifiedName, out output);
}
// Failed to find child
output = null;
return false;
}
2014-08-30 07:24:01 +00:00
/// <summary>
2014-08-31 11:41:24 +00:00
/// Gets a reference from the same tree having specified qualified name
2014-08-30 07:24:01 +00:00
/// </summary>
2014-08-31 11:41:24 +00:00
/// <param name="this">Reference contained in the tree</param>
/// <param name="qualifiedName">Full qualified name</param>
/// <returns>Found reference</returns>
/// <exception cref="ArgumentException">If qualified name not found</exception>
public static Reference GetReference(this Reference @this, string qualifiedName)
{
Reference res;
if (TryGetReference(@this, qualifiedName, out res))
{
return res;
}
else
{
throw new ArgumentException("Could not find reference.");
}
}
/// <summary>
/// Checks if a reference is in the same tree as this
/// </summary>
/// <param name="this">Reference that is in the tree we search in</param>
/// <param name="other">Reference to search</param>
/// <returns>True if the tree contains the reference.</returns>
public static bool TreeContains(this Reference @this, Reference reference)
2014-08-30 07:24:01 +00:00
{
2014-08-31 11:41:24 +00:00
Reference temp;
return TryGetReference(@this, reference.QualifiedName, out temp);
2014-08-30 07:24:01 +00:00
}
}
}