From 51e0b0d612af426fc93f2e7c61edd32e7613b1e6 Mon Sep 17 00:00:00 2001 From: Tiberiu Chibici Date: Fri, 12 Sep 2014 13:19:01 +0300 Subject: [PATCH] Work on project editor --- RainmeterStudio.Core/Model/Project.cs | 116 ++++++++++++++++-- .../Storage/IDocumentStorage.cs | 8 +- RainmeterStudio.SkinDesigner/SkinStorage.cs | 8 +- .../Storage/ProjectStorageTest.cs | 15 +-- RainmeterStudio.TextEditor/TextStorage.cs | 8 +- RainmeterStudio/Business/DocumentManager.cs | 12 +- RainmeterStudio/Business/ProjectManager.cs | 6 +- .../Editor/ProjectEditor/ProjectDocument.cs | 75 +++++++++++ .../ProjectEditor/ProjectEditorFactory.cs | 38 ++++++ .../Editor/ProjectEditor/ProjectEditorUI.xaml | 31 +++++ .../ProjectEditor/ProjectEditorUI.xaml.cs | 63 ++++++++++ RainmeterStudio/MainClass.cs | 2 +- RainmeterStudio/RainmeterStudio.csproj | 14 ++- RainmeterStudio/Storage/ProjectStorage.cs | 69 ----------- RainmeterStudio/UI/MainWindow.xaml.cs | 1 - .../UI/Panels/ProjectPanel.xaml.cs | 15 --- 16 files changed, 354 insertions(+), 127 deletions(-) create mode 100644 RainmeterStudio/Editor/ProjectEditor/ProjectDocument.cs create mode 100644 RainmeterStudio/Editor/ProjectEditor/ProjectEditorFactory.cs create mode 100644 RainmeterStudio/Editor/ProjectEditor/ProjectEditorUI.xaml create mode 100644 RainmeterStudio/Editor/ProjectEditor/ProjectEditorUI.xaml.cs delete mode 100644 RainmeterStudio/Storage/ProjectStorage.cs diff --git a/RainmeterStudio.Core/Model/Project.cs b/RainmeterStudio.Core/Model/Project.cs index 24e9bbcf..363c03e8 100644 --- a/RainmeterStudio.Core/Model/Project.cs +++ b/RainmeterStudio.Core/Model/Project.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; using System.Linq; using System.Text; using System.Xml.Serialization; @@ -12,8 +14,13 @@ namespace RainmeterStudio.Core.Model /// /// Defines a Rainmeter Studio project /// - public class Project + public class Project : INotifyPropertyChanged { + private string _author; + private Reference _autoLoadFile; + private Version _version, _minimumWindows, _minimumRainmeter; + private Reference _root; + #region Properties /// @@ -29,6 +36,9 @@ namespace RainmeterStudio.Core.Model set { Root.Name = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Name")); } } @@ -45,6 +55,9 @@ namespace RainmeterStudio.Core.Model set { Root.StoragePath = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Name")); } } @@ -52,19 +65,58 @@ namespace RainmeterStudio.Core.Model /// Gets or sets the author of the project /// [XmlElement(ElementName = "author", Order = 2)] - public string Author { get; set; } + public string Author + { + get + { + return _author; + } + set + { + _author = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Author")); + } + } /// /// Gets or sets the version of the project /// [XmlElement(ElementName = "version", Order = 3)] - public Version Version { get; set; } + public Version Version + { + get + { + return _version; + } + set + { + _version = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Version")); + } + } /// /// Gets or sets the reference to the file that automatically loads at package installation /// [XmlIgnore] - public Reference AutoLoadFile { get; set; } + public Reference AutoLoadFile + { + get + { + return _autoLoadFile; + } + set + { + _autoLoadFile = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("AutoLoadFile")); + } + } /// /// Gets or sets the qualified name of the auto load file @@ -86,7 +138,7 @@ namespace RainmeterStudio.Core.Model /// Gets or sets the list of variable files /// [XmlIgnore] - public List VariableFiles { get; set; } + public ObservableCollection VariableFiles { get; private set; } /// /// Gets or sets the list of variable files qualified names @@ -101,7 +153,7 @@ namespace RainmeterStudio.Core.Model set { VariableFiles.Clear(); - VariableFiles.AddRange(value.Select(x => Root.GetReference(x))); + value.Select(x => Root.GetReference(x)).ForEach(VariableFiles.Add); } } @@ -109,19 +161,58 @@ namespace RainmeterStudio.Core.Model /// Gets or sets the minimum rainmeter version /// [XmlElement(ElementName = "minimumRainmeter", Order = 4)] - public Version MinimumRainmeter { get; set; } + public Version MinimumRainmeter + { + get + { + return _minimumRainmeter; + } + set + { + _minimumRainmeter = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("MinimumRainmeter")); + } + } /// /// Gets or sets the minimum Windows version /// [XmlElement(ElementName = "minimumWindows", Order = 5)] - public Version MinimumWindows { get; set; } + public Version MinimumWindows + { + get + { + return _minimumWindows; + } + set + { + _minimumWindows = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("MinimumWindows")); + } + } /// /// Gets or sets the root node /// [XmlElement(ElementName = "root", Order = 6)] - public Reference Root { get; set; } + public Reference Root + { + get + { + return _root; + } + set + { + _root = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Root")); + } + } #endregion @@ -133,7 +224,7 @@ namespace RainmeterStudio.Core.Model public Project() { Root = new Reference(String.Empty); - VariableFiles = new List(); + VariableFiles = new ObservableCollection(); Version = new Version(); MinimumRainmeter = new Version("3.1"); MinimumWindows = new Version("5.1"); @@ -155,5 +246,10 @@ namespace RainmeterStudio.Core.Model } #endregion + + /// + /// Triggered when a property changes + /// + public event PropertyChangedEventHandler PropertyChanged; } } diff --git a/RainmeterStudio.Core/Storage/IDocumentStorage.cs b/RainmeterStudio.Core/Storage/IDocumentStorage.cs index f6d8f1e1..a69a66ca 100644 --- a/RainmeterStudio.Core/Storage/IDocumentStorage.cs +++ b/RainmeterStudio.Core/Storage/IDocumentStorage.cs @@ -13,27 +13,27 @@ namespace RainmeterStudio.Core.Storage /// /// Path to file /// Read document - IDocument Read(string path); + IDocument ReadDocument(string path); /// /// Writes a document to a file /// /// Path to file /// Document to write - void Write(string path, IDocument document); + void WriteDocument(IDocument document, string path); /// /// Tests if the file can be read by this storage /// /// Path to file /// True if file can be read - bool CanRead(string path); + bool CanReadDocument(string path); /// /// Tests if the document can be written by this storage /// /// Document type /// True if the document can be written - bool CanWrite(Type documentType); + bool CanWriteDocument(Type documentType); } } diff --git a/RainmeterStudio.SkinDesigner/SkinStorage.cs b/RainmeterStudio.SkinDesigner/SkinStorage.cs index a5804b07..8e173cb1 100644 --- a/RainmeterStudio.SkinDesigner/SkinStorage.cs +++ b/RainmeterStudio.SkinDesigner/SkinStorage.cs @@ -9,22 +9,22 @@ namespace RainmeterStudio.SkinDesignerPlugin { public class SkinStorage : IDocumentStorage { - public IDocument Read(string path) + public IDocument ReadDocument(string path) { throw new NotImplementedException(); } - public void Write(string path, IDocument document) + public void WriteDocument(IDocument document, string path) { throw new NotImplementedException(); } - public bool CanRead(string path) + public bool CanReadDocument(string path) { throw new NotImplementedException(); } - public bool CanWrite(Type documentType) + public bool CanWriteDocument(Type documentType) { throw new NotImplementedException(); } diff --git a/RainmeterStudio.Tests/Storage/ProjectStorageTest.cs b/RainmeterStudio.Tests/Storage/ProjectStorageTest.cs index 3476ae8c..56ed1de4 100644 --- a/RainmeterStudio.Tests/Storage/ProjectStorageTest.cs +++ b/RainmeterStudio.Tests/Storage/ProjectStorageTest.cs @@ -1,11 +1,8 @@ -using System; -using System.Text; -using System.Collections.Generic; +using System.IO; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; -using RainmeterStudio.Storage; -using System.IO; using RainmeterStudio.Core.Model; +using RainmeterStudio.Editor.ProjectEditor; using Version = RainmeterStudio.Core.Utils.Version; namespace RainmeterStudio.Tests.Storage @@ -35,8 +32,8 @@ namespace RainmeterStudio.Tests.Storage Project project = CreateProject(); // Save and load - ProjectStorage.Save(project, filename); - Project res = ProjectStorage.Load(filename); + ProjectStorage.Write(project, filename); + Project res = ProjectStorage.Read(filename); // Verify results Assert.IsNotNull(res); @@ -59,8 +56,8 @@ namespace RainmeterStudio.Tests.Storage Project project = new Project(); // Save and load project - ProjectStorage.Save(project, filename); - Project res = ProjectStorage.Load(filename); + ProjectStorage.Write(project, filename); + Project res = ProjectStorage.Read(filename); // Test results Assert.IsNotNull(res); diff --git a/RainmeterStudio.TextEditor/TextStorage.cs b/RainmeterStudio.TextEditor/TextStorage.cs index d63198b1..324ee59e 100644 --- a/RainmeterStudio.TextEditor/TextStorage.cs +++ b/RainmeterStudio.TextEditor/TextStorage.cs @@ -13,7 +13,7 @@ namespace RainmeterStudio.TextEditorPlugin public class TextStorage : IDocumentStorage { /// - IDocument IDocumentStorage.Read(string path) + public IDocument ReadDocument(string path) { TextDocument document = new TextDocument(); document.Reference = new Reference(Path.GetFileName(path), path); @@ -23,7 +23,7 @@ namespace RainmeterStudio.TextEditorPlugin } /// - public void Write(string path, IDocument document) + public void WriteDocument(IDocument document, string path) { TextDocument textDocument = document as TextDocument; @@ -34,7 +34,7 @@ namespace RainmeterStudio.TextEditorPlugin } /// - public bool CanRead(string path) + public bool CanReadDocument(string path) { // Open the file FileStream file = File.OpenRead(path); @@ -64,7 +64,7 @@ namespace RainmeterStudio.TextEditorPlugin return true; } - public bool CanWrite(Type documentType) + public bool CanWriteDocument(Type documentType) { return documentType.Equals(typeof(TextDocument)); } diff --git a/RainmeterStudio/Business/DocumentManager.cs b/RainmeterStudio/Business/DocumentManager.cs index 821a0f37..7408cf0e 100644 --- a/RainmeterStudio/Business/DocumentManager.cs +++ b/RainmeterStudio/Business/DocumentManager.cs @@ -156,7 +156,7 @@ namespace RainmeterStudio.Business throw new ArgumentException("Reference cannot be empty"); // Save - storage.Write(document.Reference.StoragePath, document); + storage.WriteDocument(document, document.Reference.StoragePath); // Clear dirty flag document.IsDirty = false; @@ -173,7 +173,7 @@ namespace RainmeterStudio.Business var storage = FindStorage(document); // Save - storage.Write(path, document); + storage.WriteDocument(document, path); // Update reference document.Reference = new Reference(Path.GetFileName(path), path); @@ -193,7 +193,7 @@ namespace RainmeterStudio.Business var storage = FindStorage(document); // Save - storage.Write(path, document); + storage.WriteDocument(document, path); } /// @@ -249,9 +249,9 @@ namespace RainmeterStudio.Business IDocument document = null; foreach (var storage in Storages) - if (storage.CanRead(path)) + if (storage.CanReadDocument(path)) { - document = storage.Read(path); + document = storage.ReadDocument(path); break; } @@ -272,7 +272,7 @@ namespace RainmeterStudio.Business IDocumentStorage storage = null; foreach (var s in Storages) - if (s.CanWrite(document.GetType())) + if (s.CanWriteDocument(document.GetType())) { storage = s; break; diff --git a/RainmeterStudio/Business/ProjectManager.cs b/RainmeterStudio/Business/ProjectManager.cs index 10ed75ee..29fc26fa 100644 --- a/RainmeterStudio/Business/ProjectManager.cs +++ b/RainmeterStudio/Business/ProjectManager.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using RainmeterStudio.Core.Model; using RainmeterStudio.Core.Storage; -using RainmeterStudio.Storage; +using RainmeterStudio.Editor.ProjectEditor; namespace RainmeterStudio.Business { @@ -88,7 +88,7 @@ namespace RainmeterStudio.Business Close(); // Open using storage - ActiveProject = Storage.Load(path); + ActiveProject = Storage.Read(path); ActiveProject.Path = path; // Raise event @@ -106,7 +106,7 @@ namespace RainmeterStudio.Business throw new InvalidOperationException("Cannot save a project that is not opened."); // Save - Storage.Save(ActiveProject); + Storage.Write(ActiveProject); } /// diff --git a/RainmeterStudio/Editor/ProjectEditor/ProjectDocument.cs b/RainmeterStudio/Editor/ProjectEditor/ProjectDocument.cs new file mode 100644 index 00000000..6300b5ee --- /dev/null +++ b/RainmeterStudio/Editor/ProjectEditor/ProjectDocument.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RainmeterStudio.Core.Model; + +namespace RainmeterStudio.Editor.ProjectEditor +{ + /// + /// A project document + /// + /// Unlike the Project class, this class implements the 'IDocument' + /// interface. This is a proxy class for the actual project. + public class ProjectDocument : IDocument + { + private Reference _reference; + private bool _isDirty = false; + + /// + /// Gets or sets the reference of the document + /// + public Reference Reference + { + get + { + return _reference; + } + set + { + _reference = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("Reference")); + } + } + + /// + public bool IsDirty + { + get + { + return _isDirty; + } + + set + { + _isDirty = value; + + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs("IsDirty")); + } + } + + /// + /// Gets the project this project document is linked to + /// + public Project Project { get; private set; } + + /// + /// Event triggered when a property changes value + /// + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Initializes this project document + /// + /// The actual project this document is linked to + public ProjectDocument(Project project) + { + Project = project; + } + } +} diff --git a/RainmeterStudio/Editor/ProjectEditor/ProjectEditorFactory.cs b/RainmeterStudio/Editor/ProjectEditor/ProjectEditorFactory.cs new file mode 100644 index 00000000..28747b11 --- /dev/null +++ b/RainmeterStudio/Editor/ProjectEditor/ProjectEditorFactory.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RainmeterStudio.Core; +using RainmeterStudio.Core.Documents; +using RainmeterStudio.Core.Model; + +namespace RainmeterStudio.Editor.ProjectEditor +{ + /// + /// Project editor factory + /// + [PluginExport] + public class ProjectEditorFactory : IDocumentEditorFactory + { + /// + /// Creates a new project editor + /// + /// The project document + /// Created editor + public IDocumentEditor CreateEditor(IDocument document) + { + return new ProjectEditorUI((ProjectDocument)document); + } + + /// + /// Checks if this editor can edit documents of given type + /// + /// Type + /// True if the project editor can edit that kind of document + public bool CanEdit(Type type) + { + return (type.Equals(typeof(ProjectDocument))); + } + } +} diff --git a/RainmeterStudio/Editor/ProjectEditor/ProjectEditorUI.xaml b/RainmeterStudio/Editor/ProjectEditor/ProjectEditorUI.xaml new file mode 100644 index 00000000..ea0dcde4 --- /dev/null +++ b/RainmeterStudio/Editor/ProjectEditor/ProjectEditorUI.xaml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + Name: + + + Author: + + + + + diff --git a/RainmeterStudio/Editor/ProjectEditor/ProjectEditorUI.xaml.cs b/RainmeterStudio/Editor/ProjectEditor/ProjectEditorUI.xaml.cs new file mode 100644 index 00000000..7eadc16a --- /dev/null +++ b/RainmeterStudio/Editor/ProjectEditor/ProjectEditorUI.xaml.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using RainmeterStudio.Core.Documents; +using RainmeterStudio.Core.Model; + +namespace RainmeterStudio.Editor.ProjectEditor +{ + /// + /// Interaction logic for ProjectEditorUI.xaml + /// + public partial class ProjectEditorUI : UserControl, IDocumentEditor + { + /// + /// Gets the attached project document being edited + /// + public ProjectDocument Document { get; private set; } + + /// + /// Gets the attached document + /// + public IDocument AttachedDocument + { + get { return Document; } + } + + /// + /// Gets the UI element to be displayed in the document window + /// + public UIElement EditorUI + { + get { return this; } + } + + /// + /// Initializes this project editor UI + /// + /// + public ProjectEditorUI(ProjectDocument document) + { + InitializeComponent(); + Document = document; + Document.Project.PropertyChanged += Project_PropertyChanged; + DataContext = Document.Project; + } + + private void Project_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + Document.IsDirty = true; + } + } +} diff --git a/RainmeterStudio/MainClass.cs b/RainmeterStudio/MainClass.cs index 635be1a9..fc6897e9 100644 --- a/RainmeterStudio/MainClass.cs +++ b/RainmeterStudio/MainClass.cs @@ -8,7 +8,7 @@ using RainmeterStudio.Business; using RainmeterStudio.Core.Documents; using RainmeterStudio.Core.Model; using RainmeterStudio.Core.Storage; -using RainmeterStudio.Storage; +using RainmeterStudio.Editor.ProjectEditor; using RainmeterStudio.UI; using RainmeterStudio.UI.Controller; diff --git a/RainmeterStudio/RainmeterStudio.csproj b/RainmeterStudio/RainmeterStudio.csproj index 1e5ba97b..cc42d387 100644 --- a/RainmeterStudio/RainmeterStudio.csproj +++ b/RainmeterStudio/RainmeterStudio.csproj @@ -65,6 +65,10 @@ + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -73,6 +77,11 @@ + + + + ProjectEditorUI.xaml + @@ -87,7 +96,7 @@ True Strings.resx - + @@ -248,6 +257,9 @@ + + +