522 lines
18 KiB
C#
522 lines
18 KiB
C#
|
#region MigraDoc - Creating Documents on the Fly
|
||
|
//
|
||
|
// Authors:
|
||
|
// Stefan Lange
|
||
|
// Klaus Potzesny
|
||
|
// David Stephensen
|
||
|
//
|
||
|
// Copyright (c) 2001-2017 empira Software GmbH, Cologne Area (Germany)
|
||
|
//
|
||
|
// http://www.pdfsharp.com
|
||
|
// http://www.migradoc.com
|
||
|
// http://sourceforge.net/projects/pdfsharp
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
// copy of this software and associated documentation files (the "Software"),
|
||
|
// to deal in the Software without restriction, including without limitation
|
||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||
|
// Software is furnished to do so, subject to the following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be included
|
||
|
// in all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
// DEALINGS IN THE SOFTWARE.
|
||
|
#endregion
|
||
|
|
||
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
using System.Reflection;
|
||
|
|
||
|
#pragma warning disable 1591
|
||
|
|
||
|
namespace MigraDoc.DocumentObjectModel.publics
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Base class of all value descriptor classes.
|
||
|
/// </summary>
|
||
|
public abstract class ValueDescriptor
|
||
|
{
|
||
|
public ValueDescriptor(string valueName, Type valueType, Type memberType, MemberInfo memberInfo, VDFlags flags)
|
||
|
{
|
||
|
// Take new naming convention into account.
|
||
|
if (valueName.StartsWith("_"))
|
||
|
valueName = valueName.Substring(1);
|
||
|
|
||
|
ValueName = valueName;
|
||
|
ValueType = valueType;
|
||
|
MemberType = memberType;
|
||
|
MemberInfo = memberInfo;
|
||
|
_flags = flags;
|
||
|
}
|
||
|
|
||
|
public object CreateValue()
|
||
|
{
|
||
|
#if !NETFX_CORE
|
||
|
ConstructorInfo constructorInfo = ValueType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
|
||
|
#else
|
||
|
var constructorInfos = ValueType.GetTypeInfo().DeclaredConstructors;
|
||
|
ConstructorInfo constructorInfo = null;
|
||
|
foreach (var info in constructorInfos)
|
||
|
{
|
||
|
if (info.GetParameters().Length == 0)
|
||
|
constructorInfo = info;
|
||
|
}
|
||
|
#endif
|
||
|
Debug.Assert(constructorInfo != null);
|
||
|
return constructorInfo.Invoke(null);
|
||
|
}
|
||
|
|
||
|
public abstract object GetValue(DocumentObject dom, GV flags);
|
||
|
public abstract void SetValue(DocumentObject dom, object val);
|
||
|
public abstract void SetNull(DocumentObject dom);
|
||
|
public abstract bool IsNull(DocumentObject dom);
|
||
|
|
||
|
public static ValueDescriptor CreateValueDescriptor(MemberInfo memberInfo, DVAttribute attr)
|
||
|
{
|
||
|
VDFlags flags = VDFlags.None;
|
||
|
if (attr.RefOnly)
|
||
|
flags |= VDFlags.RefOnly;
|
||
|
|
||
|
string name = memberInfo.Name;
|
||
|
|
||
|
FieldInfo fieldInfo = memberInfo as FieldInfo;
|
||
|
Type type = fieldInfo != null ? fieldInfo.FieldType : ((PropertyInfo)memberInfo).PropertyType;
|
||
|
|
||
|
if (type == typeof(NBool))
|
||
|
return new NullableDescriptor(name, typeof(Boolean), type, memberInfo, flags);
|
||
|
|
||
|
if (type == typeof(NInt))
|
||
|
return new NullableDescriptor(name, typeof(Int32), type, memberInfo, flags);
|
||
|
|
||
|
if (type == typeof(NDouble))
|
||
|
return new NullableDescriptor(name, typeof(Double), type, memberInfo, flags);
|
||
|
|
||
|
if (type == typeof(NString))
|
||
|
return new NullableDescriptor(name, typeof(String), type, memberInfo, flags);
|
||
|
|
||
|
if (type == typeof(String))
|
||
|
return new ValueTypeDescriptor(name, typeof(String), type, memberInfo, flags);
|
||
|
|
||
|
if (type == typeof(NEnum))
|
||
|
{
|
||
|
Type valueType = attr.Type;
|
||
|
#if !NETFX_CORE
|
||
|
Debug.Assert(valueType.IsSubclassOf(typeof(Enum)), "NEnum must have 'Type' attribute with the underlying type");
|
||
|
#else
|
||
|
Debug.Assert(valueType.GetTypeInfo().IsSubclassOf(typeof(Enum)), "NEnum must have 'Type' attribute with the underlying type");
|
||
|
#endif
|
||
|
return new NullableDescriptor(name, valueType, type, memberInfo, flags);
|
||
|
}
|
||
|
|
||
|
#if !NETFX_CORE
|
||
|
if (type.IsSubclassOf(typeof(ValueType)))
|
||
|
#else
|
||
|
if (type.GetTypeInfo().IsSubclassOf(typeof(ValueType)))
|
||
|
#endif
|
||
|
return new ValueTypeDescriptor(name, type, type, memberInfo, flags);
|
||
|
|
||
|
#if !NETFX_CORE
|
||
|
if (typeof(DocumentObjectCollection).IsAssignableFrom(type))
|
||
|
#else
|
||
|
if (typeof(DocumentObjectCollection).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
|
||
|
#endif
|
||
|
return new DocumentObjectCollectionDescriptor(name, type, type, memberInfo, flags);
|
||
|
|
||
|
#if !NETFX_CORE
|
||
|
if (typeof(DocumentObject).IsAssignableFrom(type))
|
||
|
#else
|
||
|
if (typeof(DocumentObject).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
|
||
|
#endif
|
||
|
return new DocumentObjectDescriptor(name, type, type, memberInfo, flags);
|
||
|
|
||
|
Debug.Assert(false, type.FullName);
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public bool IsRefOnly
|
||
|
{
|
||
|
get { return (_flags & VDFlags.RefOnly) == VDFlags.RefOnly; }
|
||
|
}
|
||
|
|
||
|
public FieldInfo FieldInfo
|
||
|
{
|
||
|
get { return MemberInfo as FieldInfo; }
|
||
|
}
|
||
|
|
||
|
public PropertyInfo PropertyInfo
|
||
|
{
|
||
|
get { return MemberInfo as PropertyInfo; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Name of the value.
|
||
|
/// </summary>
|
||
|
public readonly string ValueName;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Type of the described value, e.g. typeof(Int32) for an NInt.
|
||
|
/// </summary>
|
||
|
public readonly Type ValueType;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Type of the described field or property, e.g. typeof(NInt) for an NInt.
|
||
|
/// </summary>
|
||
|
public readonly Type MemberType;
|
||
|
|
||
|
/// <summary>
|
||
|
/// FieldInfo of the described field.
|
||
|
/// </summary>
|
||
|
public readonly MemberInfo MemberInfo;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Flags of the described field, e.g. RefOnly.
|
||
|
/// </summary>
|
||
|
readonly VDFlags _flags;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Value descriptor of all nullable types.
|
||
|
/// </summary>
|
||
|
public class NullableDescriptor : ValueDescriptor
|
||
|
{
|
||
|
public NullableDescriptor(string valueName, Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags)
|
||
|
: base(valueName, valueType, fieldType, memberInfo, flags)
|
||
|
{ }
|
||
|
|
||
|
public override object GetValue(DocumentObject dom, GV flags)
|
||
|
{
|
||
|
if (!Enum.IsDefined(typeof(GV), flags))
|
||
|
throw new /*InvalidEnum*/ArgumentException(DomSR.InvalidEnumValue(flags), "flags");
|
||
|
|
||
|
#if !NETFX_CORE
|
||
|
object val = FieldInfo != null ? FieldInfo.GetValue(dom) : PropertyInfo.GetGetMethod(true).Invoke(dom, null);
|
||
|
#else
|
||
|
object val = FieldInfo != null ? FieldInfo.GetValue(dom) : PropertyInfo.GetValue(dom);
|
||
|
#endif
|
||
|
INullableValue ival = (INullableValue)val;
|
||
|
if (ival.IsNull && flags == GV.GetNull)
|
||
|
return null;
|
||
|
return ival.GetValue();
|
||
|
}
|
||
|
|
||
|
public override void SetValue(DocumentObject dom, object value)
|
||
|
{
|
||
|
object val;
|
||
|
INullableValue ival;
|
||
|
if (FieldInfo != null)
|
||
|
{
|
||
|
val = FieldInfo.GetValue(dom);
|
||
|
ival = (INullableValue)val;
|
||
|
ival.SetValue(value);
|
||
|
FieldInfo.SetValue(dom, ival);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if !NETFX_CORE
|
||
|
val = PropertyInfo.GetGetMethod(true).Invoke(dom, null);
|
||
|
#else
|
||
|
val = PropertyInfo.GetValue(dom);
|
||
|
#endif
|
||
|
ival = (INullableValue)val;
|
||
|
ival.SetValue(value);
|
||
|
#if !NETFX_CORE
|
||
|
PropertyInfo.GetSetMethod(true).Invoke(dom, new object[] { ival });
|
||
|
#else
|
||
|
PropertyInfo.SetValue(dom, ival);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void SetNull(DocumentObject dom)
|
||
|
{
|
||
|
object val;
|
||
|
INullableValue ival;
|
||
|
if (FieldInfo != null)
|
||
|
{
|
||
|
val = FieldInfo.GetValue(dom);
|
||
|
ival = (INullableValue)val;
|
||
|
ival.SetNull();
|
||
|
FieldInfo.SetValue(dom, ival);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if !NETFX_CORE
|
||
|
val = PropertyInfo.GetGetMethod(true).Invoke(dom, null);
|
||
|
#else
|
||
|
val = PropertyInfo.GetValue(dom);
|
||
|
#endif
|
||
|
ival = (INullableValue)val;
|
||
|
ival.SetNull();
|
||
|
#if !NETFX_CORE
|
||
|
PropertyInfo.GetSetMethod(true).Invoke(dom, new object[] { ival });
|
||
|
#else
|
||
|
PropertyInfo.SetValue(dom, ival);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether the given DocumentObject is null (not set).
|
||
|
/// </summary>
|
||
|
public override bool IsNull(DocumentObject dom)
|
||
|
{
|
||
|
#if !NETFX_CORE
|
||
|
object val = FieldInfo != null ? FieldInfo.GetValue(dom) : PropertyInfo.GetGetMethod(true).Invoke(dom, null);
|
||
|
#else
|
||
|
object val = FieldInfo != null ? FieldInfo.GetValue(dom) : PropertyInfo.GetValue(dom);
|
||
|
#endif
|
||
|
return ((INullableValue)val).IsNull;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Value descriptor of value types.
|
||
|
/// </summary>
|
||
|
public class ValueTypeDescriptor : ValueDescriptor
|
||
|
{
|
||
|
public ValueTypeDescriptor(string valueName, Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags)
|
||
|
: base(valueName, valueType, fieldType, memberInfo, flags)
|
||
|
{ }
|
||
|
|
||
|
public override object GetValue(DocumentObject dom, GV flags)
|
||
|
{
|
||
|
if (!Enum.IsDefined(typeof(GV), flags))
|
||
|
throw new /*InvalidEnum*/ArgumentException(DomSR.InvalidEnumValue(flags), "flags");
|
||
|
|
||
|
#if !NETFX_CORE
|
||
|
object val = FieldInfo != null ? FieldInfo.GetValue(dom) : PropertyInfo.GetGetMethod(true).Invoke(dom, null);
|
||
|
#else
|
||
|
object val = FieldInfo != null ? FieldInfo.GetValue(dom) : PropertyInfo.GetValue(dom);
|
||
|
#endif
|
||
|
INullableValue ival = val as INullableValue;
|
||
|
if (ival != null && ival.IsNull && flags == GV.GetNull)
|
||
|
return null;
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
public override void SetValue(DocumentObject dom, object value)
|
||
|
{
|
||
|
if (FieldInfo != null)
|
||
|
FieldInfo.SetValue(dom, value);
|
||
|
else
|
||
|
#if !NETFX_CORE
|
||
|
PropertyInfo.GetSetMethod(true).Invoke(dom, new object[] { value });
|
||
|
#else
|
||
|
PropertyInfo.SetValue(dom, value);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
public override void SetNull(DocumentObject dom)
|
||
|
{
|
||
|
object val;
|
||
|
INullableValue ival;
|
||
|
if (FieldInfo != null)
|
||
|
{
|
||
|
val = FieldInfo.GetValue(dom);
|
||
|
ival = (INullableValue)val;
|
||
|
ival.SetNull();
|
||
|
FieldInfo.SetValue(dom, ival);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if !NETFX_CORE
|
||
|
val = PropertyInfo.GetGetMethod(true).Invoke(dom, null);
|
||
|
#else
|
||
|
val = PropertyInfo.GetValue(dom);
|
||
|
#endif
|
||
|
ival = (INullableValue)val;
|
||
|
ival.SetNull();
|
||
|
#if !NETFX_CORE
|
||
|
PropertyInfo.GetSetMethod(true).Invoke(dom, new object[] { ival });
|
||
|
#else
|
||
|
PropertyInfo.SetValue(dom, ival);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether the given DocumentObject is null (not set).
|
||
|
/// </summary>
|
||
|
public override bool IsNull(DocumentObject dom)
|
||
|
{
|
||
|
#if !NETFX_CORE
|
||
|
object val = FieldInfo != null ? FieldInfo.GetValue(dom) : PropertyInfo.GetGetMethod(true).Invoke(dom, null);
|
||
|
#else
|
||
|
object val = FieldInfo != null ? FieldInfo.GetValue(dom) : PropertyInfo.GetValue(dom);
|
||
|
#endif
|
||
|
INullableValue ival = val as INullableValue;
|
||
|
if (ival != null)
|
||
|
return ival.IsNull;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Value descriptor of DocumentObject.
|
||
|
/// </summary>
|
||
|
public class DocumentObjectDescriptor : ValueDescriptor
|
||
|
{
|
||
|
public DocumentObjectDescriptor(string valueName, Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags)
|
||
|
: base(valueName, valueType, fieldType, memberInfo, flags)
|
||
|
{ }
|
||
|
|
||
|
public override object GetValue(DocumentObject dom, GV flags)
|
||
|
{
|
||
|
if (!Enum.IsDefined(typeof(GV), flags))
|
||
|
throw new /*InvalidEnum*/ArgumentException(DomSR.InvalidEnumValue(flags), "flags");
|
||
|
|
||
|
FieldInfo fieldInfo = FieldInfo;
|
||
|
DocumentObject val;
|
||
|
if (fieldInfo != null)
|
||
|
{
|
||
|
// Member is a field
|
||
|
val = FieldInfo.GetValue(dom) as DocumentObject;
|
||
|
if (val == null && flags == GV.ReadWrite)
|
||
|
{
|
||
|
val = (DocumentObject)CreateValue();
|
||
|
val._parent = dom;
|
||
|
FieldInfo.SetValue(dom, val);
|
||
|
return val;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Member is a property
|
||
|
#if !NETFX_CORE
|
||
|
val = PropertyInfo.GetGetMethod(true).Invoke(dom, null) as DocumentObject;
|
||
|
#else
|
||
|
val = PropertyInfo.GetValue(dom) as DocumentObject;
|
||
|
#endif
|
||
|
}
|
||
|
if (val != null && (val.IsNull() && flags == GV.GetNull))
|
||
|
return null;
|
||
|
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
public override void SetValue(DocumentObject dom, object val)
|
||
|
{
|
||
|
FieldInfo fieldInfo = FieldInfo;
|
||
|
// Member is a field
|
||
|
if (fieldInfo != null)
|
||
|
{
|
||
|
fieldInfo.SetValue(dom, val);
|
||
|
return;
|
||
|
}
|
||
|
throw new InvalidOperationException("This value cannot be set.");
|
||
|
}
|
||
|
|
||
|
public override void SetNull(DocumentObject dom)
|
||
|
{
|
||
|
FieldInfo fieldInfo = FieldInfo;
|
||
|
DocumentObject val;
|
||
|
// Member is a field.
|
||
|
if (fieldInfo != null)
|
||
|
{
|
||
|
val = FieldInfo.GetValue(dom) as DocumentObject;
|
||
|
if (val != null)
|
||
|
val.SetNull();
|
||
|
}
|
||
|
|
||
|
// Member is a property.
|
||
|
if (PropertyInfo != null)
|
||
|
{
|
||
|
PropertyInfo propInfo = PropertyInfo;
|
||
|
#if !NETFX_CORE
|
||
|
val = propInfo.GetGetMethod(true).Invoke(dom, null) as DocumentObject;
|
||
|
#else
|
||
|
val = propInfo.GetValue(dom) as DocumentObject;
|
||
|
#endif
|
||
|
if (val != null)
|
||
|
val.SetNull();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether the given DocumentObject is null (not set).
|
||
|
/// </summary>
|
||
|
public override bool IsNull(DocumentObject dom)
|
||
|
{
|
||
|
FieldInfo fieldInfo = FieldInfo;
|
||
|
DocumentObject val;
|
||
|
// Member is a field
|
||
|
if (fieldInfo != null)
|
||
|
{
|
||
|
val = FieldInfo.GetValue(dom) as DocumentObject;
|
||
|
if (val == null)
|
||
|
return true;
|
||
|
return val.IsNull();
|
||
|
}
|
||
|
// Member is a property
|
||
|
PropertyInfo propInfo = PropertyInfo;
|
||
|
#if !NETFX_CORE
|
||
|
val = propInfo.GetGetMethod(true).Invoke(dom, null) as DocumentObject;
|
||
|
#else
|
||
|
val = propInfo.GetValue(dom) as DocumentObject;
|
||
|
#endif
|
||
|
if (val != null)
|
||
|
val.IsNull();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Value descriptor of DocumentObjectCollection.
|
||
|
/// </summary>
|
||
|
public class DocumentObjectCollectionDescriptor : ValueDescriptor
|
||
|
{
|
||
|
public DocumentObjectCollectionDescriptor(string valueName, Type valueType, Type fieldType, MemberInfo memberInfo, VDFlags flags)
|
||
|
: base(valueName, valueType, fieldType, memberInfo, flags)
|
||
|
{ }
|
||
|
|
||
|
public override object GetValue(DocumentObject dom, GV flags)
|
||
|
{
|
||
|
if (!Enum.IsDefined(typeof(GV), flags))
|
||
|
throw new /*InvalidEnum*/ArgumentException(DomSR.InvalidEnumValue(flags), "flags");
|
||
|
|
||
|
Debug.Assert(MemberInfo is FieldInfo, "Properties of DocumentObjectCollection not allowed.");
|
||
|
DocumentObjectCollection val = FieldInfo.GetValue(dom) as DocumentObjectCollection;
|
||
|
if (val == null && flags == GV.ReadWrite)
|
||
|
{
|
||
|
val = (DocumentObjectCollection)CreateValue();
|
||
|
val._parent = dom;
|
||
|
FieldInfo.SetValue(dom, val);
|
||
|
return val;
|
||
|
}
|
||
|
if (val != null && val.IsNull() && flags == GV.GetNull)
|
||
|
return null;
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
public override void SetValue(DocumentObject dom, object val)
|
||
|
{
|
||
|
FieldInfo.SetValue(dom, val);
|
||
|
}
|
||
|
|
||
|
public override void SetNull(DocumentObject dom)
|
||
|
{
|
||
|
DocumentObjectCollection val = FieldInfo.GetValue(dom) as DocumentObjectCollection;
|
||
|
if (val != null)
|
||
|
val.SetNull();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether the given DocumentObject is null (not set).
|
||
|
/// </summary>
|
||
|
public override bool IsNull(DocumentObject dom)
|
||
|
{
|
||
|
DocumentObjectCollection val = FieldInfo.GetValue(dom) as DocumentObjectCollection;
|
||
|
if (val == null)
|
||
|
return true;
|
||
|
return val.IsNull();
|
||
|
}
|
||
|
}
|
||
|
}
|