#region License Information
/* HeuristicLab
* Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using HeuristicLab.PluginInfrastructure;
using HeuristicLab.Visualization;
namespace HeuristicLab.Networks.Views.NetworkVisualization {
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public sealed class PrimitiveAttribute : Attribute {
public Type VisualizableType { get; private set; }
public bool IsDefaultPrimitive { get; set; }
private static readonly Dictionary defaultPrimitives = new Dictionary();
static PrimitiveAttribute() {
var primitiveTypes = ApplicationManager.Manager.GetTypes(typeof(IPrimitive), true, true)
.Where(x => !x.IsAbstract && !x.IsInterface && HasPrimitiveAttribute(x));
foreach (var primitiveType in primitiveTypes) {
foreach (var visualizableType in GetDefaultVisualizableTypes(primitiveType)) {
if (defaultPrimitives.ContainsKey(visualizableType))
throw new ArgumentException("DefaultPrimitive for type " + visualizableType + " is " + defaultPrimitives[visualizableType] +
". Can't register additional DefaultPrimitive " + primitiveType + ".");
defaultPrimitives[visualizableType] = primitiveType;
}
}
}
public PrimitiveAttribute(Type visualizableType) {
VisualizableType = visualizableType;
}
public PrimitiveAttribute(Type visualizableType, bool isDefaultPrimitive)
: this(visualizableType) {
IsDefaultPrimitive = isDefaultPrimitive;
}
public static bool HasPrimitiveAttribute(MemberInfo primitiveType) {
var attributes = primitiveType.GetCustomAttributes(typeof(PrimitiveAttribute), false);
return attributes.Any();
}
public static bool CanVisualizeType(MemberInfo primitiveType, Type visualizable) {
var attributes = (PrimitiveAttribute[])primitiveType.GetCustomAttributes(typeof(PrimitiveAttribute), false);
return attributes.Any(x => visualizable.IsAssignableFrom(x.VisualizableType));
}
public static IEnumerable GetDefaultVisualizableTypes(Type primitiveType) {
var attributes = (PrimitiveAttribute[])primitiveType.GetCustomAttributes(typeof(PrimitiveAttribute), false);
return attributes.Where(x => x.IsDefaultPrimitive).Select(x => x.VisualizableType);
}
public static IEnumerable GetVisualizableTypes(Type primitiveType) {
var attributes = (PrimitiveAttribute[])primitiveType.GetCustomAttributes(typeof(PrimitiveAttribute), false);
return attributes.Select(x => x.VisualizableType);
}
public static IPrimitive CreateDefaultPrimitive(Type visualizableType, params object[] args) {
var t = GetDefaultPrimitiveType(visualizableType);
if (t == null) return null;
return (IPrimitive)Activator.CreateInstance(t, args);
}
// TODO: add support for generic types
public static Type GetDefaultPrimitiveType(Type visualizableType) {
var type = visualizableType;
while (type != null) {
Type primitiveType;
if (defaultPrimitives.TryGetValue(type, out primitiveType))
return primitiveType;
var nonInheritedInterfaces = type.GetInterfaces().Where(i => !i.IsAssignableFrom(type.BaseType));
var interfaces = new HashSet(nonInheritedInterfaces);
while (interfaces.Any()) {
interfaces.RemoveWhere(i => interfaces.Any(x => x.GetInterfaces().Contains(i)));
var defaultViewList = defaultPrimitives.Keys.Where(interfaces.Contains).Select(x => defaultPrimitives[x]).ToList();
foreach (Type viewType in defaultViewList)
if (defaultViewList.Any(t => t.IsSubclassOf(viewType)))
defaultViewList.Remove(viewType);
if (defaultViewList.Count == 1) return defaultViewList[0];
if (defaultViewList.Count > 1)
throw new InvalidOperationException("Could not determine which is the default primitive for type " + visualizableType +
" because more than one implemented interfaces have a default primitive.");
interfaces = new HashSet(interfaces.SelectMany(i => i.GetInterfaces()));
}
type = type.BaseType;
}
return null;
}
}
}