Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LT-21053: Update homographs to match publication #251

Open
wants to merge 4 commits into
base: release/9.1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 121 additions & 91 deletions Src/xWorks/ConfiguredLcmGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
Expand Down Expand Up @@ -382,6 +383,34 @@ public static string GetClassNameAttributeForConfig(ConfigurableDictionaryNode c
return classAtt;
}

private static string PlainFieldName(string fieldname)
{
if (fieldname.EndsWith("OA") || fieldname.EndsWith("OS") || fieldname.EndsWith("OC")
|| fieldname.EndsWith("RA") || fieldname.EndsWith("RS") || fieldname.EndsWith("RC"))
{
return fieldname.Substring(0, fieldname.Length - 2);
}
return fieldname;
}

private static object GetValueFromMember(MemberInfo property, object instance)
{
switch (property.MemberType)
{
case MemberTypes.Property:
{
return ((PropertyInfo)property).GetValue(instance, new object[] { });
}
case MemberTypes.Method:
{
// Execute the presumed extension method (passing the instance as the 'this' parameter)
return ((MethodInfo)property).Invoke(instance, new object[] { instance });
}
default:
return null;
}
}

/// <summary>
/// This method will use reflection to pull data out of the given object based on the given configuration and
/// write out appropriate content using the settings parameter.
Expand Down Expand Up @@ -429,7 +458,7 @@ internal static IFragment GenerateContentForFieldByReflection(object field, Conf
{
// REVIEW: We have overloaded terms here, this is a C# class not a css class, consider a different name
var customFieldOwnerClassName = GetClassNameForCustomFieldParent(config, settings.Cache);
if (!GetPropValueForCustomField(field, config, cache, customFieldOwnerClassName, config.FieldDescription, ref propertyValue))
if (!GetPropValueForCustomField(field, config, cache, publicationDecorator, customFieldOwnerClassName, config.FieldDescription, ref propertyValue))
return settings.ContentGenerator.CreateFragment();
}
else
Expand All @@ -454,7 +483,16 @@ internal static IFragment GenerateContentForFieldByReflection(object field, Conf
#endif
return settings.ContentGenerator.CreateFragment();
}
propertyValue = GetValueFromMember(property, field);
// This code demonstrates using the cache metadata,
// an alternative form of reflection to get values that respect the decorator
bool success = false;
if (field is ICmObject)
success = GetPropValueForCustomField(field, config, cache, publicationDecorator,
((ICmObject)field).ClassName, PlainFieldName(property.Name), ref propertyValue);

if (!success)
propertyValue = GetValueFromMember(property, field);

GetSortedReferencePropertyValue(config, ref propertyValue, field);
}
// If the property value is null there is nothing to generate
Expand All @@ -467,7 +505,7 @@ internal static IFragment GenerateContentForFieldByReflection(object field, Conf
if (config.IsCustomField)
{
// Get the custom field value (in SubField) using the property which came from the field object
if (!GetPropValueForCustomField(propertyValue, config, cache, ((ICmObject)propertyValue).ClassName,
if (!GetPropValueForCustomField(propertyValue, config, cache, publicationDecorator, ((ICmObject)propertyValue).ClassName,
config.SubField, ref propertyValue))
{
return settings.ContentGenerator.CreateFragment();
Expand Down Expand Up @@ -572,86 +610,89 @@ private static IFragment GenerateContentForGroupingNode(object field, Configurab
/// <returns>true if the custom field was valid and false otherwise</returns>
/// <remarks>propertyValue can be null if the custom field is valid but no value is stored for the owning object</remarks>
private static bool GetPropValueForCustomField(object fieldOwner, ConfigurableDictionaryNode config,
LcmCache cache, string customFieldOwnerClassName, string customFieldName, ref object propertyValue)
LcmCache cache, ISilDataAccess decorator, string customFieldOwnerClassName, string customFieldName, ref object propertyValue)
{
if (decorator == null)
decorator = cache.DomainDataByFlid;
int customFieldFlid = GetCustomFieldFlid(config, cache, customFieldOwnerClassName, customFieldName);
if (customFieldFlid != 0)
if (customFieldFlid == 0)
return false;

var customFieldType = cache.MetaDataCacheAccessor.GetFieldType(customFieldFlid);
ICmObject specificObject;
if (fieldOwner is ISenseOrEntry)
{
var customFieldType = cache.MetaDataCacheAccessor.GetFieldType(customFieldFlid);
ICmObject specificObject;
if (fieldOwner is ISenseOrEntry)
specificObject = ((ISenseOrEntry)fieldOwner).Item;
if (!((IFwMetaDataCacheManaged)cache.MetaDataCacheAccessor).GetFields(specificObject.ClassID,
true, (int)CellarPropertyTypeFilter.All).Contains(customFieldFlid))
{
specificObject = ((ISenseOrEntry)fieldOwner).Item;
if (!((IFwMetaDataCacheManaged)cache.MetaDataCacheAccessor).GetFields(specificObject.ClassID,
true, (int)CellarPropertyTypeFilter.All).Contains(customFieldFlid))
{
return false;
}
}
else
{
specificObject = (ICmObject)fieldOwner;
return false;
}
}
else
{
specificObject = (ICmObject)fieldOwner;
}

switch (customFieldType)
{
case (int)CellarPropertyType.ReferenceCollection:
case (int)CellarPropertyType.OwningCollection:
// Collections are stored essentially the same as sequences.
case (int)CellarPropertyType.ReferenceSequence:
case (int)CellarPropertyType.OwningSequence:
{
var sda = cache.MainCacheAccessor;
// This method returns the hvo of the object pointed to
var chvo = sda.get_VecSize(specificObject.Hvo, customFieldFlid);
int[] contents;
using (var arrayPtr = MarshalEx.ArrayToNative<int>(chvo))
{
sda.VecProp(specificObject.Hvo, customFieldFlid, chvo, out chvo, arrayPtr);
contents = MarshalEx.NativeToArray<int>(arrayPtr, chvo);
}
// if the hvo is invalid set propertyValue to null otherwise get the object
propertyValue = contents.Select(id => cache.LangProject.Services.GetObject(id));
break;
}
case (int)CellarPropertyType.ReferenceAtomic:
case (int)CellarPropertyType.OwningAtomic:
{
// This method returns the hvo of the object pointed to
propertyValue = cache.MainCacheAccessor.get_ObjectProp(specificObject.Hvo, customFieldFlid);
// if the hvo is invalid set propertyValue to null otherwise get the object
propertyValue = (int)propertyValue > 0 ? cache.LangProject.Services.GetObject((int)propertyValue) : null;
break;
}
case (int)CellarPropertyType.GenDate:
switch (customFieldType)
{
case (int)CellarPropertyType.ReferenceCollection:
case (int)CellarPropertyType.OwningCollection:
// Collections are stored essentially the same as sequences.
case (int)CellarPropertyType.ReferenceSequence:
case (int)CellarPropertyType.OwningSequence:
{
var sda = cache.MainCacheAccessor;
// This method returns the hvo of the object pointed to
var chvo = sda.get_VecSize(specificObject.Hvo, customFieldFlid);
int[] contents;
using (var arrayPtr = MarshalEx.ArrayToNative<int>(chvo))
{
propertyValue = new GenDate(cache.MainCacheAccessor.get_IntProp(specificObject.Hvo, customFieldFlid));
break;
sda.VecProp(specificObject.Hvo, customFieldFlid, chvo, out chvo, arrayPtr);
contents = MarshalEx.NativeToArray<int>(arrayPtr, chvo);
}
// if the hvo is invalid set propertyValue to null otherwise get the object
propertyValue = contents.Select(id => cache.LangProject.Services.GetObject(id));
break;
}
case (int)CellarPropertyType.ReferenceAtomic:
case (int)CellarPropertyType.OwningAtomic:
{
// This method returns the hvo of the object pointed to
propertyValue = decorator.get_ObjectProp(specificObject.Hvo, customFieldFlid);
// if the hvo is invalid set propertyValue to null otherwise get the object
propertyValue = (int)propertyValue > 0 ? cache.LangProject.Services.GetObject((int)propertyValue) : null;
break;
}
case (int)CellarPropertyType.GenDate:
{
propertyValue = new GenDate(decorator.get_IntProp(specificObject.Hvo, customFieldFlid));
break;
}

case (int)CellarPropertyType.Time:
{
propertyValue = SilTime.ConvertFromSilTime(cache.MainCacheAccessor.get_TimeProp(specificObject.Hvo, customFieldFlid));
break;
}
case (int)CellarPropertyType.MultiUnicode:
case (int)CellarPropertyType.MultiString:
{
propertyValue = cache.MainCacheAccessor.get_MultiStringProp(specificObject.Hvo, customFieldFlid);
break;
}
case (int)CellarPropertyType.String:
{
propertyValue = cache.MainCacheAccessor.get_StringProp(specificObject.Hvo, customFieldFlid);
break;
}
case (int)CellarPropertyType.Integer:
{
propertyValue = cache.MainCacheAccessor.get_IntProp(specificObject.Hvo, customFieldFlid);
break;
}
}
case (int)CellarPropertyType.Time:
{
propertyValue = SilTime.ConvertFromSilTime(decorator.get_TimeProp(specificObject.Hvo, customFieldFlid));
break;
}
case (int)CellarPropertyType.MultiUnicode:
case (int)CellarPropertyType.MultiString:
{
propertyValue = decorator.get_MultiStringProp(specificObject.Hvo, customFieldFlid);
break;
}
case (int)CellarPropertyType.String:
{
propertyValue = decorator.get_StringProp(specificObject.Hvo, customFieldFlid);
break;
}
case (int)CellarPropertyType.Integer:
{
propertyValue = decorator.get_IntProp(specificObject.Hvo, customFieldFlid);
break;
}
}

return true;
}

Expand Down Expand Up @@ -1219,24 +1260,6 @@ private static Type GetTypeFromMember(MemberInfo property)
}
}

private static object GetValueFromMember(MemberInfo property, object instance)
{
switch (property.MemberType)
{
case MemberTypes.Property:
{
return ((PropertyInfo)property).GetValue(instance, new object[] {});
}
case MemberTypes.Method:
{
// Execute the presumed extension method (passing the instance as the 'this' parameter)
return ((MethodInfo)property).Invoke(instance, new object[] {instance});
}
default:
return null;
}
}

private static Type GetCustomFieldType(Type lookupType, ConfigurableDictionaryNode config, LcmCache cache)
{
// FDO doesn't work with interfaces, just concrete classes so chop the I off any interface types
Expand Down Expand Up @@ -2045,6 +2068,13 @@ private static List<List<Tuple<ISenseOrEntry, ILexReference>>> SortAndFilterLexR
}
}
MoveTargetsToMasterList(cmOwner, curType.Item1, config, allTargetsForType, orderedTargets);
orderedTargets.Sort((list1, list2) =>
{
if (!list1.Any() && !list2.Any()) return 0;
if (!list1.Any()) return -1;
if (!list2.Any()) return 1;
return CompareLexRefTargets(list1[0], list2[0]);
});
return orderedTargets;
}

Expand Down
87 changes: 87 additions & 0 deletions Src/xWorks/DictionaryPublicationDecorator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,15 @@ private string GetSenseNumber(ILexSense sense)
return Cache.GetOutlineNumber(sense, LexSenseTags.kflidSenses, false, true, this);
}

