Skip to content

Commit

Permalink
Extensible storage lookup fix and small improvements (#81)
Browse files Browse the repository at this point in the history
* fix broken schema fields values display

* SpecTypeId.Custom is not a measurable spec (it represents double values), but requires UnitTypeId.Custom to get an entity field value

* this allows to view extensible storage schema map fields (dictionaries)

* ElementId could represent Revit model element or built in parameter id or built in category id. In the last two cases it is better to show id value instead of "<null>"

* now keyvaluepair is a trully snoopable object

* remove unused using

* show value if ElementId represents built-in parameters or built-in category
  • Loading branch information
CADBIMDeveloper authored May 18, 2021
1 parent 1c17887 commit 998a433
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 143 deletions.
30 changes: 26 additions & 4 deletions CS/Snoop/CollectorExts/CollectorExtElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using RevitLookup.Snoop.Collectors;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using RevitLookup.Snoop.Data;
using String = System.String;

namespace RevitLookup.Snoop.CollectorExts
{
Expand All @@ -52,6 +52,7 @@ public CollectorExtElement()
.Where(x => Path.GetDirectoryName(x.Location) == baseDirectory)
.Where(x => x.GetName().Name.ToLower().Contains("revit"))
.SelectMany(x => x.GetTypes())
.Union(new [] {typeof(KeyValuePair<,>)})
.ToArray();
}

Expand All @@ -72,7 +73,7 @@ protected override void CollectEvent(object sender, CollectorEventArgs e)

private void Stream(ArrayList data, object elem)
{
var thisElementTypes = types.Where(x => elem.GetType().IsSubclassOf(x) || elem.GetType() == x || x.IsAssignableFrom(elem.GetType())).ToList();
var thisElementTypes = types.Where(x => IsSnoopableType(x, elem)).ToList();

var streams = new IElementStream[]
{
Expand All @@ -83,9 +84,9 @@ private void Stream(ArrayList data, object elem)
new ExtensibleStorageEntityContentStream(m_app.ActiveUIDocument.Document, data, elem)
};

foreach (Type type in thisElementTypes)
foreach (var type in thisElementTypes)
{
data.Add(new Snoop.Data.ClassSeparator(type));
data.Add(new ClassSeparator(type));

foreach (var elementStream in streams)
elementStream.Stream(type);
Expand All @@ -96,6 +97,27 @@ private void Stream(ArrayList data, object elem)
StreamSimpleType(data, elem);
}

private static bool IsSnoopableType(Type type, object element)
{
var elementType = element.GetType();

if (type == elementType || elementType.IsSubclassOf(type) || type.IsAssignableFrom(elementType))
return true;

return type.IsGenericType && elementType.IsGenericType && IsSubclassOfRawGeneric(type, elementType);
}

private static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
while (toCheck != null && toCheck != typeof(object)) {
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur) {
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}

private static void StreamElementExtensibleStorages(ArrayList data, Element elem)
{
var schemas = Schema.ListSchemas();
Expand Down
7 changes: 6 additions & 1 deletion CS/Snoop/CollectorExts/DataFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ public DataFactory(UIApplication application, object elem)
this.elem = elem;
}

public Data.Data Create(MethodInfo methodInfo)
public Data.Data Create(MethodInfo mi)
{
var methodInfo = mi.ContainsGenericParameters ? elem.GetType().GetMethod(mi.Name, mi.GetParameters().Select(x => x.ParameterType).ToArray()) : mi;

if (methodInfo == null)
return null;

var declaringType = methodInfo.DeclaringType;

if (methodInfo.IsSpecialName || declaringType == null)
Expand Down
93 changes: 50 additions & 43 deletions CS/Snoop/CollectorExts/ElementPropertiesStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,55 +51,62 @@ private PropertyInfo[] GetElementProperties( Type type )
.ToArray();
}

private void AddPropertyToData( PropertyInfo pi )
private void AddPropertyToData(PropertyInfo pi)
{
Type propertyType = pi.PropertyType;
var propertyInfo = pi.PropertyType.ContainsGenericParameters ? elem.GetType().GetProperty(pi.Name) : pi;

if (propertyInfo == null)
return;

var propertyType = propertyInfo.PropertyType;

try
{
object propertyValue;
if( pi.Name == "Geometry" )
propertyValue = pi.GetValue( elem, new object[ 1 ] { new Options() } );
else if( pi.Name == "BoundingBox" )
propertyValue = pi.GetValue( elem, new object[ 1 ] { application.ActiveUIDocument.ActiveView } );
else if( pi.Name == "Item" )
propertyValue = pi.GetValue( elem, new object[ 1 ] { 0 } );
else if( pi.Name == "Parameter" )
return;
else if( pi.Name == "PlanTopology" )
return;
else if( pi.Name == "PlanTopologies" && pi.GetMethod.GetParameters().Length != 0 )
return;
else
propertyValue = pi.GetValue( elem );
try
{
object propertyValue;
if (propertyInfo.Name == "Geometry")
propertyValue = propertyInfo.GetValue(elem, new object[1] {new Options()});
else if (propertyInfo.Name == "BoundingBox")
propertyValue = propertyInfo.GetValue(elem, new object[1] {application.ActiveUIDocument.ActiveView});
else if (propertyInfo.Name == "Item")
propertyValue = propertyInfo.GetValue(elem, new object[1] {0});
else if (propertyInfo.Name == "Parameter")
return;
else if (propertyInfo.Name == "PlanTopology")
return;
else if (propertyInfo.Name == "PlanTopologies" && propertyInfo.GetMethod.GetParameters().Length != 0)
return;
else if (propertyType.ContainsGenericParameters)
propertyValue = elem.GetType().GetProperty(propertyInfo.Name)?.GetValue(elem);
else
propertyValue = propertyInfo.GetValue(elem);

DataTypeInfoHelper.AddDataFromTypeInfo( application, pi, propertyType, propertyValue, elem, data );
DataTypeInfoHelper.AddDataFromTypeInfo(application, propertyInfo, propertyType, propertyValue, elem, data);

var category = elem as Category;
if( category != null && pi.Name == "Id" && category.Id.IntegerValue < 0 )
{
var bic = (BuiltInCategory) category.Id.IntegerValue;
var category = elem as Category;
if (category != null && propertyInfo.Name == "Id" && category.Id.IntegerValue < 0)
{
var bic = (BuiltInCategory) category.Id.IntegerValue;

data.Add( new Snoop.Data.String( "BuiltInCategory", bic.ToString() ) );
}
data.Add(new Snoop.Data.String("BuiltInCategory", bic.ToString()));
}

}
catch( ArgumentException ex )
{
data.Add( new Snoop.Data.Exception( pi.Name, ex ) );
}
catch( TargetException ex )
{
data.Add( new Snoop.Data.Exception( pi.Name, ex ) );
}
catch( TargetInvocationException ex )
{
data.Add( new Snoop.Data.Exception( pi.Name, ex ) );
}
catch( TargetParameterCountException ex )
{
data.Add( new Snoop.Data.Exception( pi.Name, ex ) );
}
}
catch (ArgumentException ex)
{
data.Add(new Snoop.Data.Exception(propertyInfo.Name, ex));
}
catch (TargetException ex)
{
data.Add(new Snoop.Data.Exception(propertyInfo.Name, ex));
}
catch (TargetInvocationException ex)
{
data.Add(new Snoop.Data.Exception(propertyInfo.Name, ex));
}
catch (TargetParameterCountException ex)
{
data.Add(new Snoop.Data.Exception(propertyInfo.Name, ex));
}
}
}
}
80 changes: 35 additions & 45 deletions CS/Snoop/CollectorExts/ExtensibleStorageEntityContentStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,32 @@ public void Stream( Type type )
StreamEntityFieldValue( field );
}

