/// <summary> /// Set up the referring semantic domains for the domains found of an entry /// </summary> /// <param name="semanticDomainHvos">an array of semantic domain HVOs</param> void SetupDomainsForEntry(int[] semanticDomainHvos) { m_cdaTemp.CacheVecProp(m_hvoEntry, RelatedWordsVc.ktagDomains, semanticDomainHvos, semanticDomainHvos.Length); var entries = new List <int>(); var semanticDomainRepository = m_cache.ServiceLocator.GetInstance <ICmSemanticDomainRepository>(); foreach (var semanticDomainhvo in semanticDomainHvos) { var semanticDomain = semanticDomainRepository.GetObject(semanticDomainhvo); foreach (ICmObject obj in semanticDomain.ReferringObjects) { if (obj is ILexSense && (obj as ILexSense).SemanticDomainsRC.Contains(semanticDomain)) { var entry = obj.OwnerOfClass(LexEntryTags.kClassId) as ILexEntry; if (entry != null && entry.LexemeFormOA != null && entry.LexemeFormOA.Form != null) { entries.Add(entry.Hvo); m_cdaTemp.CacheStringProp(entry.Hvo, RelatedWordsVc.ktagName, entry.LexemeFormOA.Form.VernacularDefaultWritingSystem); } } } if (entries.Count > 0) { m_cdaTemp.CacheVecProp(semanticDomainhvo, RelatedWordsVc.ktagWords, entries.ToArray(), entries.Count); entries.Clear(); } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Adds paragraphs to the database /// </summary> /// <param name="ws"></param> /// <param name="firstPara"></param> /// <param name="secondPara"></param> /// ------------------------------------------------------------------------------------ private void AddParagraphs(int ws, string firstPara, string secondPara) { int hvoPara1 = m_hvoPara++; int hvoPara2 = m_hvoPara++; int hvoText1 = m_hvoText++; int hvoText2 = m_hvoText++; ITsStrFactory tsf = TsStrFactoryClass.Create(); ITsString tsString = tsf.MakeString(firstPara, ws); IVwCacheDa cda = Cache.VwCacheDaAccessor; cda.CacheStringProp(hvoPara1, (int)StTxtPara.StTxtParaTags.kflidContents, tsString); tsString = tsf.MakeString(secondPara, ws); cda.CacheStringProp(hvoPara2, (int)StTxtPara.StTxtParaTags.kflidContents, tsString); // Now make each of them the paragraphs of an StText. int[] hvoParas = { hvoPara1 }; cda.CacheVecProp(hvoText1, (int)StText.StTextTags.kflidParagraphs, hvoParas, 1); hvoParas[0] = hvoPara2; cda.CacheVecProp(hvoText2, (int)StText.StTextTags.kflidParagraphs, hvoParas, 1); // And the StTexts to the contents of a dummy property. AddVecProp(new int[] { hvoText1, hvoText2 }); }
/// <summary> /// /// </summary> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="ws"></param> /// <param name="cda"></param> public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { IMoMorphSynAnalysis msa = MoMorphSynAnalysis.CreateFromDBObject(m_cache, hvo); ITsStrFactory tsf = TsStrFactoryClass.Create(); cda.CacheStringProp(hvo, tag, tsf.MakeString(msa.InterlinearName, m_cache.DefaultAnalWs)); }
public void StringProp_SimpleString() { // Test StringProp ITsPropsBldr propsBldr = TsStringUtils.MakePropsBldr(); ITsStrBldr strBldr = TsStringUtils.MakeStrBldr(); propsBldr.SetStrPropValue((int)FwTextPropType.ktptNamedStyle, "Verse"); strBldr.Replace(0, 0, "StringPropTest", propsBldr.GetTextProps()); ITsString tsString = strBldr.GetString(); m_IVwCacheDa.CacheStringProp(1118, 2228, tsString); ITsString tsStringNew = m_ISilDataAccess.get_StringProp(1118, 2228); Assert.AreEqual(tsString, tsStringNew); }
/// <summary> /// Fake doing the change by setting the specified property to the appropriate value /// for each item in the list. Disable items that can't be set. /// </summary> /// <param name="itemsToChange"></param> /// <param name="ktagFakeFlid"></param> public void FakeDoit(Set <int> itemsToChange, int tagFakeFlid, int tagEnable, ProgressState state) { CheckDisposed(); IVwCacheDa cda = m_cache.VwCacheDaAccessor; ISilDataAccess sda = m_cache.MainCacheAccessor; ITsString tss = m_cache.MakeAnalysisTss(m_selectedLabel); // Build a Set of parts of speech that can take this class. Set <int> possiblePOS = GetPossiblePartsOfSpeech(); int i = 0; // Report progress 50 times or every 100 items, whichever is more (but no more than once per item!) int interval = Math.Min(100, Math.Max(itemsToChange.Count / 50, 1)); foreach (int hvo in itemsToChange) { i++; if (i % interval == 0) { state.PercentDone = i * 100 / itemsToChange.Count; state.Breath(); } bool fEnable = IsItemEligible(sda, hvo, possiblePOS); if (fEnable) { cda.CacheStringProp(hvo, tagFakeFlid, tss); } cda.CacheIntProp(hvo, tagEnable, (fEnable ? 1 : 0)); } }
/// <summary> /// Load the information about the domains of hvoEntry. Returns false /// if the entry has no associated domains or none of them are linked to any other entries. /// </summary> /// <param name="cache"></param> /// <param name="hvoEntry">int ID of the lexical entry</param> /// <param name="hvoSemanticDomainsOut">A list of int IDs of the semantic domains of the lexical entry</param> /// <param name="cdaTemp"></param> /// <returns></returns> static private bool LoadDomainInfo(FdoCache cache, int hvoEntry, out int[] hvoSemanticDomainsOut, out IVwCacheDa cdaTemp) { // REVIEW (SteveMiller): The LINQ below runs slow the first time its run. We should try to // optimize it if possible. var entryRepo = cache.ServiceLocator.GetInstance <ILexEntryRepository>(); var lexEntry = entryRepo.GetObject(hvoEntry); var domains = (from sense in lexEntry.AllSenses from sd in sense.SemanticDomainsRC where (from incoming in sd.ReferringObjects where incoming is ILexSense && incoming.OwnerOfClass <ILexEntry>() != lexEntry select incoming).FirstOrDefault() != null select sd).Distinct().ToArray(); hvoSemanticDomainsOut = ( from sd in domains select sd.Hvo).ToArray(); cdaTemp = VwCacheDaClass.Create(); foreach (var sd in domains) { cdaTemp.CacheStringProp(sd.Hvo, RelatedWordsVc.ktagName, sd.Name.BestVernacularAnalysisAlternative); } cdaTemp.CacheVecProp(hvoEntry, RelatedWordsVc.ktagDomains, hvoSemanticDomainsOut, hvoSemanticDomainsOut.Length); return(hvoSemanticDomainsOut.Length > 0); }
public override void MakeRoot() { m_rootb = (IVwRootBox) new FwViews.VwRootBoxClass(); m_rootb.SetSite(this); int hvoRoot = 1; m_sda = (ISilDataAccess) new FwViews.VwCacheDaClass(); // Usually not here, but in some application global passed to each view. m_wsf = (ILgWritingSystemFactory) new FwLanguage.LgWritingSystemFactoryClass(); m_sda.set_WritingSystemFactory(m_wsf); m_rootb.set_DataAccess(m_sda); ITsStrFactory tsf = (ITsStrFactory) new FwKernelLib.TsStrFactoryClass(); ITsString tss = tsf.MakeString("Hello World! This is a view", m_wsf.get_UserWs()); IVwCacheDa cda = (IVwCacheDa)m_sda; cda.CacheStringProp(hvoRoot, ktagProp, tss); m_vVc = new HvVc(); m_rootb.SetRootObject(hvoRoot, m_vVc, kfrText, null); m_fRootboxMade = true; m_dxdLayoutWidth = -50000; // Don't try to draw until we get OnSize and do layout. }
/// <summary> /// Obain an initial default value from the object's shortname (and convert to appropriate writing /// system). /// </summary> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="ws"></param> /// <param name="_cda"></param> public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { ICmObject obj = CmObject.CreateFromDBObject(m_cache, hvo); //Enhance JohnT: don't preload everything. string name = obj.ShortName; ITsStrFactory tsf = TsStrFactoryClass.Create(); cda.CacheStringProp(hvo, tag, tsf.MakeString(name, m_ws)); }
/// <summary> /// Add a new string as the next line of the text. Does not display. /// Call Complete() to update after adding all lines. /// </summary> /// <param name="tss"></param> public void AddPara(ITsString tss) { CheckDisposed(); int hvoPara = m_hvoNextPara++; m_cd.CacheStringProp(hvoPara, (int)SampleTags.ktagParaContents, tss); }
/// <summary> /// Load the information about the domains of hvoEntry. Returns false /// if the entry has no associated domains or none of them are linked to any other entries. /// </summary> /// <param name="cache"></param> /// <param name="hvoEntry"></param> /// <param name="domains"></param> /// <param name="cdaTemp"></param> /// <param name="fMoreRows"></param> /// <param name="owner"></param> /// <returns></returns> static private bool LoadDomainInfo(FdoCache cache, int hvoEntry, out int[] domainsOut, out IVwCacheDa cdaTemp, IWin32Window owner) { // This produces first the Semantic domains of the senses of the entry, // then restricts to those that occur on some other entry, // then looks up the vernacular (or, if none, analysis) name of the domains. The are sorted by // domain name. // We do left outer joins for the last two so we can distinguish the failure // modes "no SDs on senses of initial entry" versus "no other entries in those SDs" string sql1 = string.Format("select lssd2.dst, cn.txt, cn.ws from LexEntry le" + " join LexSense_ ls on ls.owner$ = le.id" + " join LexSense_SemanticDomains lssd on lssd.src = ls.id " + " left outer join LexSense_SemanticDomains lssd2 on lssd2.dst = lssd.dst" + " and exists (select * from CmObject lsother" + " join LexEntry leother on leother.id = lsother.owner$ and lsother.id = lssd2.src and leother.id != le.id)" + " left outer join CmPossibility_Name cn on lssd2.dst = cn.obj and cn.ws" + " in ({0}, {1}) where le.id = {2}" + " group by lssd2.dst, cn.txt, cn.ws" + " order by cn.txt", cache.DefaultVernWs, cache.DefaultAnalWs, hvoEntry); IOleDbCommand odc = DbOps.MakeRowSet(cache, sql1, null); bool fGotSrcDomain = false; // true if we found a semantic domain on some sense of the source entry try { bool fMoreRows; List <int> domains = new List <int>(); cdaTemp = VwCacheDaClass.Create(); for (odc.NextRow(out fMoreRows); fMoreRows; odc.NextRow(out fMoreRows)) { fGotSrcDomain = true; // any row indicates success here. int hvoDomain = DbOps.ReadInt(odc, 0); if (hvoDomain == 0) { continue; // null row, an SD that occurs on no other entry. } if (!((ISilDataAccess)cdaTemp).get_IsPropInCache(hvoDomain, RelatedWordsVc.ktagName, (int)CellarModuleDefns.kcptString, 0)) { ITsString tss = DbOps.ReadTss2(odc, 1); if (tss == null) { tss = FDO.Cellar.CmPossibility.BestAnalysisOrVernName(cache, hvoDomain); } cdaTemp.CacheStringProp(hvoDomain, RelatedWordsVc.ktagName, tss); domains.Add(hvoDomain); } } domainsOut = DbOps.ListToIntArray(domains); } finally { DbOps.ShutdownODC(ref odc); } return(fGotSrcDomain); }
public void MakeStringProp(int hvo, XmlNode node, string attrName, int tag, int ws, ITsStrFactory tsf, IVwCacheDa cda) { string val = GetAttrVal(node, attrName); if (val == null) { return; } cda.CacheStringProp(hvo, tag, tsf.MakeString(val, ws)); }
/// <summary> /// The string is being written. Since we always just use CacheStringProp to set a /// fake value, this means the user is actually editing the string...nothing else would /// (normally) cause a SetStringProp call. /// </summary> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="ws"></param> /// <param name="unk"></param> /// <param name="sda"></param> public override void WriteObj(int hvo, int tag, int ws, object unk, ISilDataAccess sda) { ITsString tssNew = (ITsString)unk; //ITsString tssOld = sda.get_StringProp(hvo, tag); // Todo: if possible, figure lookahead and substitute. Can we do that here? // Problem is backspace (needs to delete range AND one character)..should it fill in? // For now, see if we can make it work just doing a write-through and notify, and put the // smarts in a SelectionChanged somewhere. // Note that we do NOT use sds.SetStringProp, which would attempt to update the DB. IVwCacheDa cda = sda as IVwCacheDa; cda.CacheStringProp(hvo, tag, tssNew); //sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvo, tag, 0, 0, 0); }
public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { // Value is always an empty string in the specified writing system. ITsStrFactory tsf = TsStrFactoryClass.Create(); ITsString tssEmpty = tsf.MakeString("", m_ws); if (ws == 0) { cda.CacheStringProp(hvo, tag, tssEmpty); } else { cda.CacheStringAlt(hvo, tag, ws, tssEmpty); } }
/// <summary> /// Load the information about the lexical relations that link to hvoEntry. Specifically, we want LexReferences /// that refer to the target Entry (hvoEntry) and also some other lexical entry. /// For each such thing, we store in cdaTemp the name (or, if appropriate, the reverse name) of the /// relationship that hvoEntry has to the other entry(s) in the lex reference, as property RelatedWordsVc.ktagName of /// the LexReference Hvo. Return through relsOut the list of LexReferences that are thus related to hvoEntry. /// Return true if there are any. /// </summary> /// <param name="cache"></param> /// <param name="hvoEntry">ID of the lexical entry we're working with</param> /// <param name="relsOut">an array of IDs (HVOs) for related objects</param> /// <param name="cdaTemp"></param> /// <returns>false if the entry has no associated lexical relations, or none of them are linked to any other entries.</returns> // static private bool LoadLexicalRelationInfo(FdoCache cache, int hvoEntry, out int[] relsOut, IVwCacheDa cdaTemp) { var relatedObjectIds = new List <int>(); var entryRepository = cache.ServiceLocator.GetInstance <ILexEntryRepository>(); var lexEntry = entryRepository.GetObject(hvoEntry); var targets = new HashSet <ICmObject>(lexEntry.AllSenses.Cast <ICmObject>()) { lexEntry }; foreach (ILexRefType lexRefType in cache.LanguageProject.LexDbOA.ReferencesOA.ReallyReallyAllPossibilities) { foreach (var lexReference in lexRefType.MembersOC) { // If at least one target is the lex entry or one of its senses. if ((from target in lexReference.TargetsRS where targets.Contains(target) select target).FirstOrDefault() != null && (from target in lexReference.TargetsRS where !targets.Contains(target) select target).FirstOrDefault() != null) { // The name we want to use for our lex reference is either the name or the reverse name // (depending on the direction of the relationship, if relevant) of the owning lex ref type. var lexReferenceName = lexRefType.Name.BestVernacularAnalysisAlternative; if (lexRefType.MappingType == (int)MappingTypes.kmtEntryAsymmetricPair || lexRefType.MappingType == (int)MappingTypes.kmtEntryOrSenseAsymmetricPair || lexRefType.MappingType == (int)MappingTypes.kmtSenseAsymmetricPair || lexRefType.MappingType == (int)MappingTypes.kmtEntryTree || lexRefType.MappingType == (int)MappingTypes.kmtEntryOrSenseTree || lexRefType.MappingType == (int)MappingTypes.kmtSenseTree) { if (lexEntry.OwnOrd == 0 && lexRefType.Name != null) // the original code had a check for name length as well. { lexReferenceName = lexRefType.ReverseName.BestVernacularAnalysisAlternative; } } cdaTemp.CacheStringProp(lexReference.Hvo, RelatedWordsVc.ktagName, lexReferenceName); relatedObjectIds.Add(lexReference.Hvo); } } } relsOut = relatedObjectIds.ToArray(); return(relsOut.Length > 0); }
/// <summary> /// Load the information about the domains of hvoEntry. Returns false /// if the entry has no associated domains or none of them are linked to any other entries. /// </summary> /// <param name="cache"></param> /// <param name="hvoEntry">int ID of the lexical entry</param> /// <param name="hvoSemanticDomainsOut">A list of int IDs of the semantic domains of the lexical entry</param> /// <param name="cdaTemp"></param> /// <returns></returns> static private bool LoadDomainInfo(FdoCache cache, int hvoEntry, out int[] hvoSemanticDomainsOut, out IVwCacheDa cdaTemp) { // REVIEW (SteveMiller): The LINQ below runs slow the first time its run. We should try to // optimize it if possible. var entryRepo = cache.ServiceLocator.GetInstance<ILexEntryRepository>(); var lexEntry = entryRepo.GetObject(hvoEntry); var domains = (from sense in lexEntry.AllSenses from sd in sense.SemanticDomainsRC where (from incoming in sd.ReferringObjects where incoming is ILexSense && incoming.OwnerOfClass<ILexEntry>() != lexEntry select incoming).FirstOrDefault() != null select sd).Distinct().ToArray(); hvoSemanticDomainsOut = ( from sd in domains select sd.Hvo).ToArray(); cdaTemp = VwCacheDaClass.Create(); foreach (var sd in domains) { cdaTemp.CacheStringProp(sd.Hvo, RelatedWordsVc.ktagName, sd.Name.BestVernacularAnalysisAlternative); } cdaTemp.CacheVecProp(hvoEntry, RelatedWordsVc.ktagDomains, hvoSemanticDomainsOut, hvoSemanticDomainsOut.Length); return hvoSemanticDomainsOut.Length > 0; }
/// <summary> /// Load the information about the lexical relations that link to hvoEntry. Specifically, we want LexReferences /// that refer to the target Entry (hvoEntry) and also some other lexical entry. /// For each such thing, we store in cdaTemp the name (or, if appropriate, the reverse name) of the /// relationship that hvoEntry has to the other entry(s) in the lex reference, as property RelatedWordsVc.ktagName of /// the LexReference Hvo. Return through relsOut the list of LexReferences that are thus related to hvoEntry. /// Return true if there are any. /// </summary> /// <param name="cache"></param> /// <param name="hvoEntry">ID of the lexical entry we're working with</param> /// <param name="relsOut">an array of IDs (HVOs) for related objects</param> /// <param name="cdaTemp"></param> /// <returns>false if the entry has no associated lexical relations, or none of them are linked to any other entries.</returns> // static private bool LoadLexicalRelationInfo(FdoCache cache, int hvoEntry, out int[] relsOut, IVwCacheDa cdaTemp) { var relatedObjectIds = new List<int>(); var entryRepository = cache.ServiceLocator.GetInstance<ILexEntryRepository>(); var lexEntry = entryRepository.GetObject(hvoEntry); var targets = new HashSet<ICmObject>(lexEntry.AllSenses.Cast<ICmObject>()) {lexEntry}; foreach (ILexRefType lexRefType in cache.LanguageProject.LexDbOA.ReferencesOA.ReallyReallyAllPossibilities) { foreach (var lexReference in lexRefType.MembersOC) { // If at least one target is the lex entry or one of its senses. if ((from target in lexReference.TargetsRS where targets.Contains(target) select target).FirstOrDefault() != null && (from target in lexReference.TargetsRS where !targets.Contains(target) select target).FirstOrDefault() != null) { // The name we want to use for our lex reference is either the name or the reverse name // (depending on the direction of the relationship, if relevant) of the owning lex ref type. var lexReferenceName = lexRefType.Name.BestVernacularAnalysisAlternative; if (lexRefType.MappingType == (int)MappingTypes.kmtEntryAsymmetricPair || lexRefType.MappingType == (int)MappingTypes.kmtEntryOrSenseAsymmetricPair || lexRefType.MappingType == (int)MappingTypes.kmtSenseAsymmetricPair || lexRefType.MappingType == (int)MappingTypes.kmtEntryTree || lexRefType.MappingType == (int)MappingTypes.kmtEntryOrSenseTree || lexRefType.MappingType == (int)MappingTypes.kmtSenseTree) { if (lexEntry.OwnOrd == 0 && lexRefType.Name != null) // the original code had a check for name length as well. lexReferenceName = lexRefType.ReverseName.BestVernacularAnalysisAlternative; } cdaTemp.CacheStringProp(lexReference.Hvo, RelatedWordsVc.ktagName, lexReferenceName); relatedObjectIds.Add(lexReference.Hvo); } } } relsOut = relatedObjectIds.ToArray(); return relsOut.Length > 0; }
/// <summary> /// /// </summary> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="ws"></param> /// <param name="cda"></param> public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { // JohnT: this is often used in sorting and filtering, it is usually way too expensive // to either validate or preload the object. This can cost several queries per item // in a 32K item list! ICmObject obj = CmObject.CreateFromDBObject(m_cache, hvo, false); ITsString tss; if (m_methodInfo != null) { object[] parm = new object[1]; parm[0] = this.WsId(m_cache, hvo, ws); tss = (ITsString)m_methodInfo.Invoke(obj, parm); } else { tss = (ITsString)m_propertyInfo.GetValue(obj, null); } cda.CacheStringProp(hvo, tag, tss); }
public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { // Value is always an empty string in the specified writing system. ITsStrFactory tsf = TsStrFactoryClass.Create(); ITsString tssEmpty = tsf.MakeString("", m_ws); if (ws == 0) cda.CacheStringProp(hvo, tag, tssEmpty); else cda.CacheStringAlt(hvo, tag, ws, tssEmpty); }
void SetupDomainsForEntry(int[] domains) { m_cdaTemp.CacheVecProp(m_hvoEntry, RelatedWordsVc.ktagDomains, domains, domains.Length); // This produces first the Semantic domains of the senses of the entry, // then uses a backreference to find all senses linked to those domains. // Todo JohnT: this finds only entries that directly own senses linked to the relevant domains. // It will not find entries that only have senses with subsenses in the domain. // This is because we're specifically looking for MoForms with the same owner as the senses we found. // We'd have to do something tricky and recursive to get owning entry of a subsense. string sql2 = string.Format("select lscd.dst, cmls.owner$, mff.txt from LexSense ls" + " join CmObject cols on ls.id = cols.id and cols.owner$ = {0}" + " join LexSense_SemanticDomains lscd on lscd.src = ls.id" + " join LexSense_SemanticDomains lscd2 on lscd2.dst = lscd.dst and lscd2.src != ls.id" + " join CmObject cmls on lscd2.src = cmls.id and cmls.owner$ != {0}" + " join MoForm_ mf on mf.owner$ = cmls.owner$ and mf.OwnFlid$ = {1}" + " join MoForm_Form mff on mff.obj = mf.id and mff.ws = {2}" + " group by lscd.dst, cmls.owner$, mff.txt" + " order by lscd.dst, mff.txt", m_hvoEntry, (int)LexEntry.LexEntryTags.kflidLexemeForm, m_cache.DefaultVernWs); IOleDbCommand odc = DbOps.MakeRowSet(m_cache, sql2, null); try { bool fMoreRows; List <int> words = new List <int>(); int hvoOldDomain = 0; // to trigger change of domain on first iteration for (odc.NextRow(out fMoreRows); fMoreRows; odc.NextRow(out fMoreRows)) { int hvoNewDomain = DbOps.ReadInt(odc, 0); if (hvoNewDomain != hvoOldDomain) { if (hvoOldDomain != 0) { m_cdaTemp.CacheVecProp(hvoOldDomain, RelatedWordsVc.ktagWords, DbOps.ListToIntArray(words), words.Count); words.Clear(); } hvoOldDomain = hvoNewDomain; } int hvoWord = DbOps.ReadInt(odc, 1); // JohnT: if I was better at sql, I could no doubt figure out how to prevent // duplicates in the query above, which are caused by having two or more senses of the // same entry in the same domain. But it's easier to just eliminate them here (and maybe // even faster). if (!words.Contains(hvoWord)) { m_cdaTemp.CacheStringProp(hvoWord, RelatedWordsVc.ktagName, DbOps.ReadTss(odc, 2, m_cache.DefaultVernWs)); words.Add(hvoWord); } } if (hvoOldDomain != 0) { // Cache words of last domain. m_cdaTemp.CacheVecProp(hvoOldDomain, RelatedWordsVc.ktagWords, DbOps.ListToIntArray(words), words.Count); } int hvoLf = m_cache.MainCacheAccessor.get_ObjectProp(m_hvoEntry, (int)LexEntry.LexEntryTags.kflidLexemeForm); if (hvoLf != 0) { ITsString tssCf = m_cache.MainCacheAccessor.get_MultiStringAlt(hvoLf, (int)MoForm.MoFormTags.kflidForm, m_cache.DefaultVernWs); m_cdaTemp.CacheStringProp(m_hvoEntry, RelatedWordsVc.ktagCf, tssCf); } } finally { DbOps.ShutdownODC(ref odc); } }
/// <summary> /// Load the value into the cache. /// </summary> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="ws"></param> /// <param name="cda"></param> public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { ISilDataAccess sda = cda as ISilDataAccess; int ichMin = sda.get_IntProp(hvo, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginOffset); int ichLim = sda.get_IntProp(hvo, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidEndOffset); int hvoObj = sda.get_ObjectProp(hvo, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginObject); int flid = sda.get_IntProp(hvo, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidFlid); ITsString tss = sda.get_StringProp(hvoObj, flid); Debug.Assert(ichMin < tss.Length); Debug.Assert(ichLim <= tss.Length); cda.CacheStringProp(hvo, tag, tss.GetSubstring(ichMin, ichLim)); }
/// <summary> /// Load the information about the lexical relations that link to hvoEntry. /// </summary> /// <param name="cache"></param> /// <param name="hvoEntry"></param> /// <param name="relsOut"></param> /// <param name="cdaTemp"></param> /// <param name="owner"></param> /// <returns>false if the entry has no associated lexical relations, or none of them are linked to any other entries.</returns> static private bool LoadLexicalRelationInfo(FdoCache cache, int hvoEntry, out int[] relsOut, IVwCacheDa cdaTemp, IWin32Window owner) { string sql1 = string.Format("SELECT DISTINCT tar2.Src, lrt.MappingType, tar.Ord, cn.Txt, cn.Ws, rev.Txt, rev.Ws" + " FROM LexReference_Targets tar" + " LEFT OUTER JOIN LexReference_Targets tar2 ON tar2.Src=tar.Src AND EXISTS (SELECT * FROM CmObject other WHERE other.Id=tar2.Dst AND other.Id != tar.Dst)" + " LEFT OUTER JOIN LexRefType_Members mem ON mem.Dst=tar2.Src" + " LEFT OUTER JOIN LexRefType lrt ON lrt.Id=mem.Src" + " LEFT OUTER JOIN CmPossibility_Name cn ON cn.Obj=mem.Src AND cn.Ws IN ({0}, {1})" + " LEFT OUTER JOIN LexRefType_ReverseName rev ON rev.Obj=mem.Src AND rev.Ws IN ({0}, {1})" + " WHERE tar.Dst = {2} OR tar.Dst IN (SELECT Id FROM fnGetOwnedIds({2}, {3}, {4}))", cache.DefaultVernWs, cache.DefaultAnalWs, hvoEntry, (int)LexEntry.LexEntryTags.kflidSenses, (int)LexSense.LexSenseTags.kflidSenses); IOleDbCommand odc = DbOps.MakeRowSet(cache, sql1, null); bool fGotLexRef = false; // true if we found a lexical relation for the entry or one of its senses try { bool fMoreRows; List<int> rels = new List<int>(); for (odc.NextRow(out fMoreRows); fMoreRows; odc.NextRow(out fMoreRows)) { fGotLexRef = true; int hvoLexRef = DbOps.ReadInt(odc, 0); if (hvoLexRef == 0) continue; // null row. if (!((ISilDataAccess)cdaTemp).get_IsPropInCache(hvoLexRef, RelatedWordsVc.ktagName, (int)CellarModuleDefns.kcptString, 0)) { int type = DbOps.ReadInt(odc, 1); int ord = DbOps.ReadInt(odc, 2); ITsString tssName = DbOps.ReadTss2(odc, 3); ITsString tssRevName = DbOps.ReadTss2(odc, 5); if (type == (int)LexRefType.MappingTypes.kmtEntryAsymmetricPair || type == (int)LexRefType.MappingTypes.kmtEntryOrSenseAsymmetricPair || type == (int)LexRefType.MappingTypes.kmtSenseAsymmetricPair) { if (ord != 0 && tssRevName != null && tssRevName.Length > 0) tssName = tssRevName; } else if (type == (int)LexRefType.MappingTypes.kmtEntryTree || type == (int)LexRefType.MappingTypes.kmtEntryOrSenseTree || type == (int)LexRefType.MappingTypes.kmtSenseTree) { if (ord != 0 && tssRevName != null && tssRevName.Length > 0) tssName = tssRevName; } cdaTemp.CacheStringProp(hvoLexRef, RelatedWordsVc.ktagName, tssName); rels.Add(hvoLexRef); } } relsOut = DbOps.ListToIntArray(rels); } finally { DbOps.ShutdownODC(ref odc); } return fGotLexRef; }
/// <summary> /// This is the real guts of type-ahead. It is called by the client whenever a key is pressed. /// It returns true if it handled the key press, which it does if the current selection /// is in a type-ahead name property. /// </summary> /// <param name="ehelp"></param> /// <param name="e"></param> /// <param name="modifiers"></param> /// <param name="vwGraphics"></param> /// <returns></returns> public virtual bool OnKeyPress(EditingHelper ehelp, KeyPressEventArgs e, Keys modifiers, IVwGraphics vwGraphics) { IVwRootBox rootb = ehelp.Callbacks.EditedRootBox; if (rootb == null) // If we don't have a root box, can't do anything interesting. { return(false); } IVwSelection sel = rootb.Selection; if (sel == null) // nothing interesting to do without a selection, either. { return(false); } ITsString tssA, tssE; int ichA, ichE, hvoObjA, hvoObjE, tagA, tagE, ws; bool fAssocPrev; // Enhance JohnT: what we're really trying to do here is confirm that the selection is // all in one string property. We could readily have a method in the selection interface to tell us that. sel.TextSelInfo(false, out tssA, out ichA, out fAssocPrev, out hvoObjA, out tagA, out ws); if (tagA != m_taTagName) { return(false); // selection not anchored in a type-ahead name property. } sel.TextSelInfo(true, out tssE, out ichE, out fAssocPrev, out hvoObjE, out tagE, out ws); int cch = tssA.Length; // To do our type-ahead trick, both ends of the seleciton must be in the same string property. // Also, we want the selection to extend to the end of the name. // Enhance JohnT: poupu list may not depend on selection extending to end. if (tagE != m_taTagName || hvoObjE != hvoObjA || cch != tssE.Length || Math.Max(ichA, ichE) != cch) { return(false); // not going to attempt type-ahead behavior } // if the key pressed is a backspace or del, prevent smart completion, // otherwise we are likely to put back what the user deleted. // Review JohnT: do arrow keys come through here? What do we do if so? int charT = Convert.ToInt32(e.KeyChar); if (charT == (int)Keys.Back || charT == (int)Keys.Delete) { return(false); // normal key handling will just delete selection. // Review: should backspace delete one more? } // OK, we're in a type-ahead situation. First step is to let normal editing take place. ehelp.OnKeyPress(e, modifiers); e.Handled = true; // Now see what we have. Note that our old selection is no longer valid. sel = rootb.Selection; if (sel == null) { return(true); // can't be smart, but we already did the keypress. } int cvsli = sel.CLevels(false); // CLevels includes the string prop itself, but AllTextSelInfo does not need it. cvsli--; // Get selection information to determine where the user is typing. int ihvoObj; int tagTextProp; int cpropPrevious, ichAnchor, ichEnd, ihvoEnd; ITsTextProps ttp; SelLevInfo[] rgvsli = SelLevInfo.AllTextSelInfo(sel, cvsli, out ihvoObj, out tagTextProp, out cpropPrevious, out ichAnchor, out ichEnd, out ws, out fAssocPrev, out ihvoEnd, out ttp); if (tagTextProp != m_taTagName || ichAnchor != ichEnd || ihvoEnd != -1 || cvsli < 1) { return(true); // something bizarre happened, but keypress is done. } int hvoLeaf = rgvsli[0].hvo; // Get the parent object we will modify. // (This would usually work, but not if the parent object is the root of the whole display, // as in a simple atomic ref type ahead slice. //int hvoParent = rgvsli[1].hvo; // object whose reference property we are setting.) int tagParent, cpropPreviousDummy, ihvo; IVwPropertyStore vps; int hvoParent; sel.PropInfo(false, 1, out hvoParent, out tagParent, out ihvo, out cpropPreviousDummy, out vps); if (hvoParent != m_hvoParent) { return(true); // another bizarre unexpected event. } // This is what the name looks like after the keypress. ITsString tssTyped = m_sda.get_StringProp(hvoLeaf, m_taTagName); // Get the substitute. This is where the actual type-ahead behavior happens. Sets hvoNewRef to 0 if no match. ICmObject objNewRef; ITsString tssLookup = Lookup(tssTyped, out objNewRef); int hvoNewRef = (objNewRef != null) ? objNewRef.Hvo : 0; IVwCacheDa cda = m_sda as IVwCacheDa; if (hvoNewRef == 0 && tssTyped.Length > 0) { // No match...underline string in red squiggle. ITsStrBldr bldr = tssLookup.GetBldr(); bldr.SetIntPropValues(0, tssLookup.Length, (int)FwTextPropType.ktptUnderline, (int)FwTextPropVar.ktpvEnum, (int)FwUnderlineType.kuntSquiggle); bldr.SetIntPropValues(0, tssLookup.Length, (int)FwTextPropType.ktptUnderColor, (int)FwTextPropVar.ktpvDefault, (int)ColorUtil.ConvertColorToBGR(Color.Red)); tssLookup = bldr.GetString(); } // Don't rely on sel from here on. if (hvoNewRef != hvoLeaf) { m_hvoTa = hvoNewRef; // Before we replace in the prop, so it gets displayed using special ta prop. switch (m_type) { case CellarPropertyType.ReferenceAtomic: if (m_hvoParent != 0) // I think it always is, except when loss of focus during debugging causes problems. { // If nothing matched, set the real property to null and the fake one to kbaseFakeObj. // Otherwise set both to the indicated object. m_sda.SetObjProp(m_hvoParent, m_tag, hvoNewRef); // Review: do we want to set the real thing yet? m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvoParent, m_tag, 0, 1, 1); if (hvoNewRef == 0) { hvoNewRef = m_hvoTa = kBaseFakeObj; // use in fake so we can display something. } cda.CacheObjProp(m_hvoParent, m_virtualTagObj, hvoNewRef); // Change the fake property m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvoParent, m_virtualTagObj, 0, 1, 1); } break; case CellarPropertyType.ReferenceSequence: case CellarPropertyType.ReferenceCollection: // Several cases, depending on whether we got a match and whether hvoLeaf is the dummy object // 1. match on dummy: insert appropriate real object, change dummy name to empty. // 2. match on non-dummy: replace old object with new // 3: non-match: do nothing. (Even if not looking at the fake object, we'll go on using the // actual object as a base for the fake name, since it's displayed only for the active position.) if (hvoNewRef == 0) { break; // case 3 } if (hvoLeaf == kBaseFakeObj) { // case 1 // The fake object goes back to being an empty name at the end of the list. ITsStrBldr bldr = tssLookup.GetBldr(); bldr.ReplaceTsString(0, bldr.Length, null); // makes an empty string in correct ws. cda.CacheStringProp(kBaseFakeObj, m_taTagName, bldr.GetString()); // Insert the new object before the fake one in fake prop and at end of real seq. // Include the fake object in the replace to get it redisplayed also. cda.CacheReplace(m_hvoParent, m_virtualTagObj, m_ihvoTa, m_ihvoTa + 1, new int[] { hvoNewRef, kBaseFakeObj }, 2); m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvoParent, m_virtualTagObj, m_ihvoTa, 2, 1); m_sda.Replace(m_hvoParent, m_tag, m_ihvoTa, m_ihvoTa, new int[] { hvoNewRef }, 1); m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvoParent, m_tag, m_ihvoTa, 1, 0); } else { // case 2 // Replace the object being edited with the indicated one in both props. cda.CacheReplace(m_hvoParent, m_virtualTagObj, m_ihvoTa, m_ihvoTa + 1, new int[] { hvoNewRef }, 1); m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvoParent, m_virtualTagObj, m_ihvoTa, 1, 1); m_sda.Replace(m_hvoParent, m_tag, m_ihvoTa, m_ihvoTa + 1, new int[] { hvoNewRef }, 1); m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvoParent, m_tag, m_ihvoTa, 1, 1); } break; default: throw new Exception("unsupported property type for type-ahead chooser"); } } cda.CacheStringProp(hvoNewRef, m_taTagName, tssLookup); m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoNewRef, m_taTagName, 0, tssLookup.Length, tssTyped.Length); // Make a new selection, typically the range that is the bit added to the typed string. // no change is needed to rgvsli because it's the same object index in the same property of the same parent. sel = rootb.MakeTextSelection(ihvoObj, cvsli, rgvsli, m_taTagName, cpropPrevious, ichAnchor, tssLookup.Length, ws, true, -1, null, true); return(true); }
/// <summary> /// The value of this property is the outline number. /// </summary> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="ws"></param> /// <param name="cda"></param> public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { string outline = m_cache.GetOutlineNumber(hvo, m_flid, m_fFinalPeriod, m_fIncTopOwner); cda.CacheStringProp(hvo, tag, m_cache.MakeUserTss(outline)); }
/// <summary> /// Load the data. /// </summary> /// <param name="hvo">a Wfic.</param> /// <param name="tag"></param> /// <param name="ws"></param> /// <param name="cda"></param> public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { ISilDataAccess sda = cda as ISilDataAccess; int hvoPara = sda.get_ObjectProp(hvo, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginObject); int hvoStText = 0; if (hvoPara != 0) hvoStText = sda.get_ObjectProp(hvoPara, (int)CmObjectFields.kflidCmObject_Owner); if (hvoStText == 0) { // Unusual case, possibly hvoPara is not actually a para at all, for example, it may // be a picture caption. For now we make an empty reference so at least it won't crash. ITsStrFactory tsf = TsStrFactoryClass.Create(); ITsString dummy = tsf.MakeString("", ws); cda.CacheStringAlt(hvo, tag, ws, dummy); cda.CacheStringProp(hvo, tag, dummy); return; } ITsString tssName = null; StText stText = new StText(Cache, hvoStText); int wsActual = 0; bool fUsingAbbreviation = false; if (stText.OwningFlid == (int)Text.TextTags.kflidContents) { // see if we can find an abbreviation. Text text = stText.Owner as Text; tssName = text.Abbreviation.GetAlternativeOrBestTss(ws, out wsActual); if (wsActual > 0) fUsingAbbreviation = true; } else if (stText.OwningFlid == (int)ScrSection.ScrSectionTags.kflidContent) { // Body of Scripture. Figure a book/chapter/verse ScrTxtPara scrPara = new ScrTxtPara(m_cache, hvoPara, false, false); ScrBook book = new ScrBook(m_cache, Cache.GetOwnerOfObject(Cache.GetOwnerOfObject(stText.Hvo))); string mainRef = FullScrRef(scrPara, hvo, book.BestUIAbbrev).Trim(); int ktagParaSegments = StTxtPara.SegmentsFlid(Cache); int beginOffset = Cache.GetIntProperty(hvo, (int) CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginOffset); int chvo = sda.get_VecSize(hvoPara, ktagParaSegments); int idxSeg = 0; while (idxSeg < chvo - 1) { // Stop if the FOLLOWING segment has a larger beginOffset than the target one. int hvoSeg = sda.get_VecItem(hvoPara, ktagParaSegments, idxSeg + 1); int segBeginOffset = sda.get_IntProp(hvoSeg, (int) CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginOffset); if (segBeginOffset > beginOffset) break; idxSeg++; } ITsString tssRef1 = Cache.MakeUserTss(mainRef + VerseSegLabel(scrPara, idxSeg, ktagParaSegments)); cda.CacheStringProp(hvo, tag, tssRef1); cda.CacheStringAlt(hvo, tag, m_cache.DefaultUserWs, tssRef1); return; } else if (stText.OwningFlid == (int)ScrSection.ScrSectionTags.kflidHeading) { // use the section title without qualifiers. ITsString tssRef2 = stText.Title.GetAlternativeOrBestTss(ws, out wsActual); cda.CacheStringProp(hvo, tag, tssRef2); cda.CacheStringAlt(hvo, tag, wsActual, tssRef2); return; } if (wsActual == 0) { tssName = stText.Title.GetAlternativeOrBestTss(ws, out wsActual); } // if we didn't find an alternative, we'll just revert to using the 'ws' we're loading for. string sNotFound = null; if (wsActual == 0) { wsActual = ws; sNotFound = tssName.Text; } ITsStrBldr bldr = tssName.GetBldr(); // If we didn't find a "best", reset to an empty string. if (bldr.Length > 0 && bldr.Text == sNotFound) bldr.ReplaceTsString(0, bldr.Length, null); // Truncate to 8 chars, if the user hasn't specified an abbreviation. // Enhance JohnT: Eventually Text will have an abbreviation property, and we will do the // truncate title thing only if abbreviation is empty. if (!fUsingAbbreviation && bldr.Length > 8) bldr.ReplaceTsString(8, bldr.Length, null); // Make a TsTextProps specifying just the writing system. ITsPropsBldr propBldr = TsPropsBldrClass.Create(); propBldr.SetIntPropValues((int)FwTextPropType.ktptWs, (int)FwTextPropVar.ktpvDefault, wsActual); ITsTextProps props = propBldr.GetTextProps(); // Insert a space (if there was any title) if (bldr.Length > 0) bldr.Replace(bldr.Length, bldr.Length, " ", props); // if Scripture.IsResponsibleFor(stText) we should try to get the verse number of the annotation. //if (stText.OwningFlid == (int)Text.TextTags.kflidContents) //{ // Insert paragraph number. int cparas = sda.get_VecSize(hvoStText, (int)StText.StTextTags.kflidParagraphs); int ipara = 0; for (; sda.get_VecItem(hvoStText, (int)StText.StTextTags.kflidParagraphs, ipara) != hvoPara; ipara++) ; ipara++; bldr.Replace(bldr.Length, bldr.Length, ipara.ToString(), props); // And a colon... bldr.Replace(bldr.Length, bldr.Length, ":", props); // And now the segment number string segnumStr = GetSegmentRange(hvo); bldr.Replace(bldr.Length, bldr.Length, segnumStr, props); //} ITsString tssRef = bldr.GetString(); cda.CacheStringAlt(hvo, tag, wsActual, tssRef); cda.CacheStringProp(hvo, tag, tssRef); }
public void MakeStringProp(int hvo, XmlNode node, string attrName, int tag, int ws, ITsStrFactory tsf, IVwCacheDa cda) { string val = GetAttrVal(node, attrName); if (val == null) return; cda.CacheStringProp(hvo, tag, tsf.MakeString(val, ws)); }
/// <summary> /// Load the information about the lexical relations that link to hvoEntry. /// </summary> /// <param name="cache"></param> /// <param name="hvoEntry"></param> /// <param name="relsOut"></param> /// <param name="cdaTemp"></param> /// <param name="owner"></param> /// <returns>false if the entry has no associated lexical relations, or none of them are linked to any other entries.</returns> static private bool LoadLexicalRelationInfo(FdoCache cache, int hvoEntry, out int[] relsOut, IVwCacheDa cdaTemp, IWin32Window owner) { string sql1 = string.Format("SELECT DISTINCT tar2.Src, lrt.MappingType, tar.Ord, cn.Txt, cn.Ws, rev.Txt, rev.Ws" + " FROM LexReference_Targets tar" + " LEFT OUTER JOIN LexReference_Targets tar2 ON tar2.Src=tar.Src AND EXISTS (SELECT * FROM CmObject other WHERE other.Id=tar2.Dst AND other.Id != tar.Dst)" + " LEFT OUTER JOIN LexRefType_Members mem ON mem.Dst=tar2.Src" + " LEFT OUTER JOIN LexRefType lrt ON lrt.Id=mem.Src" + " LEFT OUTER JOIN CmPossibility_Name cn ON cn.Obj=mem.Src AND cn.Ws IN ({0}, {1})" + " LEFT OUTER JOIN LexRefType_ReverseName rev ON rev.Obj=mem.Src AND rev.Ws IN ({0}, {1})" + " WHERE tar.Dst = {2} OR tar.Dst IN (SELECT Id FROM fnGetOwnedIds({2}, {3}, {4}))", cache.DefaultVernWs, cache.DefaultAnalWs, hvoEntry, (int)LexEntry.LexEntryTags.kflidSenses, (int)LexSense.LexSenseTags.kflidSenses); IOleDbCommand odc = DbOps.MakeRowSet(cache, sql1, null); bool fGotLexRef = false; // true if we found a lexical relation for the entry or one of its senses try { bool fMoreRows; List <int> rels = new List <int>(); for (odc.NextRow(out fMoreRows); fMoreRows; odc.NextRow(out fMoreRows)) { fGotLexRef = true; int hvoLexRef = DbOps.ReadInt(odc, 0); if (hvoLexRef == 0) { continue; // null row. } if (!((ISilDataAccess)cdaTemp).get_IsPropInCache(hvoLexRef, RelatedWordsVc.ktagName, (int)CellarModuleDefns.kcptString, 0)) { int type = DbOps.ReadInt(odc, 1); int ord = DbOps.ReadInt(odc, 2); ITsString tssName = DbOps.ReadTss2(odc, 3); ITsString tssRevName = DbOps.ReadTss2(odc, 5); if (type == (int)LexRefType.MappingTypes.kmtEntryAsymmetricPair || type == (int)LexRefType.MappingTypes.kmtEntryOrSenseAsymmetricPair || type == (int)LexRefType.MappingTypes.kmtSenseAsymmetricPair) { if (ord != 0 && tssRevName != null && tssRevName.Length > 0) { tssName = tssRevName; } } else if (type == (int)LexRefType.MappingTypes.kmtEntryTree || type == (int)LexRefType.MappingTypes.kmtEntryOrSenseTree || type == (int)LexRefType.MappingTypes.kmtSenseTree) { if (ord != 0 && tssRevName != null && tssRevName.Length > 0) { tssName = tssRevName; } } cdaTemp.CacheStringProp(hvoLexRef, RelatedWordsVc.ktagName, tssName); rels.Add(hvoLexRef); } } relsOut = DbOps.ListToIntArray(rels); } finally { DbOps.ShutdownODC(ref odc); } return(fGotLexRef); }
/// <summary> /// Load the information about the domains of hvoEntry. Returns false /// if the entry has no associated domains or none of them are linked to any other entries. /// </summary> /// <param name="cache"></param> /// <param name="hvoEntry"></param> /// <param name="domains"></param> /// <param name="cdaTemp"></param> /// <param name="fMoreRows"></param> /// <param name="owner"></param> /// <returns></returns> static private bool LoadDomainInfo(FdoCache cache, int hvoEntry, out int[] domainsOut, out IVwCacheDa cdaTemp, IWin32Window owner) { // This produces first the Semantic domains of the senses of the entry, // then restricts to those that occur on some other entry, // then looks up the vernacular (or, if none, analysis) name of the domains. The are sorted by // domain name. // We do left outer joins for the last two so we can distinguish the failure // modes "no SDs on senses of initial entry" versus "no other entries in those SDs" string sql1 = string.Format("select lssd2.dst, cn.txt, cn.ws from LexEntry le" + " join LexSense_ ls on ls.owner$ = le.id" + " join LexSense_SemanticDomains lssd on lssd.src = ls.id " + " left outer join LexSense_SemanticDomains lssd2 on lssd2.dst = lssd.dst" + " and exists (select * from CmObject lsother" + " join LexEntry leother on leother.id = lsother.owner$ and lsother.id = lssd2.src and leother.id != le.id)" + " left outer join CmPossibility_Name cn on lssd2.dst = cn.obj and cn.ws" + " in ({0}, {1}) where le.id = {2}" + " group by lssd2.dst, cn.txt, cn.ws" + " order by cn.txt", cache.DefaultVernWs, cache.DefaultAnalWs, hvoEntry); IOleDbCommand odc = DbOps.MakeRowSet(cache, sql1, null); bool fGotSrcDomain = false; // true if we found a semantic domain on some sense of the source entry try { bool fMoreRows; List<int> domains = new List<int>(); cdaTemp = VwCacheDaClass.Create(); for (odc.NextRow(out fMoreRows); fMoreRows; odc.NextRow(out fMoreRows)) { fGotSrcDomain = true; // any row indicates success here. int hvoDomain = DbOps.ReadInt(odc, 0); if (hvoDomain == 0) continue; // null row, an SD that occurs on no other entry. if (!((ISilDataAccess)cdaTemp).get_IsPropInCache(hvoDomain, RelatedWordsVc.ktagName, (int)CellarModuleDefns.kcptString, 0)) { ITsString tss = DbOps.ReadTss2(odc, 1); if (tss == null) { tss = FDO.Cellar.CmPossibility.BestAnalysisOrVernName(cache, hvoDomain); } cdaTemp.CacheStringProp(hvoDomain, RelatedWordsVc.ktagName, tss); domains.Add(hvoDomain); } } domainsOut = DbOps.ListToIntArray(domains); } finally { DbOps.ShutdownODC(ref odc); } return fGotSrcDomain; }