public override ITsMultiString get_MultiStringProp(int hvo, int tag)
{
if (tag == m_mlHeadwordFlid)
{
return new PublicationAwareMultiStringAccessor(hvo, tag, this);
}
return base.get_MultiStringProp(hvo, tag);
}

public override ITsString get_MultiStringAlt(int hvo, int tag, int ws)
{
if (tag == m_mlHeadwordFlid)
Expand Down Expand Up @@ -615,5 +624,83 @@ private bool IsPublishableReference(ILexEntryRef entryRef)
// A reference is also not publishable if all of its PrimarySensesOrEntries are excluded
return entryRef.PrimarySensesOrEntries.Any(senseOrEntry => !m_excludedItems.Contains(senseOrEntry.Item.Hvo));
}

private class PublicationAwareMultiStringAccessor : IMultiAccessorBase
{
private readonly int m_hvo;
private readonly int m_tag;
private readonly DictionaryPublicationDecorator m_decorator;

public PublicationAwareMultiStringAccessor(int hvo, int tag, DictionaryPublicationDecorator decorator)
{
m_hvo = hvo;
m_tag = tag;
m_decorator = decorator;
}

public ITsString GetStringFromIndex(int iws, out int _ws)
{
throw new NotImplementedException();
}

public ITsString get_String(int ws)
{
return m_decorator.get_MultiStringAlt(m_hvo, m_tag, ws);
}

public void set_String(int ws, ITsString _tss)
{
throw new NotImplementedException();
}

public int StringCount { get; }
public void SetAnalysisDefaultWritingSystem(string val)
{
throw new NotImplementedException();
}

public void SetVernacularDefaultWritingSystem(string val)
{
throw new NotImplementedException();
}

public void SetUserWritingSystem(string val)
{
throw new NotImplementedException();
}

public void set_String(int ws, string val)
{
throw new NotImplementedException();
}

public bool TryWs(int ws, out int actualWs)
{
throw new NotImplementedException();
}

public bool TryWs(int ws, out int actualWs, out ITsString tssActual)
{
throw new NotImplementedException();
}

public ITsString StringOrNull(int ws)
{
throw new NotImplementedException();
}

public int Flid { get; }
public ITsString NotFoundTss { get; }
public ITsString AnalysisDefaultWritingSystem { get; set; }
public ITsString VernacularDefaultWritingSystem { get; set; }
public string UiString { get; }
public ITsString UserDefaultWritingSystem { get; set; }
public ITsString RawUserDefaultWritingSystem { get; }
public ITsString BestAnalysisVernacularAlternative { get; }
public ITsString BestAnalysisAlternative { get; }
public ITsString BestVernacularAlternative { get; }
public ITsString BestVernacularAnalysisAlternative { get; }
public int[] AvailableWritingSystemIds { get; }
}
}
}
Binary file added x64/Debug/System.ValueTuple.dll
Binary file not shown.
Loading