diff --git a/CSharp/Libraries/UniversalEditor.Core/Association.cs b/CSharp/Libraries/UniversalEditor.Core/Association.cs index f13d267c..c7b32839 100644 --- a/CSharp/Libraries/UniversalEditor.Core/Association.cs +++ b/CSharp/Libraries/UniversalEditor.Core/Association.cs @@ -32,6 +32,9 @@ namespace UniversalEditor /// public class Association { + /// + /// Defines a collection of s. + /// public class AssociationCollection : System.Collections.ObjectModel.Collection { @@ -40,24 +43,42 @@ namespace UniversalEditor private static List _associations = new List(); - + /// + /// Registers the specified if it is not already registered. + /// + /// true if the is not already registered and has been added; false otherwise. + /// The to register. public static bool Register(Association assoc) { if (_associations.Contains(assoc)) return false; _associations.Add(assoc); return true; } + /// + /// Unregisters the specified if it has been registered. + /// + /// true if the given has been unregistered; false if the given has not been registered. + /// The to unregister. public static bool Unregister(Association assoc) { if (!_associations.Contains(assoc)) return false; _associations.Remove(assoc); return true; } - + /// + /// Returns an array of all known s. + /// + /// The all associations. public static Association[] GetAllAssociations() { return _associations.ToArray(); } + /// + /// Gets an array of s that match the given or . + /// + /// An array of s that match the given or . + /// The to compare. + /// The to compare. public static Association[] FromObjectModelOrDataFormat(ObjectModelReference objectModel = null, DataFormatReference dataFormat = null) { Association[] _associations = Association.GetAllAssociations(); @@ -71,11 +92,18 @@ namespace UniversalEditor } return associations.ToArray(); } + /// + /// Gets an array of s that match the given or file name filters. + /// + /// An array of s that match the given or file name filters. + /// The to compare. + /// Not implemented. public static Association[] FromAccessor(Accessor accessor = null, string fileNameFilter = null) { Association[] assocs = Association.GetAllAssociations(); List associations = new List(); + // FIXME: the fileNameFilter parameter is not referenced in this method body // stopwatch diagnostics determined a nested for loop is 0.0547024 ms faster than foreach for (int i = 0; i < assocs.Length; i++) { @@ -120,6 +148,10 @@ namespace UniversalEditor /// public DataFormatReference.DataFormatReferenceCollection DataFormats { get { return mvarDataFormats; } } + /// + /// Returns a that represents the current . + /// + /// A that represents the current . public override string ToString() { StringBuilder sb = new StringBuilder(); @@ -149,6 +181,11 @@ namespace UniversalEditor return sb.ToString(); } + /// + /// Returns an array of s that satisfy the given . + /// + /// An array of s that match the specified criteria. + /// The that define the criteria to match when searching for s. public static Association[] FromCriteria(AssociationCriteria ac) { List associations = new List(); diff --git a/CSharp/Libraries/UniversalEditor.Core/DataFormat.cs b/CSharp/Libraries/UniversalEditor.Core/DataFormat.cs index ab1c0d5c..4c0458d1 100644 --- a/CSharp/Libraries/UniversalEditor.Core/DataFormat.cs +++ b/CSharp/Libraries/UniversalEditor.Core/DataFormat.cs @@ -28,8 +28,14 @@ using UniversalEditor.IO; namespace UniversalEditor { + /// + /// The on-disk representation of data stored in an and accessed by an . + /// public abstract class DataFormat : References { + /// + /// Represents a collection of objects. + /// public class DataFormatCollection : System.Collections.ObjectModel.Collection { @@ -45,20 +51,34 @@ namespace UniversalEditor get { return mvarReference; } } + /// + /// Creates a for this and registers it for future use. + /// + /// The that provides metadata and other information about this . public DataFormatReference MakeReference() { DataFormatReference dfr = MakeReferenceInternal(); DataFormatReference.Register(dfr); return dfr; } + /// + /// Creates a new . The returned is not cached. It is recommended that subclasses + /// override this method and cache their own personal instances of containing the appropriate metadata for their + /// subclassed implementations. + /// + /// The that provides metadata and other information about this . protected virtual DataFormatReference MakeReferenceInternal() { DataFormatReference dfr = new DataFormatReference(GetType()); return dfr; } - - private Accessor mvarAccessor = null; - protected internal Accessor Accessor { get { return mvarAccessor; } set { mvarAccessor = value; } } + + /// + /// The used to read and write data. + /// + /// The used to read and write data. + [Obsolete("In next version, Accessor will be a parameter passed into LoadInternal / SaveInternal methods")] + protected internal Accessor Accessor { get; set; } = null; /// /// Continues loading the file into the specified with a different @@ -68,10 +88,15 @@ namespace UniversalEditor /// The used to parse the document. protected void ContinueLoading(ref ObjectModel objectModel, DataFormat otherDataFormat) { - otherDataFormat.Accessor = mvarAccessor; + otherDataFormat.Accessor = Accessor; otherDataFormat.Load(ref objectModel); } + /// + /// Determines if the given is supported by this . + /// + /// true, if the specified is supported by this , false otherwise. + /// The whose support should be checked. protected virtual bool IsObjectModelSupported(ObjectModel objectModel) { DataFormatReference dfr = MakeReferenceInternal(); @@ -79,6 +104,26 @@ namespace UniversalEditor return dfr.Capabilities.Contains(omr.Type) || dfr.Capabilities.Contains(omr.ID); } + /// + /// Reads the contents of the specified from the using this . + /// + /// + /// + /// Before the actual content is read using this 's method, a is + /// created and the specified is pushed onto the stack. The method is then called, with the + /// stack as its only parameter. A single is then popped off the stack, and the method is called + /// with this as its only parameter. After the actual content is read, the method is called, + /// again passing in the stack as its only parameter. + /// + /// + /// Note that the passed into the method may not necessarily be the same as the + /// that is eventually passed into the method. It is possible to subclass s to create new formats + /// based on existing ones. XML, ZIP, and RIFF are a few good examples of s that serve as the base for others. For more + /// information, refer to the documentation for the , , and + /// methods. + /// + /// + /// The whose content should be written using this . [DebuggerNonUserCode()] public void Load(ref ObjectModel objectModel) { @@ -99,9 +144,29 @@ namespace UniversalEditor */ AfterLoadInternal(stack); } + /// + /// Writes the contents of the specified to the using this . + /// + /// + /// + /// Before the actual content is written using this 's method, a is + /// created and the specified is pushed onto the stack. The method is then called, with the + /// stack as its only parameter. A single is then popped off the stack, and the method is called + /// with this as its only parameter. After the actual content is written, the method is called, + /// again passing in the stack as its only parameter. + /// + /// + /// Note that the passed into the method may not necessarily be the same as the + /// that is eventually passed into the method. It is possible to subclass s to create new formats + /// based on existing ones. XML, ZIP, and RIFF are a few good examples of s that serve as the base for others. For more + /// information, refer to the documentation for the , , and + /// methods. + /// + /// + /// The whose content should be written using this . public void Save(ObjectModel objectModel) { - if (objectModel == null) throw new ArgumentNullException("objectModel", "objectModel cannot be null"); + if (objectModel == null) throw new ArgumentNullException(nameof(objectModel), "objectModel cannot be null"); Stack stack = new Stack(); stack.Push(objectModel); @@ -114,18 +179,83 @@ namespace UniversalEditor AfterSaveInternal(stack); } + /// + /// Reads the data from the into the specified . + /// + /// The into which to load data. protected abstract void LoadInternal(ref ObjectModel objectModel); + /// + /// Writes the contents of the specified to the . + /// + /// The from which to save data. protected abstract void SaveInternal(ObjectModel objectModel); + /// + /// Method called BEFORE the method is called on the original 's subclass. + /// + /// + /// When inheriting from a + /// subclass (e.g. XMLDataFormat), you need to create a new instance of the appropriate that the + /// subclass expects, and push that onto the stack, i.e. objectModels.Push(new MarkupObjectModel()); This is + /// usually the only line of code in the overridden method's body. + /// + /// + /// objectModels.Push(new BaseObjectModel()); // this is all we need to do + /// + /// The stack of s used by this . protected virtual void BeforeLoadInternal(Stack objectModels) { } + /// + /// Method called AFTER the method is called on the original 's subclass. + /// + /// + /// When inheriting from a subclass (e.g. XMLDataFormat), you need to first pop the that you pushed + /// onto the stack in your implementation, then pop the that + /// your class expects to get passed. Now you can read data from the original and modify the second . + /// Because these objects are passed by reference, you do not need to push them back onto the stack for them to get properly loaded. + /// + /// + /// BaseObjectModel bom = (objectModels.Pop() as BaseObjectModel); // base object model comes first + /// MyVerySpecificObjectModel myOM = (objectModels.Pop() as MyVerySpecificObjectModel); + /// + /// // populate MyVerySpecificObjectModel... and we're done. nothing else needs to be pushed back onto the stack. + /// + /// The stack of s used by this . protected virtual void AfterLoadInternal(Stack objectModels) { } + /// + /// Method called BEFORE the method is called on the original 's subclass. + /// + /// + /// When inheriting from a subclass (e.g. XMLDataFormat), you need to first pop the that your class + /// expects to get passed, then create a new instance of the proper type of the base class is expecting. Now you can retrieve + /// data from the that your class expects and properly format it for the the base class expects. + /// When you're done, you need to push the newly-created onto the stack so that the underlying + /// method will be able to see it. + /// + /// + /// MyVerySpecificObjectModel myOM = (objectModels.Pop() as MyVerySpecificObjectModel); + /// BaseObjectModel bom = new BaseObjectModel(); + /// + /// // populate BaseObjectModel... + /// + /// objectModels.Push(bom); // aaand we're done + /// + /// The stack of s used by this . protected virtual void BeforeSaveInternal(Stack objectModels) { } + /// + /// Method called AFTER the method is called on the original 's subclass. + /// + /// + /// Although this method does get called after the method is called, there does not seem to be any reason to actually use it. + /// The standard practice of inheriting s utilizes the , , and + /// methods. + /// + /// The stack of s used by this . protected virtual void AfterSaveInternal(Stack objectModels) { } diff --git a/CSharp/Libraries/UniversalEditor.Core/ObjectModel.cs b/CSharp/Libraries/UniversalEditor.Core/ObjectModel.cs index 0f9671ee..4bd4fcd3 100644 --- a/CSharp/Libraries/UniversalEditor.Core/ObjectModel.cs +++ b/CSharp/Libraries/UniversalEditor.Core/ObjectModel.cs @@ -25,45 +25,95 @@ using System.Text; namespace UniversalEditor { + /// + /// The in-memory representation of data serialized to and from an using a particular . + /// public abstract class ObjectModel : ICloneable, References { + /// + /// Represents a collection of objects. + /// public class ObjectModelCollection : System.Collections.ObjectModel.Collection { } + /// + /// Creates a for this and registers it for future use. + /// + /// The that provides metadata and other information about this . public ObjectModelReference MakeReference() { ObjectModelReference omr = MakeReferenceInternal(); ObjectModelReference.Register(omr); return omr; } + /// + /// Creates a new . The returned is not cached. It is recommended that subclasses + /// override this method and cache their own personal instances of containing the appropriate metadata for their + /// subclassed implementations. + /// + /// The that provides metadata and other information about this . protected virtual ObjectModelReference MakeReferenceInternal() { ObjectModelReference omr = new ObjectModelReference(GetType()); return omr; } - private Accessor mvarAccessor = null; - public Accessor Accessor { get { return mvarAccessor; } internal set { mvarAccessor = value; } } + /// + /// The that was last used to read or write this . + /// + /// The accessor. + [Obsolete("ObjectModels should be Accessor-agnostic and not rely on being able to communicate with the Accessor")] + public Accessor Accessor { get; internal set; } + /// + /// Clears all data from this and returns it to a pristine state. + /// public abstract void Clear(); + /// + /// Copies all data from this to the specified . + /// + /// The into which to copy the data of this . + /// The conversion between this and the given is not supported. public abstract void CopyTo(ObjectModel where); + /// + /// Copies all data from this to the specified . + /// + /// The into which to copy the data of this . + /// When false, the method is called on the destination before the copy is performed. + /// The conversion between this and the given is not supported. public void CopyTo(ObjectModel where, bool append) { if (!append) where.Clear(); CopyTo(where); } + /// + /// Copies all data from the given into this . + /// + /// The from which to copy the data. + /// The conversion between this and the given is not supported. public void CopyFrom(ObjectModel where) { where.CopyTo(this); } + /// + /// Copies all data from the given into this . + /// + /// The from which to copy the data. + /// When false, the method is called on this before the copy is performed. + /// The conversion between this and the given is not supported. public void CopyFrom(ObjectModel where, bool append) { if (!append) Clear(); CopyFrom(where); } + /// + /// Creates a clone of this and returns it. This is normally implemented as creating a new instance of this + /// , then calling the original instance's method passing in the new instance as the target. + /// + /// The cloned . public object Clone() { Type type = this.GetType(); @@ -72,6 +122,12 @@ namespace UniversalEditor return clone; } + /// + /// Performs a simple find and replace on the public properties of this using reflection. For a more in-depth find and replace + /// solution, individual authors should annotate individual parameters that should participate in the find-and-replace feature. + /// + /// The string to search for. + /// The string with which the found string should be replaced. public virtual void Replace(string FindWhat, string ReplaceWith) { Type type = GetType(); @@ -88,6 +144,17 @@ namespace UniversalEditor } private Dictionary> _customProperties = new Dictionary>(); + + // TODO: should this use the MBS.Framework "ISupportsExtraData" interface? Or is this specifically UE functionality (with DataFormatReference)? + /// + /// Gets the value of the custom property with the specified name for the given . If no custom property with the given + /// name is registered for the specified , return the value specified as . + /// + /// The value of the custom property with the specified name for the given . + /// The for which to look up custom properties. + /// The name of the custom property to search for. + /// The value that should be returned if no custom property with the given name is registered for the specified . + /// The type of custom property that should be returned. public T GetCustomProperty(DataFormatReference dfr, string name, T defaultValue = default(T)) { if (_customProperties.ContainsKey(dfr)) @@ -99,10 +166,26 @@ namespace UniversalEditor } return defaultValue; } + /// + /// Gets the value of the custom property with the specified name for the given . If no custom property with the given + /// name is registered for the specified , return the value specified as . + /// + /// The value of the custom property with the specified name for the given . + /// The for which to look up custom properties. + /// The name of the custom property to search for. + /// The value that should be returned if no custom property with the given name is registered for the specified . public object GetCustomProperty(DataFormatReference dfr, string name, object defaultValue = null) { return GetCustomProperty(dfr, name, defaultValue); } + /// + /// Sets the value of the custom property with the specified name for the given . If no custom property with the given + /// name is registered for the specified , a new property is registered. + /// + /// The for which to look up or register custom properties. + /// The name of the custom property to set. + /// The value that should be assigned to the property. + /// The type of custom property that should be set. public void SetCustomProperty(DataFormatReference dfr, string name, T value) { if (!_customProperties.ContainsKey(dfr)) @@ -111,6 +194,13 @@ namespace UniversalEditor } _customProperties[dfr][name] = value; } + /// + /// Sets the value of the custom property with the specified name for the given . If no custom property with the given + /// name is registered for the specified , a new property is registered. + /// + /// The for which to look up or register custom properties. + /// The name of the custom property to set. + /// The value that should be assigned to the property. public void SetCustomProperty(DataFormatReference dfr, string name, object value) { SetCustomProperty(dfr, name, value); diff --git a/CSharp/Libraries/UniversalEditor.UserInterface/ObjectModelChangingEvent.cs b/CSharp/Libraries/UniversalEditor.UserInterface/ObjectModelChangingEvent.cs index 4c0e9321..900a13cf 100644 --- a/CSharp/Libraries/UniversalEditor.UserInterface/ObjectModelChangingEvent.cs +++ b/CSharp/Libraries/UniversalEditor.UserInterface/ObjectModelChangingEvent.cs @@ -6,19 +6,35 @@ using System.Text; namespace UniversalEditor.UserInterface { + /// + /// The event handler that is raised when an is changed, e.g. on an . + /// public delegate void ObjectModelChangingEventHandler(object sender, ObjectModelChangingEventArgs e); + /// + /// The used with the . + /// public class ObjectModelChangingEventArgs : CancelEventArgs { - private ObjectModel mvarOldObjectModel = null; - public ObjectModel OldObjectModel { get { return mvarOldObjectModel; } } - - private ObjectModel mvarNewObjectModel = null; - public ObjectModel NewObjectModel { get { return mvarNewObjectModel; } set { mvarNewObjectModel = value; } } + /// + /// The original before the change occurs. + /// + /// The original before the change occurs. + public ObjectModel OldObjectModel { get; private set; } + /// + /// The current after the change occurs. + /// + /// The current after the change occurs. + public ObjectModel NewObjectModel { get; set; } + /// + /// Initializes a new instance of the class with the given old and new . + /// + /// The original before the change occurs. + /// The current after the change occurs. public ObjectModelChangingEventArgs(ObjectModel oldObjectModel, ObjectModel newObjectModel) { - mvarOldObjectModel = oldObjectModel; - mvarNewObjectModel = newObjectModel; + OldObjectModel = oldObjectModel; + NewObjectModel = newObjectModel; } } }