private void StreamEntityFieldValue( Field field )
private void StreamEntityFieldValue(Field field)
{
try
{
var getEntityValueMethod = GetEntityFieldValueMethod( field );
try
{
var getEntityValueMethod = GetEntityFieldValueMethod(field);

var valueType = GetFieldValueType( field );
var valueType = GetFieldValueType(field);

var genericGet = getEntityValueMethod.MakeGenericMethod( valueType );
var genericGet = getEntityValueMethod.MakeGenericMethod(valueType);

//var unit = UnitUtils.GetValidDisplayUnits( field.UnitType ).First(); // 2020
var fieldSpecType = field.GetSpecTypeId();

var unit = UnitUtils.GetValidUnits( field.GetSpecTypeId() ).First(); // 2021
var unit = UnitUtils.IsMeasurableSpec(fieldSpecType) ? UnitUtils.GetValidUnits(field.GetSpecTypeId()).First() : UnitTypeId.Custom;

var parameters = getEntityValueMethod.GetParameters().Length == 1
? new object[] { field }
: new object[] { field, unit };
var parameters = getEntityValueMethod.GetParameters().Length == 1
? new object[] {field}
: new object[] {field, unit};

var value = genericGet.Invoke( entity, parameters );
var value = genericGet.Invoke(entity, parameters);

AddFieldValue( field, value );
}
catch( Exception ex )
{
data.Add( new Snoop.Data.Exception( field.FieldName, ex ) );
}
AddFieldValue(field, value);
}
catch (Exception ex)
{
data.Add(new Data.Exception(field.FieldName, ex));
}
}

