private void TestFeatureStructureContent(IFsFeatStruc featStruct) { IFdoOwningCollection <IFsFeatureSpecification> specCol = featStruct.FeatureSpecsOC; Assert.AreEqual(1, specCol.Count, "Count of top level feature specs"); foreach (IFsFeatureSpecification spec in specCol) { IFsComplexValue complex = spec as IFsComplexValue; Assert.IsNotNull(complex, "complex feature value is null and should not be"); Assert.AreEqual("subject agreement", complex.FeatureRA.Name.AnalysisDefaultWritingSystem.Text, "Expected complex feature name"); IFsFeatStruc fsNested = complex.ValueOA as IFsFeatStruc; IFdoOwningCollection <IFsFeatureSpecification> fsNestedCol = fsNested.FeatureSpecsOC; Assert.AreEqual(2, fsNestedCol.Count, "Nested fs has one feature"); foreach (IFsFeatureSpecification specNested in fsNestedCol) { IFsClosedValue closed = specNested as IFsClosedValue; Assert.IsNotNull(closed, "closed feature value is null and should not be"); if (!(((closed.FeatureRA.Name.AnalysisDefaultWritingSystem.Text == "gender") && (closed.ValueRA.Name.AnalysisDefaultWritingSystem.Text == "feminine gender")) || ((closed.FeatureRA.Name.AnalysisDefaultWritingSystem.Text == "person") && (closed.ValueRA.Name.AnalysisDefaultWritingSystem.Text == "first person")))) { Assert.Fail("Unexpected value found: {0}:{1}", closed.FeatureRA.Name.AnalysisDefaultWritingSystem.Text, closed.ValueRA.Name.AnalysisDefaultWritingSystem.Text); } } } }
private void CreateFeatStruc(IFsFeatStrucType type, IFsFeatStruc fs, FS featVals) { fs.TypeRA = type; foreach (KeyValuePair <IFsFeatDefn, object> featVal in featVals) { var closedFeat = featVal.Key as IFsClosedFeature; if (closedFeat != null) { var sym = (IFsSymFeatVal)featVal.Value; IFsClosedValue cv = Cache.ServiceLocator.GetInstance <IFsClosedValueFactory>().Create(); fs.FeatureSpecsOC.Add(cv); cv.FeatureRA = closedFeat; cv.ValueRA = sym; } else { var complexFeat = (IFsComplexFeature)featVal.Key; IFsComplexValue cv = Cache.ServiceLocator.GetInstance <IFsComplexValueFactory>().Create(); fs.FeatureSpecsOC.Add(cv); IFsFeatStruc childFS = Cache.ServiceLocator.GetInstance <IFsFeatStrucFactory>().Create(); cv.FeatureRA = complexFeat; cv.ValueOA = childFS; CreateFeatStruc(complexFeat.TypeRA, childFS, (FS)featVal.Value); } } }
protected void CreateFeatureStructureNodes(XmlDocument doc, XmlNode msaNode, IFsFeatStruc fs, int id, string sFSName) { if (fs == null) { return; } XmlNode fsNode = CreateXmlElement(doc, sFSName, msaNode); CreateXmlAttribute(doc, "id", id.ToString(), fsNode); foreach (IFsFeatureSpecification spec in fs.FeatureSpecsOC) { XmlNode feature = CreateXmlElement(doc, "feature", fsNode); XmlNode name = CreateXmlElement(doc, "name", feature); name.InnerText = spec.FeatureRA.Abbreviation.BestAnalysisAlternative.Text; XmlNode fvalue = CreateXmlElement(doc, "value", feature); IFsClosedValue cv = spec as IFsClosedValue; if (cv != null) { fvalue.InnerText = cv.ValueRA.Abbreviation.BestAnalysisAlternative.Text; } else { IFsComplexValue complex = spec as IFsComplexValue; if (complex == null) { continue; // skip this one since we're not dealing with it yet } IFsFeatStruc nestedFs = complex.ValueOA as IFsFeatStruc; if (nestedFs != null) { CreateFeatureStructureNodes(doc, fvalue, nestedFs, 0, "fs"); } } } }
private void AddNode(IFsFeatureSpecification spec, FeatureTreeNode parentNode) { IFsFeatDefn defn = spec.FeatureRA; TreeNodeCollection col; if (parentNode == null) { col = Nodes; } else { col = parentNode.Nodes; } IFsClosedValue closed = spec as IFsClosedValue; if (closed != null) { foreach (FeatureTreeNode node in col) { if (defn.Hvo == node.Hvo) { // already there (which is to be expected); see if its value is, too AddNodeFromFS(closed.ValueRA, node); return; } } // did not find the node, so add it and its value (not to be expected, but we'd better deal with it) FeatureTreeNode newNode = new FeatureTreeNode(defn.Name.AnalysisDefaultWritingSystem, (int)ImageKind.feature, (int)ImageKind.feature, defn.Hvo, FeatureTreeNodeInfo.NodeKind.Closed); InsertNode(newNode, parentNode); IFsSymFeatVal val = closed.ValueRA; if (val != null) { FeatureTreeNode newValueNode = new FeatureTreeNode(val.Name.AnalysisDefaultWritingSystem, (int)ImageKind.radioSelected, (int)ImageKind.radioSelected, val.Hvo, FeatureTreeNodeInfo.NodeKind.SymFeatValue); newValueNode.Chosen = true; InsertNode(newValueNode, newNode); } } IFsComplexValue complex = spec as IFsComplexValue; if (complex != null) { foreach (FeatureTreeNode node in col) { if (defn.Hvo == node.Hvo) { // already there (which is to be expected); see if its value is, too AddNode((IFsFeatStruc)complex.ValueOA, node); return; } } // did not find the node, so add it and its value (not to be expected, but we'd better deal with it) FeatureTreeNode newNode = new FeatureTreeNode(defn.Name.AnalysisDefaultWritingSystem, (int)ImageKind.complex, (int)ImageKind.complex, defn.Hvo, FeatureTreeNodeInfo.NodeKind.Complex); InsertNode(newNode, parentNode); AddNode((IFsFeatStruc)complex.ValueOA, newNode); } }
/// <summary> /// Recursively builds the feature structure based on contents of treeview node path. /// It recurses back up the treeview node path to the top and then builds the feature structure /// as it goes back down. /// </summary> /// <param name="node"></param> /// <param name="fs"></param> /// <returns></returns> private void BuildFeatureStructure(FeatureTreeNode node, ref IFsFeatStruc fs, ref IFsFeatureSpecification val) { if (node.Parent != null) { BuildFeatureStructure((FeatureTreeNode)node.Parent, ref fs, ref val); } switch (node.Kind) { case FeatureTreeNodeInfo.NodeKind.Complex: IFsComplexValue complex = fs.FindOrCreateComplexValue(node.Hvo); val = complex as FsComplexValue; val.FeatureRAHvo = node.Hvo; if (fs.TypeRA == null) { // this is the type which contains the complex feature fs.TypeRAHvo = FsFeatureSystem.GetTypeFromFsComplexFeature(m_cache, node.Hvo); } fs = (IFsFeatStruc)complex.ValueOA; if (fs.TypeRA == null) { // this is the type of what's being embedded in the fs IFsComplexFeature cf = val.FeatureRA as IFsComplexFeature; if (cf != null) { fs.TypeRA = cf.TypeRA; } } break; case FeatureTreeNodeInfo.NodeKind.Closed: val = (IFsClosedValue)fs.FindOrCreateClosedValue(node.Hvo); val.FeatureRAHvo = node.Hvo; break; case FeatureTreeNodeInfo.NodeKind.SymFeatValue: IFsClosedValue closed = val as IFsClosedValue; if (closed != null) { closed.ValueRAHvo = node.Hvo; } break; default: break; // do nothing } }
public void AddComplexFeaturesToFeatureSystemAndThenToAFeatureStructure() { ILangProject lp = Cache.LangProject; Assert.IsNotNull(lp.MsFeatureSystemOA, "Expect a feature system to be present"); // Set up the xml fs description XmlDocument doc = new XmlDocument(); string sFileDir = Path.Combine(SIL.FieldWorks.Common.Utils.DirectoryFinder.FwSourceDirectory, @"FDO\FDOTests\TestData"); string sFile = Path.Combine(sFileDir, "FeatureSystem2.xml"); doc.Load(sFile); XmlNode itemNeut = doc.SelectSingleNode("//item[@id='vNeut']"); // Add the feature for first time FsFeatureSystem.AddFeatureAsXml(Cache, itemNeut); IFsFeatureSystem msfs = lp.MsFeatureSystemOA; Assert.AreEqual(1, msfs.TypesOC.Count, "should have two types"); Assert.AreEqual(2, msfs.FeaturesOC.Count, "should have two features"); foreach (IFsFeatStrucType type in msfs.TypesOC) { string sName = type.Name.AnalysisDefaultWritingSystem; if (sName != "Subject agreement") { Assert.Fail("Unexpected fs type found: {0}", sName); } Assert.AreEqual(1, type.FeaturesRS.Count, "Expect to have one feature in the type"); IFsFeatDefn defn = (IFsFeatDefn)type.FeaturesRS.FirstItem; Assert.IsNotNull(defn, "first feature in type {0} is not null", sName); IFsComplexFeature complex = defn as IFsComplexFeature; if (complex != null) { Assert.AreEqual("subject agreement", complex.Name.AnalysisDefaultWritingSystem, "Expect name of subject agreement"); } IFsClosedFeature closed = defn as IFsClosedFeature; if (closed != null) { Assert.AreEqual("gender", closed.Name.AnalysisDefaultWritingSystem, "Expect to have gender feature"); foreach (IFsSymFeatVal value in closed.ValuesOC) { Assert.AreEqual("neuter gender", value.Name.AnalysisDefaultWritingSystem, "Expect neuter value"); } } } foreach (IFsFeatDefn defn in msfs.FeaturesOC) { IFsComplexFeature complex = defn as IFsComplexFeature; if (complex != null) { Assert.AreEqual("subject agreement", complex.Name.AnalysisDefaultWritingSystem, "Expect to have subject agreement feature"); } IFsClosedFeature closed = defn as IFsClosedFeature; if (closed != null) { Assert.AreEqual("gender", closed.Name.AnalysisDefaultWritingSystem, "Expect to have gender feature"); foreach (IFsSymFeatVal value in closed.ValuesOC) { Assert.AreEqual("neuter gender", value.Name.AnalysisDefaultWritingSystem, "Expect neuter value"); } } } // Now add a feature that differs only in value XmlNode itemFem = doc.SelectSingleNode("//item[@id='vFem']"); FsFeatureSystem.AddFeatureAsXml(Cache, itemFem); Assert.AreEqual(1, msfs.TypesOC.Count, "should have two types"); Assert.AreEqual(2, msfs.FeaturesOC.Count, "should have two features"); foreach (IFsFeatStrucType type in msfs.TypesOC) { string sName = type.Name.AnalysisDefaultWritingSystem; if (sName != "Subject agreement") { Assert.Fail("Unexpected fs type found: {0}", sName); } } foreach (IFsFeatDefn defn in msfs.FeaturesOC) { IFsComplexFeature complex = defn as IFsComplexFeature; if (complex != null) { Assert.AreEqual("subject agreement", complex.Name.AnalysisDefaultWritingSystem, "Expect to have subject agreement feature"); } IFsClosedFeature closed = defn as IFsClosedFeature; if (closed != null) { Assert.AreEqual("gender", closed.Name.AnalysisDefaultWritingSystem, "Expect to have gender feature"); Assert.AreEqual(2, closed.ValuesOC.Count, "should have two values"); foreach (IFsSymFeatVal cv in closed.ValuesOC) { if (cv.Name.AnalysisDefaultWritingSystem != "neuter gender" && cv.Name.AnalysisDefaultWritingSystem != "feminine gender") { Assert.Fail("Unexpected value found: {0}", cv.Name.AnalysisDefaultWritingSystem); } } } } // now add to feature structure IPartOfSpeech pos = (IPartOfSpeech)lp.PartsOfSpeechOA.PossibilitiesOS.FirstItem; Assert.IsNotNull(pos, "Need one non-null pos"); pos.DefaultFeaturesOA = new FsFeatStruc(); IFsFeatStruc featStruct = pos.DefaultFeaturesOA; // Add the first feature featStruct.AddFeatureFromXml(Cache, itemNeut); Assert.AreEqual("sbj", featStruct.TypeRA.Abbreviation.AnalysisDefaultWritingSystem, "Expect type sbj"); Assert.AreEqual(1, featStruct.FeatureSpecsOC.Count, "should have one feature spec"); foreach (IFsFeatureSpecification fspec in featStruct.FeatureSpecsOC) { IFsComplexValue complex = fspec as IFsComplexValue; Assert.IsNotNull(complex, "Should have non-null complex feature value"); IFsFeatStruc nestedFs = (IFsFeatStruc)complex.ValueOA; Assert.IsNotNull(nestedFs, "Should have non-null nested fs"); foreach (IFsClosedValue cv in nestedFs.FeatureSpecsOC) { Assert.AreEqual("gen", cv.FeatureRA.Abbreviation.AnalysisDefaultWritingSystem, "Expect to have gen feature name"); Assert.AreEqual("n", cv.ValueRA.Abbreviation.AnalysisDefaultWritingSystem, "Expect to have 'n' feature value"); } } // Now add a feature that differs only in value; it should override the old one featStruct.AddFeatureFromXml(Cache, itemFem); Assert.AreEqual("sbj", featStruct.TypeRA.Abbreviation.AnalysisDefaultWritingSystem, "Expect type sbj"); Assert.AreEqual(1, featStruct.FeatureSpecsOC.Count, "should have one feature spec"); foreach (IFsFeatureSpecification fspec in featStruct.FeatureSpecsOC) { IFsComplexValue complex = fspec as IFsComplexValue; Assert.IsNotNull(complex, "Should have non-null complex feature value"); IFsFeatStruc nestedFs = (IFsFeatStruc)complex.ValueOA; Assert.IsNotNull(nestedFs, "Should have non-null nested fs"); foreach (IFsClosedValue cv in nestedFs.FeatureSpecsOC) { if (cv.FeatureRA.Name.AnalysisDefaultWritingSystem != "gender" && cv.ValueRA.Name.AnalysisDefaultWritingSystem != "feminine gender") { Assert.Fail("Unexpected value found: {0}:{1}", cv.FeatureRA.Name.AnalysisDefaultWritingSystem, cv.ValueRA.Name.AnalysisDefaultWritingSystem); } } } // Now add another feature XmlNode item1st = doc.SelectSingleNode("//item[@id='v1']"); featStruct.AddFeatureFromXml(Cache, item1st); Assert.AreEqual("sbj", featStruct.TypeRA.Abbreviation.AnalysisDefaultWritingSystem, "Expect type sbj"); Assert.AreEqual(1, featStruct.FeatureSpecsOC.Count, "should have one feature spec at top feature structure"); foreach (IFsFeatureSpecification fspec in featStruct.FeatureSpecsOC) { IFsComplexValue complex = fspec as IFsComplexValue; Assert.IsNotNull(complex, "Should have non-null complex feature value"); IFsFeatStruc nestedFs = (IFsFeatStruc)complex.ValueOA; Assert.IsNotNull(nestedFs, "Should have non-null nested fs"); Assert.AreEqual(2, nestedFs.FeatureSpecsOC.Count, "should have two feature specs in nested feature structure"); foreach (IFsClosedValue cv in nestedFs.FeatureSpecsOC) { if (!(((cv.FeatureRA.Name.AnalysisDefaultWritingSystem == "gender") && (cv.ValueRA.Name.AnalysisDefaultWritingSystem == "feminine gender")) || ((cv.FeatureRA.Name.AnalysisDefaultWritingSystem == "person") && (cv.ValueRA.Name.AnalysisDefaultWritingSystem == "first person")))) { Assert.Fail("Unexpected value found: {0}:{1}", cv.FeatureRA.Name.AnalysisDefaultWritingSystem, cv.ValueRA.Name.AnalysisDefaultWritingSystem); } } } // Update inflectable features on pos pos.AddInflectableFeatsFromXml(Cache, itemNeut); Assert.AreEqual(1, pos.InflectableFeatsRC.Count, "should have 1 inflectable feature in pos"); foreach (IFsFeatDefn defn in pos.InflectableFeatsRC) { IFsComplexFeature complex = defn as IFsComplexFeature; if (complex != null) { Assert.AreEqual("subject agreement", complex.Name.AnalysisDefaultWritingSystem, "expect to find subject agreement in pos inflectable features"); } } // Check for correct ShortName string in complex Assert.AreEqual("1 f", featStruct.ShortName, "Incorrect ShortName for complex"); // Check for correct LongName string in complex Assert.AreEqual("[sbj:[pers:1 gen:f]]", featStruct.LongName, "Incorrect LongName for complex"); // Now add a closed feature not at the same level sFile = Path.Combine(sFileDir, "FeatureSystem3.xml"); doc = null; doc = new XmlDocument(); doc.Load(sFile); XmlNode itemAorist = doc.SelectSingleNode("//item[@id='xAor']"); FsFeatureSystem.AddFeatureAsXml(Cache, itemAorist); pos.AddInflectableFeatsFromXml(Cache, itemAorist); featStruct.AddFeatureFromXml(Cache, itemAorist); // Check for correct LongName Assert.AreEqual("[asp:aor sbj:[pers:1 gen:f]]", featStruct.LongName, "Incorrect LongName for complex and closed"); // Now add the features in the featurs struct in a different order pos.DefaultFeaturesOA = null; pos.DefaultFeaturesOA = new FsFeatStruc(); featStruct = pos.DefaultFeaturesOA; featStruct.AddFeatureFromXml(Cache, itemAorist); featStruct.AddFeatureFromXml(Cache, item1st); featStruct.AddFeatureFromXml(Cache, itemFem); // check for correct short name Assert.AreEqual("f 1 aor", featStruct.ShortName, "Incorrect ShortName for complex"); // Check for correct LongName Assert.AreEqual("[sbj:[gen:f pers:1] asp:aor]", featStruct.LongName, "Incorrect LongName for complex and closed"); }