diff --git a/RainmeterStudio.Core/Model/Project.cs b/RainmeterStudio.Core/Model/Project.cs index 363c03e8..9636c4d9 100644 --- a/RainmeterStudio.Core/Model/Project.cs +++ b/RainmeterStudio.Core/Model/Project.cs @@ -223,7 +223,7 @@ namespace RainmeterStudio.Core.Model /// public Project() { - Root = new Reference(String.Empty); + Root = new Reference(String.Empty, Reference.ReferenceTargetKind.Project); VariableFiles = new ObservableCollection(); Version = new Version(); MinimumRainmeter = new Version("3.1"); diff --git a/RainmeterStudio.Core/Model/Reference.cs b/RainmeterStudio.Core/Model/Reference.cs index 1412f3da..30a4cd58 100644 --- a/RainmeterStudio.Core/Model/Reference.cs +++ b/RainmeterStudio.Core/Model/Reference.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; using System.Diagnostics; +using System.IO; using System.Linq; using System.Text; using System.Xml.Serialization; @@ -14,9 +16,52 @@ namespace RainmeterStudio.Core.Model /// Reference to a file or folder /// [DebuggerDisplay("QualifiedName = {QualifiedName}, StoragePath = {StoragePath}")] - public class Reference : INotifyCollectionChanged + public class Reference : INotifyCollectionChanged, INotifyPropertyChanged { + /// + /// The kind of item the reference points to + /// + public enum ReferenceTargetKind + { + /// + /// Invalid state + /// + None, + + /// + /// Reference points to a file + /// + File, + + /// + /// Reference points to a directory + /// + Directory, + + /// + /// Reference points to a project + /// + Project + } + private Dictionary _children; + private Reference _parent; + private string _name, _storagePath; + private ReferenceTargetKind _kind; + + #region Events + + /// + /// Triggered when children are added or removed. + /// + public event NotifyCollectionChangedEventHandler CollectionChanged; + + /// + /// Triggered when a property changes its value + /// + public event PropertyChangedEventHandler PropertyChanged; + + #endregion #region Properties @@ -24,7 +69,30 @@ namespace RainmeterStudio.Core.Model /// Gets or sets the parent of this reference /// [XmlIgnore] - public Reference Parent { get; set; } + public Reference Parent + { + get + { + return _parent; + } + set + { + // Unsubscribe from old parent + if (_parent != null) + _parent.PropertyChanged -= Parent_PropertyChanged; + + // Set new parent + _parent = value; + + // Subscribe to new parent + if (_parent != null) + _parent.PropertyChanged += Parent_PropertyChanged; + + // Notify + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Parent")); + } + } /// /// Gets the children references @@ -34,7 +102,7 @@ namespace RainmeterStudio.Core.Model { get { - return new ReadOnlyDictionary(_children); + return new ReadOnlyDictionary(_children); } } @@ -61,7 +129,17 @@ namespace RainmeterStudio.Core.Model [XmlAttribute("name")] public string Name { - get; set; + get + { + return _name; + } + set + { + _name = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Name")); + } } /// @@ -110,8 +188,33 @@ namespace RainmeterStudio.Core.Model [XmlAttribute("storagePath")] public string StoragePath { - get; - set; + get + { + return _storagePath; + } + set + { + _storagePath = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("StoragePath")); + } + } + + [XmlAttribute("targetKind")] + public ReferenceTargetKind TargetKind + { + get + { + return _kind; + } + set + { + _kind = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Kind")); + } } #endregion @@ -119,19 +222,31 @@ namespace RainmeterStudio.Core.Model #region Constructors /// - /// Initializes the reference + /// Initializes the reference as a file reference /// public Reference() - : this(null, null) + : this(null, null, ReferenceTargetKind.File) { } /// /// Initializes the reference /// - /// Project path to item referenced - public Reference(string name) - : this(name, null) + /// Name of this reference + /// Reference kind + public Reference(string name, ReferenceTargetKind kind) + : this(name, null, kind) + { + } + + /// + /// Initializes the reference. + /// Kind is inferred by testing the file on disk. + /// + /// Name of reference + /// Path to item on disk + public Reference(string name, string storagePath) + : this(name, storagePath, InferKind(storagePath)) { } @@ -140,24 +255,37 @@ namespace RainmeterStudio.Core.Model /// /// Name of reference /// Path to item on disk - public Reference(string name, string storagePath) + /// Reference kind + public Reference(string name, string storagePath, ReferenceTargetKind kind) { StoragePath = storagePath; Name = name; + TargetKind = kind; _children = new Dictionary(); } #endregion + #region Exists + /// - /// Checks if the reference has a file on disk + /// Checks if the file exists /// /// - public bool IsOnStorage() + public bool ExistsOnStorage() { - return (StoragePath != null); + if (StoragePath != null) + { + return File.Exists(StoragePath) || Directory.Exists(StoragePath); + } + + return false; } + #endregion + + #region Children/parenting operations + /// /// Adds a child reference /// @@ -241,6 +369,16 @@ namespace RainmeterStudio.Core.Model } } + private void Parent_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (PropertyChanged != null && (e.PropertyName == "Parent" || e.PropertyName == "Name" || e.PropertyName == "QualifiedName")) + PropertyChanged(this, new PropertyChangedEventArgs("QualifiedName")); + } + + #endregion + + #region Object overrides + /// /// Compares a reference to another objects /// @@ -275,10 +413,27 @@ namespace RainmeterStudio.Core.Model return QualifiedName; } - /// - /// Triggered when children are added or removed. - /// - public event NotifyCollectionChangedEventHandler CollectionChanged; + #endregion + + #region Helper methods + + private static ReferenceTargetKind InferKind(string storagePath) + { + ReferenceTargetKind kind = ReferenceTargetKind.None; + + if (Path.GetExtension(storagePath) == ".rsproj") + kind = ReferenceTargetKind.Project; + + else if (File.Exists(storagePath)) + kind = ReferenceTargetKind.File; + + else if (Directory.Exists(storagePath)) + kind = ReferenceTargetKind.Directory; + + return kind; + } + + #endregion } /// diff --git a/RainmeterStudio.Tests/Model/ReferenceTest.cs b/RainmeterStudio.Tests/Model/ReferenceTest.cs index f9573653..f12d6e6e 100644 --- a/RainmeterStudio.Tests/Model/ReferenceTest.cs +++ b/RainmeterStudio.Tests/Model/ReferenceTest.cs @@ -20,8 +20,8 @@ namespace RainmeterStudio.Tests.Model [TestMethod] public void ReferenceConstructorTest() { - Reference root = new Reference("root", "D:\\Data\\Project"); - Reference file = new Reference("f ile__asdf.txt"); + Reference root = new Reference("root", "D:\\Data\\Project", Reference.ReferenceTargetKind.Directory); + Reference file = new Reference("f ile__asdf.txt", Reference.ReferenceTargetKind.File); // Test root Assert.AreEqual("root", root.Name); @@ -45,11 +45,11 @@ namespace RainmeterStudio.Tests.Model public void ReferenceParentingTest() { Reference root = new Reference(String.Empty, "D:\\Data\\Project"); - Reference folder1 = new Reference("folder1"); - Reference folder2 = new Reference("folder 2"); - Reference file1 = new Reference("file1"); - Reference file2 = new Reference("file2.txt"); - Reference file3 = new Reference("file 3.png"); + Reference folder1 = new Reference("folder1", Reference.ReferenceTargetKind.Directory); + Reference folder2 = new Reference("folder 2", Reference.ReferenceTargetKind.Directory); + Reference file1 = new Reference("file1", Reference.ReferenceTargetKind.File); + Reference file2 = new Reference("file2.txt", Reference.ReferenceTargetKind.File); + Reference file3 = new Reference("file 3.png", Reference.ReferenceTargetKind.File); root.Add(folder1); root.Add(file3); @@ -87,11 +87,11 @@ namespace RainmeterStudio.Tests.Model public void ReferenceQualifiedNameTest() { Reference root = new Reference(String.Empty, "D:\\Data\\Project"); - Reference folder1 = new Reference("folder1"); - Reference folder2 = new Reference("folder 2"); - Reference file1 = new Reference("file1"); - Reference file2 = new Reference("file2.txt"); - Reference file3 = new Reference("file 3.png"); + Reference folder1 = new Reference("folder1", Reference.ReferenceTargetKind.Directory); + Reference folder2 = new Reference("folder 2", Reference.ReferenceTargetKind.Directory); + Reference file1 = new Reference("file1", Reference.ReferenceTargetKind.File); + Reference file2 = new Reference("file2.txt", Reference.ReferenceTargetKind.File); + Reference file3 = new Reference("file 3.png", Reference.ReferenceTargetKind.File); root.Add(folder1); root.Add(file3); @@ -134,11 +134,11 @@ namespace RainmeterStudio.Tests.Model public void ReferenceGetReferenceTest() { Reference root = new Reference(String.Empty, "D:\\Data\\Project"); - Reference folder1 = new Reference("folder1"); - Reference folder2 = new Reference("folder 2"); - Reference file1 = new Reference("file1"); - Reference file2 = new Reference("file2.txt"); - Reference file3 = new Reference("file 3.png"); + Reference folder1 = new Reference("folder1", Reference.ReferenceTargetKind.Directory); + Reference folder2 = new Reference("folder 2", Reference.ReferenceTargetKind.Directory); + Reference file1 = new Reference("file1", Reference.ReferenceTargetKind.File); + Reference file2 = new Reference("file2.txt", Reference.ReferenceTargetKind.File); + Reference file3 = new Reference("file 3.png", Reference.ReferenceTargetKind.File); root.Add(folder1); root.Add(file3); diff --git a/RainmeterStudio/RainmeterStudio.csproj b/RainmeterStudio/RainmeterStudio.csproj index 6bde3587..bfe10553 100644 --- a/RainmeterStudio/RainmeterStudio.csproj +++ b/RainmeterStudio/RainmeterStudio.csproj @@ -98,10 +98,12 @@ + + CloseUnsavedDialog.xaml diff --git a/RainmeterStudio/UI/Controller/DocumentController.cs b/RainmeterStudio/UI/Controller/DocumentController.cs index 14fab78b..d429b0f0 100644 --- a/RainmeterStudio/UI/Controller/DocumentController.cs +++ b/RainmeterStudio/UI/Controller/DocumentController.cs @@ -210,7 +210,7 @@ namespace RainmeterStudio.UI.Controller /// public bool Save(IDocumentEditor editor) { - if (editor.AttachedDocument.Reference.IsOnStorage()) + if (editor.AttachedDocument.Reference != null) { DocumentManager.Save(editor.AttachedDocument); return true; diff --git a/RainmeterStudio/UI/Controller/IconProvider.cs b/RainmeterStudio/UI/Controller/IconProvider.cs index 8b3f4128..1025985d 100644 --- a/RainmeterStudio/UI/Controller/IconProvider.cs +++ b/RainmeterStudio/UI/Controller/IconProvider.cs @@ -33,7 +33,7 @@ namespace RainmeterStudio.UI.Controller string key = "ProjectItem"; // Is a file? - if (File.Exists(item.StoragePath)) + if (item.TargetKind == Reference.ReferenceTargetKind.File || item.TargetKind == Reference.ReferenceTargetKind.Project) { if (String.IsNullOrEmpty(Path.GetExtension(item.StoragePath))) key += "Unknown"; @@ -43,7 +43,7 @@ namespace RainmeterStudio.UI.Controller } // Not a file, try to figure out if a directory - else if (item.Count > 0 || Directory.Exists(item.StoragePath)) + else if (item.TargetKind == Reference.ReferenceTargetKind.Directory) { key += "Directory"; } diff --git a/RainmeterStudio/UI/ViewModel/ReferenceViewModel.cs b/RainmeterStudio/UI/ViewModel/ReferenceViewModel.cs index 0d9533aa..e3126868 100644 --- a/RainmeterStudio/UI/ViewModel/ReferenceViewModel.cs +++ b/RainmeterStudio/UI/ViewModel/ReferenceViewModel.cs @@ -35,17 +35,6 @@ namespace RainmeterStudio.UI.ViewModel } } - /// - /// Gets or sets the path - /// - public string Path - { - get - { - return Reference.StoragePath; - } - } - /// /// Gets an enumerable of this object's children /// @@ -120,9 +109,16 @@ namespace RainmeterStudio.UI.ViewModel { Reference = reference; Reference.CollectionChanged += Reference_CollectionChanged; + Reference.PropertyChanged += Reference_PropertyChanged; RefreshChildren(); } + private void Reference_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "Name" && PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Name")); + } + private void Reference_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { List newItems = new List();