public override void AddToDatabase(FdoCache cache) { CheckDisposed(); if (m_fInDatabase) { return; // It's already in the database, so nothing more can be done. } cache.BeginUndoTask(MGAStrings.ksUndoCreateInflectionFeature, MGAStrings.ksRedoCreateInflectionFeature); m_featDefn = FsFeatureSystem.AddFeatureAsXml(cache, m_node); cache.EndUndoTask(); }
/// <summary> /// figure out if the feature represented by the node is already in the database /// </summary> /// <param name="cache">database cache</param> public override void DetermineInDatabase(FdoCache cache) { CheckDisposed(); XmlNode item = m_node.SelectSingleNode("."); string sId = XmlUtils.GetOptionalAttributeValue(item, "id"); if (m_eKind == GlossListTreeView.ImageKind.closedFolder || m_eKind == GlossListTreeView.ImageKind.openFolder) { m_fInDatabase = false; } if (KindCanBeInDatabase()) { switch (m_eKind) { case GlossListTreeView.ImageKind.radio: // fall through case GlossListTreeView.ImageKind.radioSelected: // fall through case GlossListTreeView.ImageKind.checkBox: // fall through case GlossListTreeView.ImageKind.checkedBox: // these are all feature values m_fInDatabase = FsFeatureSystem.HasSymbolicValue(cache, sId); break; case GlossListTreeView.ImageKind.complex: m_fInDatabase = FsFeatureSystem.HasComplexFeature(cache, sId); break; case GlossListTreeView.ImageKind.userChoice: // closed feature string sStatus = XmlUtils.GetAttributeValue(m_node, "status"); if (sStatus == "proxy") { XmlNode xnType = this.m_node.SelectSingleNode("ancestor::item[@type='fsType']/@id"); if (xnType != null) { m_fInDatabase = FsFeatureSystem.FsFeatStrucTypeHasFeature(cache, xnType.InnerText, sId) && FsFeatureSystem.HasClosedFeature(cache, sId); } else { m_fInDatabase = FsFeatureSystem.HasClosedFeature(cache, sId); } } else { m_fInDatabase = FsFeatureSystem.HasClosedFeature(cache, sId); } break; } } }
/// <summary> /// figure out if the feature represented by the node is already in the database /// </summary> /// <param name="cache">database cache</param> public override void DetermineInDatabase(FdoCache cache) { CheckDisposed(); //XmlNode item = m_node.SelectSingleNode("."); string sId = XmlUtils.GetOptionalAttributeValue(m_node, "id"); if (IsAGroup()) { m_fInDatabase = false; } else { m_fInDatabase = FsFeatureSystem.HasClosedFeature(cache, sId); } }
/// <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 } }
private ILangProject CreateFeatureSystem(out IFsFeatStruc featStruct) { featStruct = null; ILangProject lp = Cache.LangProject; // 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; // Now add a feature that differs only in value XmlNode itemFem = doc.SelectSingleNode("//item[@id='vFem']"); FsFeatureSystem.AddFeatureAsXml(Cache, itemFem); // now add to feature structure IPartOfSpeech pos = (IPartOfSpeech)lp.PartsOfSpeechOA.PossibilitiesOS.FirstItem; pos.DefaultFeaturesOA = new FsFeatStruc(); featStruct = pos.DefaultFeaturesOA; // Add the first feature featStruct.AddFeatureFromXml(Cache, itemNeut); // Now add a feature that differs only in value; it should override the old one featStruct.AddFeatureFromXml(Cache, itemFem); // Now add another feature XmlNode item1st = doc.SelectSingleNode("//item[@id='v1']"); featStruct.AddFeatureFromXml(Cache, item1st); // Update inflectable features on pos XmlNode subjAgr = doc.SelectSingleNode("//item[@id='cSubjAgr']"); pos.AddInflectableFeatsFromXml(Cache, subjAgr); pos.AddInflectableFeatsFromXml(Cache, itemNeut); return(lp); }
public override void AddToDatabase(FdoCache cache) { CheckDisposed(); if (m_fInDatabase) { return; // It's already in the database, so nothing more can be done. } string sType = XmlUtils.GetManditoryAttributeValue(m_node, "type"); if (sType == "feature") { cache.BeginUndoTask(MGAStrings.ksUndoCreatePhonologicalFeature, MGAStrings.ksRedoCreatePhonologicalFeature); ILangProject lp = cache.LangProject; IFsFeatureSystem featsys = lp.PhFeatureSystemOA as IFsFeatureSystem; // Since phonological features in the chooser only have features and no values, // we need to create the positive and negative value nodes string sName = XmlUtils.GetManditoryAttributeValue(m_node, "id"); const string sTemplate = "<item id='v{0}Positive' type='value'><abbrev ws='en'>+</abbrev><term ws='en'>positive</term>" + "<fs id='v{0}PositiveFS' type='Phon'><f name='{0}'><sym value='+'/></f></fs></item>" + "<item id='v{0}Negative' type='value'><abbrev ws='en'>-</abbrev><term ws='en'>negative</term>" + "<fs id='v{0}NegativeFS' type='Phon'><f name='{0}'><sym value='-'/></f></fs></item>"; StringBuilder sb = new StringBuilder(); sb.AppendFormat(sTemplate, sName.Substring(1)); m_node.InnerXml += sb.ToString(); // have to use a ndw document or, for some odd reason, it keeps on using an old value and not the new one... XmlDocument doc = new XmlDocument(); doc.LoadXml(m_node.OuterXml); // add positive value; note that the FsFeatDefn will be the same for both XmlNode valueNode = doc.SelectSingleNode("//item[contains(@id,'Positive')]"); m_featDefn = FsFeatureSystem.AddFeatureAsXml(cache, featsys, valueNode); // add negative value valueNode = doc.SelectSingleNode("//item[contains(@id,'Negative')]"); m_featDefn = FsFeatureSystem.AddFeatureAsXml(cache, featsys, valueNode); cache.EndUndoTask(); } }
public void AddClosedFeaturesToFeatureSystemAndThenToAFeatureStructure() { ILangProject lp = Cache.LangProject; // Set up the xml fs description XmlDocument doc = new XmlDocument(); doc.LoadXml(m_ksFS1); XmlNode itemNeut = doc.SelectSingleNode("/item/item[3]"); // Add the feature for first time FsFeatureSystem.AddFeatureAsXml(Cache, itemNeut); IFsFeatureSystem msfs = lp.MsFeatureSystemOA; Assert.AreEqual(1, msfs.TypesOC.Count, "should have one type"); Assert.AreEqual(1, msfs.FeaturesOC.Count, "should have one feature"); foreach (IFsFeatStrucType type in msfs.TypesOC) { Assert.AreEqual("Agr", type.Abbreviation.AnalysisDefaultWritingSystem, "Expect to have Agr type"); Assert.AreEqual(1, type.FeaturesRS.Count, "Expect to have one feature in the type"); IFsClosedFeature closed = (IFsClosedFeature)type.FeaturesRS.FirstItem; Assert.AreEqual("gender", closed.Name.AnalysisDefaultWritingSystem, "Expect name of gender"); } foreach (IFsClosedFeature closed in msfs.FeaturesOC) { 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/item[2]"); FsFeatureSystem.AddFeatureAsXml(Cache, itemFem); Assert.AreEqual(1, msfs.TypesOC.Count, "should have one type"); Assert.AreEqual(1, msfs.FeaturesOC.Count, "should have one feature"); foreach (IFsFeatStrucType type in msfs.TypesOC) { Assert.AreEqual("Agr", type.Abbreviation.AnalysisDefaultWritingSystem, "Expect to have Agr type"); } foreach (IFsClosedFeature closed in msfs.FeaturesOC) { 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; pos.DefaultFeaturesOA = new FsFeatStruc(); IFsFeatStruc featStruct = pos.DefaultFeaturesOA; // Add the first feature featStruct.AddFeatureFromXml(Cache, itemNeut); Assert.AreEqual("Agr", featStruct.TypeRA.Abbreviation.AnalysisDefaultWritingSystem, "Expect type Agr"); Assert.AreEqual(1, featStruct.FeatureSpecsOC.Count, "should have one feature spec"); foreach (IFsClosedValue cv in featStruct.FeatureSpecsOC) { Assert.AreEqual("Gen", cv.FeatureRA.Abbreviation.AnalysisDefaultWritingSystem, "Expect to have Gen feature name"); Assert.AreEqual("Neut", cv.ValueRA.Abbreviation.AnalysisDefaultWritingSystem, "Expect to have Neut feature value"); } // Now add a feature that differs only in value; it should override the old one featStruct.AddFeatureFromXml(Cache, itemFem); Assert.AreEqual("Agr", featStruct.TypeRA.Abbreviation.AnalysisDefaultWritingSystem, "Expect type Agr"); Assert.AreEqual(1, featStruct.FeatureSpecsOC.Count, "should have one feature spec"); foreach (IFsClosedValue cv in featStruct.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); } } // Update inflectable features on pos pos.AddInflectableFeatsFromXml(Cache, itemNeut); Assert.AreEqual(1, pos.InflectableFeatsRC.Count, "should have 1 inflectable feature in pos"); foreach (IFsClosedFeature closed in pos.InflectableFeatsRC) { Assert.AreEqual("gender", closed.Name.AnalysisDefaultWritingSystem, "expect to find gender in pos inflectable features"); } // Check for correct ShortName string in closed Assert.AreEqual("Fem", featStruct.ShortName, "Incorrect ShortName for closed"); // Check for correct LongName string in complex Assert.AreEqual("[Gen:Fem]", featStruct.LongName, "Incorrect LongName for closed"); }
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"); }
protected virtual void HandleCheckBoxNodes(TreeView tv, TreeNode tn) { UndoLastSelectedNode(); if (m_fTerminalsUseCheckBoxes) { if (IsTerminalNode(tn)) { MasterInflectionFeature mif = tn.Tag as MasterInflectionFeature; if (tn.Checked) { if (mif == null || !mif.InDatabase) { tn.Checked = false; tn.ImageIndex = tn.SelectedImageIndex = (int)ImageKind.checkBox; } } else { tn.Checked = true; tn.ImageIndex = tn.SelectedImageIndex = (int)ImageKind.checkedBox; if (mif != null) { string sId = XmlUtils.GetOptionalAttributeValue(mif.Node, "id"); if (FsFeatureSystem.HasSymbolicValue(m_cache, sId)) { // we want to set all other sisters that are in the database TreeNode sibling = tn.Parent.FirstNode; while (sibling != null) { if (IsTerminalNode(sibling) && sibling != tn) { mif = sibling.Tag as MasterInflectionFeature; if (mif != null) { sId = XmlUtils.GetOptionalAttributeValue(mif.Node, "id"); if (FsFeatureSystem.HasSymbolicValue(m_cache, sId)) { sibling.Checked = true; sibling.ImageIndex = sibling.SelectedImageIndex = (int)ImageKind.checkedBox; } } } sibling = sibling.NextNode; } } } } tv.Invalidate(); } } else { if (IsTerminalNode(tn)) { tn.Checked = true; tn.ImageIndex = tn.SelectedImageIndex = (int)ImageKind.radioSelected; if (tn.Parent != null) { TreeNode sibling = tn.Parent.FirstNode; while (sibling != null) { if (IsTerminalNode(sibling) && sibling != tn) { sibling.Checked = false; sibling.ImageIndex = sibling.SelectedImageIndex = (int)ImageKind.radio; } sibling = sibling.NextNode; } } tv.Invalidate(); } m_lastSelectedTreeNode = tn; } }