using System;
using System.Collections.Generic;
using System.Diagnostics;
using Newtonsoft.Json;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
namespace Umbraco.Core.PropertyEditors
{
///
/// Represents a data editor.
///
///
/// Editors can be deserialized from e.g. manifests, which is. why the class is not abstract,
/// the json serialization attributes are required, and the properties have an internal setter.
///
[DebuggerDisplay("{" + nameof(DebuggerDisplay) + "(),nq}")]
[HideFromTypeFinder]
public class DataEditor : IDataEditor
{
private IDictionary _defaultConfiguration;
///
/// Initializes a new instance of the class.
///
public DataEditor(ILogger logger, EditorType type = EditorType.PropertyValue)
{
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
// defaults
Type = type;
Icon = Constants.Icons.PropertyEditor;
Group = "common";
// assign properties based on the attribute, if it is found
Attribute = GetType().GetCustomAttribute(false);
if (Attribute == null) return;
Alias = Attribute.Alias;
Type = Attribute.Type;
Name = Attribute.Name;
Icon = Attribute.Icon;
Group = Attribute.Group;
IsDeprecated = Attribute.IsDeprecated;
}
///
/// Gets the editor attribute.
///
protected DataEditorAttribute Attribute { get; }
///
/// Gets a logger.
///
protected ILogger Logger { get; }
///
[JsonProperty("alias", Required = Required.Always)]
public string Alias { get; internal set; }
///
[JsonIgnore]
public EditorType Type { get; }
///
[JsonProperty("name", Required = Required.Always)]
public string Name { get; internal set; }
///
[JsonProperty("icon")]
public string Icon { get; internal set; }
///
[JsonProperty("group")]
public string Group { get; internal set; }
///
[JsonIgnore]
public bool IsDeprecated { get; }
///
///
/// If an explicit value editor has been assigned, then this explicit
/// instance is returned. Otherwise, a new instance is created by CreateValueEditor.
/// The instance created by CreateValueEditor is not cached, i.e.
/// a new instance is created each time the property value is retrieved. The
/// property editor is a singleton, and the value editor cannot be a singleton
/// since it depends on the datatype configuration.
/// Technically, it could be cached by datatype but let's keep things
/// simple enough for now.
///
// TODO: point of that one? shouldn't we always configure?
public IDataValueEditor GetValueEditor() => ExplicitValueEditor ?? CreateValueEditor();
///
///
/// If an explicit value editor has been assigned, then this explicit
/// instance is returned. Otherwise, a new instance is created by CreateValueEditor,
/// and configured with the configuration.
/// The instance created by CreateValueEditor is not cached, i.e.
/// a new instance is created each time the property value is retrieved. The
/// property editor is a singleton, and the value editor cannot be a singleton
/// since it depends on the datatype configuration.
/// Technically, it could be cached by datatype but let's keep things
/// simple enough for now.
///
public IDataValueEditor GetValueEditor(object configuration)
{
// if an explicit value editor has been set (by the manifest parser)
// then return it, and ignore the configuration, which is going to be
// empty anyways
if (ExplicitValueEditor != null)
return ExplicitValueEditor;
var editor = CreateValueEditor();
((DataValueEditor) editor).Configuration = configuration; // TODO: casting is bad
return editor;
}
///
/// Gets or sets an explicit value editor.
///
/// Used for manifest data editors.
[JsonProperty("editor")]
public IDataValueEditor ExplicitValueEditor { get; set; }
///
///
/// If an explicit configuration editor has been assigned, then this explicit
/// instance is returned. Otherwise, a new instance is created by CreateConfigurationEditor.
/// The instance created by CreateConfigurationEditor is not cached, i.e.
/// a new instance is created each time. The property editor is a singleton, and although the
/// configuration editor could technically be a singleton too, we'd rather not keep configuration editor
/// cached.
///
public IConfigurationEditor GetConfigurationEditor() => ExplicitConfigurationEditor ?? CreateConfigurationEditor();
///
/// Gets or sets an explicit configuration editor.
///
/// Used for manifest data editors.
[JsonProperty("config")]
public IConfigurationEditor ExplicitConfigurationEditor { get; set; }
///
[JsonProperty("defaultConfig")]
public IDictionary DefaultConfiguration
{
// for property value editors, get the ConfigurationEditor.DefaultConfiguration
// else fallback to a default, empty dictionary
get => _defaultConfiguration ?? ((Type & EditorType.PropertyValue) > 0 ? GetConfigurationEditor().DefaultConfiguration : (_defaultConfiguration = new Dictionary()));
set => _defaultConfiguration = value;
}
///
public virtual IPropertyIndexValueFactory PropertyIndexValueFactory => new DefaultPropertyIndexValueFactory();
///
/// Creates a value editor instance.
///
///
protected virtual IDataValueEditor CreateValueEditor()
{
if (Attribute == null)
throw new InvalidOperationException("The editor does not specify a view.");
return new DataValueEditor(Attribute);
}
///
/// Creates a configuration editor instance.
///
protected virtual IConfigurationEditor CreateConfigurationEditor()
{
return new ConfigurationEditor();
}
///
/// Provides a summary of the PropertyEditor for use with the .
///
protected virtual string DebuggerDisplay()
{
return $"Name: {Name}, Alias: {Alias}";
}
}
}