private Type GetFieldValueType( Field field )
Expand Down Expand Up @@ -97,7 +97,7 @@ private void AddFieldValue( Field field, object value )
try
{
if( field.ContainerType != ContainerType.Simple )
data.Add( new Snoop.Data.Object( field.FieldName, value ) );
data.Add( new Snoop.Data.Enumerable( field.FieldName, value as IEnumerable ) );
else if( field.ValueType == typeof( double ) )
data.Add( new Snoop.Data.Double( field.FieldName, (double) value ) );
else if( field.ValueType == typeof( string ) )
Expand Down Expand Up @@ -125,40 +125,30 @@ private void AddFieldValue( Field field, object value )
}
}

private MethodInfo GetEntityFieldValueMethod( Field field )
private static MethodInfo GetEntityFieldValueMethod(Field field)
{
return typeof( Entity )
.GetMethods( BindingFlags.Public | BindingFlags.Instance )
.Where( x => x.Name == "Get" && x.IsGenericMethod )
.Single( x => IsGetByFieldMethod( x, field ) );
return typeof(Entity)
.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.Name == nameof(Entity.Get) && x.IsGenericMethod)
.Single(x => IsGetByFieldMethod(x, field));
}

private static bool IsGetByFieldMethod( MethodInfo methodInfo, Field field )
private static bool IsGetByFieldMethod(MethodInfo methodInfo, Field field)
{
var parameters = methodInfo.GetParameters();

if( field.ContainerType == ContainerType.Simple
&& (field.ValueType == typeof( XYZ )
|| field.ValueType == typeof( double )) )
{
//#pragma warning disable CS0618 // Revit 2021
// warning CS0618: `DisplayUnitType` is obsolete:
// This enumeration is deprecated in Revit 2021 and may be removed in a future version of Revit.
// Please use the `ForgeTypeId` class instead.
// Use constant members of the `UnitTypeId` class to replace uses of specific values of this enumeration.
var parameters = methodInfo.GetParameters();

var fieldSpecType = field.GetSpecTypeId();

if( 2 == parameters.Length )
if (UnitUtils.IsMeasurableSpec(fieldSpecType) || fieldSpecType == SpecTypeId.Custom)
{
ParameterInfo p1 = parameters.First();
ParameterInfo p2 = parameters.Last();
return p1.ParameterType == typeof( Field )
&& // (p2.ParameterType == typeof( DisplayUnitType ) || // Revit 2021
p2.ParameterType == typeof( ForgeTypeId );
var firstParameter = parameters.First();

var lastParameter = parameters.Last();

return parameters.Length == 2 && firstParameter.ParameterType == typeof(Field) && lastParameter.ParameterType == typeof(ForgeTypeId);
}
//#pragma warning restore CS0618 // Revit 2021

}
return parameters.Length == 1 && parameters.Single().ParameterType == typeof( Field );
return parameters.Length == 1 && parameters.Single().ParameterType == typeof(Field);
}
}
}
Loading

0 comments on commit 998a433

Please sign in to comment.