/// ------------------------------------------------------------------------------------ /// <summary> /// Loads the footnotes. /// </summary> /// <param name="footnoteHvo">The footnote hvo.</param> /// ------------------------------------------------------------------------------------ private void LoadFootnotes(int footnoteHvo) { Debug.Assert(m_cache.GetClassOfObject(footnoteHvo) == StFootnote.kClassId); StFootnote foot = new StFootnote(m_cache, footnoteHvo); IScrBook book = new ScrBook(m_cache, foot.OwnerHVO); int footnoteCount = GetBookFootnoteCount(book.Hvo); FdoOwningSequence <IStFootnote> footnotes = book.FootnotesOS; // If the information we want is already in the cache, then do nothing if (footnotes.Count == footnoteCount && m_htFootnoteIndex.ContainsKey(footnoteHvo)) { return; } ScrFootnote footnote = null; int index = 0; for (int i = 0; i < footnotes.Count; i++) { footnote = new ScrFootnote(m_cache, footnotes.HvoArray[i]); if (footnote.FootnoteType == FootnoteMarkerTypes.AutoFootnoteMarker) { int oldIndex = GetFootnoteIndex(footnote.Hvo); if (oldIndex != index) { m_htFootnoteIndex[footnote.Hvo] = new FootnoteIndexCacheInfo(index, true); } index++; } } m_htBookFootnoteCount[book.Hvo] = footnotes.Count; }
/// <summary> /// a factory method for creating the correct type of object label, depending on the /// class of the object /// </summary> static public ObjectLabel CreateObjectLabel(FdoCache cache, int hvo, string displayNameProperty, string displayWs) { if (hvo == 0) { return(new NullObjectLabel(cache)); } else { //enhance: this is very expensive currently, it loads the entire object. // does it? it's not obvious to the casual observer... uint classId = (uint)cache.GetClassOfObject(hvo); uint baseClassId = 0; if (classId == CmPossibility.kClassId) { baseClassId = classId; // not exactly true, but simplifies logic below. } else { baseClassId = cache.MetaDataCacheAccessor.GetBaseClsId(classId); } if (CmPossibility.kClassId == baseClassId) { return(new CmPossibilityLabel(cache, hvo, displayNameProperty, displayWs)); } else if (MoInflClass.kClassId == classId) { return(new MoInflClassLabel(cache, hvo, displayNameProperty, displayWs)); } else { return(new ObjectLabel(cache, hvo, displayNameProperty, displayWs)); } } }
/// <summary> /// Create the ordered vector of writing sytems to try for displaying names. /// </summary> protected void EstablishWritingSystemsToTry(string sDisplayWs) { if (m_cache == null || m_writingSystemIds != null) { return; } if (sDisplayWs == null || sDisplayWs == String.Empty) { sDisplayWs = "analysis vernacular"; // very general default. } int flid = 0; if (!string.IsNullOrEmpty(m_displayNameProperty)) { string className = m_cache.GetClassName((uint)m_cache.GetClassOfObject(Hvo)); IVwVirtualHandler vh = m_cache.VwCacheDaAccessor.GetVirtualHandlerName(className, m_displayNameProperty); if (vh != null) { flid = vh.Tag; } } m_writingSystemIds = LangProject.GetWritingSystemIdsFromLabel(m_cache, sDisplayWs, m_cache.DefaultUserWs, m_hvo, flid, null); }
/// <summary> /// Get a wordform from an HVO that may be a WfiWordform, WfiAnalysis, or WfiGloss (or 0). /// Answer 0 if arguent is zero, fail if it is some other class. /// </summary> public static int GetWordformFromWag(FdoCache cache, int cbaInstanceOf) { int hvoWordform = 0; if (cbaInstanceOf != 0) { int classid = cache.GetClassOfObject(cbaInstanceOf); switch (classid) { case WfiWordform.kclsidWfiWordform: hvoWordform = cbaInstanceOf; break; case WfiAnalysis.kclsidWfiAnalysis: hvoWordform = cache.GetOwnerOfObject(cbaInstanceOf); break; case WfiGloss.kclsidWfiGloss: int hvoAnalysis = cache.GetOwnerOfObject(cbaInstanceOf); hvoWordform = cache.GetOwnerOfObject(hvoAnalysis); break; default: Debug.Fail("Actual cba (" + cbaInstanceOf + "): Class of InstanceOf (" + classid + ") is not WfiWordform, WfiAnalysis, or WfiGloss."); break; } } return hvoWordform; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Refreshes cache for all footnotes in the StText containing the paragraph. We only /// use this method when verses of a paragraph are changed - this will only happen on /// content paragraphs of a ScrSection. /// </summary> /// <param name="cache"></param> /// <param name="hvoObj"></param> /// ------------------------------------------------------------------------------------ internal static void RefreshCacheForParagraph(FdoCache cache, int hvoObj) { int hvoPara = hvoObj; if (cache.GetClassOfObject(hvoObj) == CmTranslation.kClassId) hvoPara = cache.GetOwnerOfObject(hvoObj); int hvoText = cache.GetOwnerOfObject(hvoPara); IStText text = new StText(cache, hvoText); ScrSection section = new ScrSection(cache, text.OwnerHVO); BCVRef verseRef = new BCVRef(section.VerseRefStart); Dictionary<int, FootnoteHashEntry> dict; // Don't bother on empty cache - it will be created when needed. Need to use HVO to get GUID so we // don't create the book and potentially cause the refresh routine to be called. Guid bookGuid = cache.GetGuidFromId(section.OwnerHVO); if (!cache.TryGetHashtable<int, FootnoteHashEntry>(bookGuid, out dict) || dict.Count == 0) { return; } AddFootnoteRefsInText(text, dict, ref verseRef); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets footnote hvo from reference in text properties /// </summary> /// <param name="cache"></param> /// <param name="tprops"></param> /// <returns>Hvo of the footnote that was found or 0 if none was found</returns> /// ------------------------------------------------------------------------------------ protected static int GetFootnoteFromProps(FdoCache cache, ITsTextProps tprops) { string footnoteRef = tprops.GetStrPropValue((int)FwTextPropType.ktptObjData); if (footnoteRef != null) { // first char. of strData is type code - GUID will follow it. Guid objGuid = MiscUtils.GetGuidFromObjData(footnoteRef.Substring(1)); int hvo = cache.GetIdFromGuid(objGuid); if (hvo > 0 && cache.GetClassOfObject(hvo) == StFootnote.kClassId) return hvo; } return 0; }
/// <summary> /// a factory method for creating the correct type of object label, depending on the /// class of the object /// </summary> static public ObjectLabel CreateObjectLabel(FdoCache cache, int hvo, string displayNameProperty, string displayWs) { if (hvo == 0) { return new NullObjectLabel(cache); } else { //enhance: this is very expensive currently, it loads the entire object. // does it? it's not obvious to the casual observer... uint classId = (uint)cache.GetClassOfObject(hvo); uint baseClassId = 0; if (classId == CmPossibility.kClassId) baseClassId = classId; // not exactly true, but simplifies logic below. else baseClassId = cache.MetaDataCacheAccessor.GetBaseClsId(classId); if (CmPossibility.kClassId == baseClassId) return new CmPossibilityLabel(cache, hvo, displayNameProperty, displayWs); else if (MoInflClass.kClassId == classId) return new MoInflClassLabel(cache, hvo, displayNameProperty, displayWs); else return new ObjectLabel(cache, hvo, displayNameProperty, displayWs); } }
/// <summary> /// /// </summary> /// <param name="fdoCache"></param> /// <param name="dummyAnnHvo"></param> /// <returns></returns> public static ICmBaseAnnotation ConvertBaseAnnotationToReal(FdoCache fdoCache, int dummyAnnHvo) { using (SuppressSubTasks supressActionHandler = new SuppressSubTasks(fdoCache, true)) { Debug.Assert(fdoCache.IsDummyObject(dummyAnnHvo)); if (!fdoCache.IsDummyObject(dummyAnnHvo) || fdoCache.GetClassOfObject(dummyAnnHvo) != CmBaseAnnotation.kclsidCmBaseAnnotation) { return null; // indicate no change. } ISilDataAccess sda = fdoCache.MainCacheAccessor; ICmBaseAnnotation cbaDummy = (ICmBaseAnnotation)CmObject.CreateFromDBObject(fdoCache, dummyAnnHvo, false); ICmBaseAnnotation cbaReal = CreateRealAnnotation(fdoCache, cbaDummy.AnnotationTypeRAHvo, cbaDummy.InstanceOfRAHvo, cbaDummy.BeginObjectRAHvo, cbaDummy.Flid, cbaDummy.BeginOffset, cbaDummy.EndOffset); cbaReal.WritingSystemRAHvo = cbaDummy.WritingSystemRAHvo; int hvoRealAnn = cbaReal.Hvo; // transfer any default analysis (guess) int ktagTwficDefault = StTxtPara.TwficDefaultFlid(fdoCache); int hvoTwficAnalysisGuess = fdoCache.GetObjProperty(dummyAnnHvo, ktagTwficDefault); if (hvoTwficAnalysisGuess != 0) { fdoCache.VwCacheDaAccessor.CacheObjProp(hvoRealAnn, ktagTwficDefault, hvoTwficAnalysisGuess); } int textSegType = CmAnnotationDefn.TextSegment(fdoCache).Hvo; int twficType = CmAnnotationDefn.Twfic(fdoCache).Hvo; if (cbaDummy.AnnotationTypeRAHvo == twficType) StTxtPara.CacheReplaceTWFICAnnotation(fdoCache, dummyAnnHvo, hvoRealAnn); else if (cbaDummy.AnnotationTypeRAHvo == textSegType) StTxtPara.CacheReplaceTextSegmentAnnotation(fdoCache, dummyAnnHvo, hvoRealAnn); else Debug.Assert(true, "CacheReplace does not yet support annotation type " + cbaDummy.AnnotationTypeRAHvo); // now clear it from the cache, since we're done with it. if (fdoCache.ActionHandlerAccessor != null) fdoCache.ActionHandlerAccessor.AddAction(new ClearInfoOnCommitUndoAction(fdoCache, dummyAnnHvo)); return cbaReal; } }
/// <summary> /// If hvoEntry is the id of a variant, try to find an entry it's a variant of that /// has a sense. Return the corresponding ILexEntryRef for the first such entry. /// If this is being called to establish a default monomorphemic guess, skip over /// any bound root or bound stem entries that hvoEntry may be a variant of. /// </summary> public static ILexEntryRef GetVariantRef(FdoCache cache, int hvoEntry, bool fMonoMorphemic) { ISilDataAccess sda = cache.MainCacheAccessor; int cRef = sda.get_VecSize(hvoEntry, (int)LexEntry.LexEntryTags.kflidEntryRefs); for (int i = 0; i < cRef; ++i) { int hvoRef = sda.get_VecItem(hvoEntry, (int)LexEntry.LexEntryTags.kflidEntryRefs, i); int refType = sda.get_IntProp(hvoRef, (int)LexEntryRef.LexEntryRefTags.kflidRefType); if (refType == LexEntryRef.krtVariant) { int cEntries = sda.get_VecSize(hvoRef, (int)LexEntryRef.LexEntryRefTags.kflidComponentLexemes); if (cEntries != 1) continue; int hvoComponent = sda.get_VecItem(hvoRef, (int)LexEntryRef.LexEntryRefTags.kflidComponentLexemes, 0); int clid = cache.GetClassOfObject(hvoComponent); if (fMonoMorphemic && IsEntryBound(cache, hvoComponent, clid)) continue; if (clid == LexSense.kclsidLexSense || sda.get_VecSize(hvoComponent, (int)LexEntry.LexEntryTags.kflidSenses) > 0) { return LexEntryRef.CreateFromDBObject(cache, hvoRef); } else { // Should we check for a variant of a variant of a ...? } } } return null; // nothing useful we can do. }
/// <summary> /// Get the writing system for the given ReversalIndexEntry. /// </summary> /// <param name="cache"></param> /// <param name="hvoObj"></param> /// <param name="wsDefault"></param> /// <returns></returns> public static int GetReversalIndexEntryWritingSystem(FdoCache cache, int hvoObj, int wsDefault) { if (cache != null && hvoObj != 0) { IReversalIndex ri = null; int clid = cache.GetClassOfObject(hvoObj); switch (clid) { case ReversalIndex.kclsidReversalIndex: ri = ReversalIndex.CreateFromDBObject(cache, hvoObj); break; case ReversalIndexEntry.kclsidReversalIndexEntry: int hvoReversalIndex = cache.GetOwnerOfObjectOfClass(hvoObj, ReversalIndex.kclsidReversalIndex); if (hvoReversalIndex > 0) ri = ReversalIndex.CreateFromDBObject(cache, hvoReversalIndex); break; case PartOfSpeech.kclsidPartOfSpeech: // It may be nested, but we need the owner (index) of the list, // no matter how high up. int reversalIndexId = cache.GetOwnerOfObjectOfClass(hvoObj, ReversalIndex.kclsidReversalIndex); if (reversalIndexId > 0) ri = ReversalIndex.CreateFromDBObject(cache, reversalIndexId); break; case LexSense.kclsidLexSense: // Pick a plausible default reversal index for the LexSense. case LexDb.kclsidLexDb: // happens while initializing bulk edit combos default: // since this doesn't actually depend on the hvo, it's not a bad general default. List<int> rgriCurrent = cache.LangProject.LexDbOA.CurrentReversalIndices; if (rgriCurrent.Count > 0) { ri = ReversalIndex.CreateFromDBObject(cache, (int)rgriCurrent[0]); } else { if (cache.LangProject.LexDbOA.ReversalIndexesOC.Count > 0) { int hvo = cache.LangProject.LexDbOA.ReversalIndexesOC.HvoArray[0]; ri = (IReversalIndex)CmObject.CreateFromDBObject(cache, hvo); } } break; } if (ri != null) return ri.WritingSystemRAHvo; } return wsDefault; }
public static int GetParentOfClass(FdoCache m_cache, int hvo, int classIdOfParentToSearchFor) { //save the caller the need to see if this property was empty or not if(hvo <1) return -1; int classId = m_cache.GetClassOfObject(hvo) ; while((!m_cache.IsSameOrSubclassOf(classId,classIdOfParentToSearchFor)) && (classId != FDO.LangProj.LangProject.kClassId)) { hvo = m_cache.GetOwnerOfObject(hvo); classId = m_cache.GetClassOfObject(hvo) ; } if((!m_cache.IsSameOrSubclassOf(classId,classIdOfParentToSearchFor))) return -1; else return hvo; }
/// <summary> /// In many cases we don't really need the FDO object, which can be relatively expensive /// to create. This version saves the information, and creates it when needed. /// </summary> /// <param name="cache"></param> /// <param name="hvo"></param> /// <returns></returns> public static CmObjectUi MakeUi(FdoCache cache, int hvo) { return MakeUi(cache, hvo, (uint)cache.GetClassOfObject(hvo)); }
/// ------------------------------------------------------------------------------------ /// <summary> /// This variant looks up the type, but never checks validity, and allows control of whether /// to load into cache. /// </summary> /// <param name="fcCache"></param> /// <param name="hvo"></param> /// <param name="bLoadIntoCache"></param> /// <returns></returns> /// ------------------------------------------------------------------------------------ public static ICmObject CreateFromDBObject(FdoCache fcCache, int hvo, bool bLoadIntoCache) { return CreateFromDBObject(fcCache, hvo, GetTypeFromFWClassID(fcCache, fcCache.GetClassOfObject(hvo)), false, // don't validity check bLoadIntoCache); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Instantiate an object of the correct type, given the hvo. /// </summary> /// <remarks> /// Needed when the signature of the property is CmObject (and the actual class of the /// object is unknown). /// Notice that, even though the return signature of this method is CmObject, it /// will actually be returning an object of either CmObject or one of its subclasses. /// Note that in debug builds, this will include a validity check on the object. If you want /// a validity check during a release build, use the version of this method which /// includes a parameter to control this explicitly. /// </remarks> /// <param name="fcCache"></param> /// <param name="hvo"></param> /// <returns></returns> /// ------------------------------------------------------------------------------------ public static ICmObject CreateFromDBObject(FdoCache fcCache,int hvo) { Type cSharpType = GetTypeFromFWClassID(fcCache, fcCache.GetClassOfObject(hvo)); // Now construct the object // If the object's class is already cached, assume all the FDO preload data is too. // Occasionally we will get a miss, where the class has been loaded some other way, // but we will auto-load the properties actually used in that case, and on the other // hand we save a huge amount of time not reloading objects we've already loaded. bool fLoadIntoCache = !fcCache.MainCacheAccessor.get_IsPropInCache(hvo, (int)CmObjectFields.kflidCmObject_Class, (int)CellarModuleDefns.kcptInteger, 0); return CreateFromDBObject(fcCache, hvo, cSharpType, //#if DEBUG // true/*validity check*/, //#else false, //#endif fLoadIntoCache); }
/// <summary> /// Uses CmObject base class to determine validity, since /// subclasses can override IsValidObject() to use different validation logic. /// </summary> /// <param name="cache"></param> /// <param name="hvo"></param> /// <returns></returns> static public bool IsValidObject(FdoCache cache, int hvo) { if (hvo == 0) return false; int clsid = cache.GetClassOfObject(hvo); if (clsid == 0) return false; ICmObject co = CmObject.CreateFromDBObject(cache, hvo, GetTypeFromFWClassID(cache, clsid), false, false); return co.IsValidObject(); }
static internal int InsertObjectIntoVirtualBackref(FdoCache cache, Mediator mediator, IVwVirtualHandler vh, int hvoSlice, uint clidNewObj, uint clidOwner, uint flid) { if (vh != null) { int clidSlice = cache.GetClassOfObject(hvoSlice); if (clidNewObj == LexEntry.kclsidLexEntry && clidSlice == LexEntry.kclsidLexEntry && clidOwner == LexDb.kclsidLexDb) { if (vh.FieldName == "VariantFormEntryBackRefs") { using (InsertVariantDlg dlg = new InsertVariantDlg()) { ILexEntry entOld = LexEntry.CreateFromDBObject(cache, hvoSlice); dlg.SetHelpTopic("khtpInsertVariantDlg"); dlg.SetDlgInfo(cache, mediator, entOld as IVariantComponentLexeme); if (dlg.ShowDialog() == DialogResult.OK && dlg.NewlyCreatedVariantEntryRefResult) { int insertPos = cache.GetVectorSize(hvoSlice, (int)flid); cache.PropChanged(hvoSlice, (int)flid, insertPos, 1, 0); return insertPos; } // say we've handled this. return -2; } } } } return -1; }
/// <summary> /// If hvoWordform is the hvo of a capitalized wordform which has no useful information, /// delete it. It is considered useless if /// - it has no occurrences /// - it has no anlyses /// - it doesn't have known incorrect spelling status. /// Note that the argument may be some other kind of object (typically a WfiAnalysis or WfiGloss). /// If so do nothing. /// </summary> public static void DeleteRedundantCapitalizedWordform(FdoCache cache, int hvoWordform) { if (cache.GetClassOfObject(hvoWordform) != WfiWordform.kclsidWfiWordform) return; if (cache.GetVectorProperty(hvoWordform, OccurrencesFlid(cache), true).Length != 0) return; if (cache.IsValidObject(hvoWordform)) { // If it's real it might have analyses etc. WfiWordform wf = (WfiWordform) CmObject.CreateFromDBObject(cache, hvoWordform); if (wf.AnalysesOC.Count > 0) return; // Arguably we should keep it for known correct spelling status. However, if it's ever been // confirmed as an analysis, even temporarily, it will have that. if (wf.SpellingStatus == (int)SpellingStatusStates.incorrect) return; } foreach (int ws in cache.LangProject.CurVernWssRS.HvoArray) { CaseFunctions cf = new CaseFunctions(cache.LanguageWritingSystemFactoryAccessor.get_EngineOrNull(ws).IcuLocale); string text = cache.GetMultiStringAlt(hvoWordform, (int) WfiWordformTags.kflidForm, ws).Text; if (!String.IsNullOrEmpty(text) && cf.StringCase(text) == StringCaseStatus.allLower) return; } cache.DeleteObject(hvoWordform); }
private static int GetWfiAnalysisFromWficInstanceOf(FdoCache cache, int hvoInstanceOf, out int hvoWordform) { hvoWordform = 0; int hvoWfiAnalysis = 0; int classid = cache.GetClassOfObject(hvoInstanceOf); switch (classid) { case WfiWordform.kclsidWfiWordform: hvoWordform = hvoInstanceOf; return 0; // need use or make a guess for analysis case WfiAnalysis.kclsidWfiAnalysis: hvoWfiAnalysis = hvoInstanceOf; break; case WfiGloss.kclsidWfiGloss: hvoWfiAnalysis = cache.GetOwnerOfObject(hvoInstanceOf); break; default: throw new ArgumentException("cba.InstanceOf(" + hvoInstanceOf + ") class(" + classid + ") is not WfiWordform, WfiAnalysis, or WfiGloss."); } return hvoWfiAnalysis; }
// Is hvoAnn, currently analyzed as hvoAnalysis, fully analyzed? // This means: // -- it isn't a default (property InterlinVc.m_vc.ktagTwficDefault isn't cached) // -- It's a WfiGloss, with non-empty form. // -- Owner is a WfiAnalysis with non-empty Category. // -- Owner has at least one WfiMorphBundle. // -- For each WfiMorphBundle, Form, Msa, and Sense are all filled in. // Alternatively, if hvoAnalysis is zero, the annotation is punctuation, which we don't analyze further; // so return true to indicate that it needs no further attention. internal bool FullyAnalyzed(FdoCache fdoCache, WsListManager listman, int hvoAnn, int hvoAnalysis) { int ktagTwficDefault = StTxtPara.TwficDefaultFlid(fdoCache); if (hvoAnalysis == 0) return true; // punctuation, treat as fully analyzed. ISilDataAccess sda = fdoCache.MainCacheAccessor; // Check for default. If the analysis we're showing is a default it needs at least confirmation. if (sda.get_IsPropInCache(hvoAnn, ktagTwficDefault, (int)CellarModuleDefns.kcptReferenceAtom, 0) && sda.get_ObjectProp(hvoAnn, ktagTwficDefault) != 0) return false; int analysisClass = fdoCache.GetClassOfObject(hvoAnalysis); if (analysisClass != (int)WfiGloss.kclsidWfiGloss && analysisClass != (int)WfiAnalysis.kclsidWfiAnalysis) return false; // Has to BE an analysis...unless pathologically everything is off? Too bad if so... int hvoWfiAnalysis = fdoCache.GetOwnerOfObject(hvoAnalysis); int hvoWordform; if (analysisClass == (int)WfiAnalysis.kclsidWfiAnalysis) { hvoWordform = hvoWfiAnalysis; hvoWfiAnalysis = hvoAnalysis; } else { hvoWordform = fdoCache.GetOwnerOfObject(hvoWfiAnalysis); } foreach (InterlinLineSpec spec in m_vc.LineChoices) { // see if the information required for this linespec is present. switch (spec.Flid) { case InterlinLineChoices.kflidWord: int ws = m_vc.GetRealWs(hvoWordform, spec); if (sda.get_MultiStringAlt(hvoWordform, (int)WfiWordform.WfiWordformTags.kflidForm, ws).Length == 0) return false; break; case InterlinLineChoices.kflidLexEntries: if (!CheckPropSetForAllMorphs(sda, hvoWfiAnalysis, (int)WfiMorphBundle.WfiMorphBundleTags.kflidMorph)) return false; break; case InterlinLineChoices.kflidMorphemes: if (!CheckPropSetForAllMorphs(sda, hvoWfiAnalysis, (int)WfiMorphBundle.WfiMorphBundleTags.kflidMorph)) return false; break; case InterlinLineChoices.kflidLexGloss: if (!CheckPropSetForAllMorphs(sda, hvoWfiAnalysis, (int)WfiMorphBundle.WfiMorphBundleTags.kflidSense)) return false; break; case InterlinLineChoices.kflidLexPos: if (!CheckPropSetForAllMorphs(sda, hvoWfiAnalysis, (int)WfiMorphBundle.WfiMorphBundleTags.kflidMsa)) return false; break; case InterlinLineChoices.kflidWordGloss: // If it isn't a WfiGloss the user needs a chance to supply a word gloss. if (analysisClass != WfiGloss.kclsidWfiGloss) return false; // If it is empty for the (possibly magic) ws specified here, it needs filling in. int ws1 = m_vc.GetRealWs(hvoAnalysis, spec); if (sda.get_MultiStringAlt(hvoAnalysis, (int)WfiGloss.WfiGlossTags.kflidForm, ws1).Length == 0) return false; break; case InterlinLineChoices.kflidWordPos: if (sda.get_ObjectProp(hvoWfiAnalysis, (int)WfiAnalysis.WfiAnalysisTags.kflidCategory) == 0) return false; break; case InterlinLineChoices.kflidFreeTrans: case InterlinLineChoices.kflidLitTrans: case InterlinLineChoices.kflidNote: default: // unrecognized or non-word-level annotation, nothing required. break; } } return true; // If we can't find anything to complain about, it's fully analyzed. }
const int ktagMinVp = 0x7f000000; // copied from VwCacheDa.h, mimimum value for assigned virtual props. /// <summary> /// We implement this to record modify times. /// </summary> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="ivMin"></param> /// <param name="cvIns"></param> /// <param name="cvDel"></param> public void PropChanged(int hvo, int tag, int ivMin, int cvIns, int cvDel) { CheckDisposed(); if (m_fModifyChangeInProgress) // ignore PropChanged on the DateModified property! { return; } // Typically an Undo will restore the modify time to what it was before the // main change. We don't want to reverse that by recording the time of the Undo! // Note that there is one pathological scenario: // t1: make a change. // t2: undo the change. // t3: export all changed records (since before t1). // t4: redo the change. Record appears to have been modified at time t2. // t5: export all changed records (since t3). // If this was the only change to the record, it is not part of either export, // and the change might be lost. // To prevent this, I think the 'export changed records' function should clear // the Undo stack. if (m_cache.ActionHandlerAccessor != null && m_cache.ActionHandlerAccessor.IsUndoOrRedoInProgress) { return; } if (tag < 0 || tag >= ktagMinVp) { return; // phony or virtual properties, not real changes (e.g., different filter applied, or selection moving in browse). } try { DateTime dtNow = DateTime.Now; int hvoMajor = 0; // hvo of the 'major' object that has the DateModified property. if (SameMinute(dtNow, m_currentMinute)) { // We can use our Dictionary if (m_recentMods.ContainsKey(hvo)) { hvoMajor = m_recentMods[hvo]; } } else { ResetDelay(); } int flidModify = 0; if (hvoMajor == 0) { for (int hvoCandidate = hvo; hvoCandidate != 0; hvoCandidate = m_cache.GetOwnerOfObject(hvoCandidate)) { // We assume that this is a dummy object at this point and GetClassOfObject // only accepts real objects. Since it's a dummy object, changes should never // affect the modify time of a real object. Maybe at some point we can get an // interface method to check for dummy objects. if (hvoCandidate < 0) { return; } int clid = m_cache.GetClassOfObject(hvoCandidate); if (clid == 0) { return; // maybe a deleted object, no good to us, we can't record modify time. } flidModify = (int)m_mdc.GetFieldId2((uint)clid, "DateModified", true); if (flidModify != 0) { hvoMajor = hvoCandidate; break; } } if (hvoMajor == 0) { return; // found no owner with DateCreated property. } m_recentMods[hvo] = hvoMajor; // lets us find it fast if modified again soon. } else { // We need to set flidModify! int clid = m_cache.GetClassOfObject(hvoMajor); if (clid != 0) { flidModify = (int)m_mdc.GetFieldId2((uint)clid, "DateModified", true); } } if (flidModify == 0) { return; // can't set the time prop without a field... } DateTime oldModifyTime = m_cache.GetTimeProperty(hvoMajor, flidModify); // If we already noted a modify time in the current minute, don't do it again. // This is intended to keep down the overhead of recording modify times for frequently // modified objects. if (SameMinute(oldModifyTime, dtNow)) { //Trace.TraceInformation("New Modify Time ({0}) for {1} is same minute as the old ({2}).\n", // dtNow, hvoMajor, oldModifyTime); return; } // if (m_currentMinute != null && // m_currentMinute.Date == dtNow.Date && m_currentMinute.Hour = dtNow.Hour && m_currentMinute.Minute == dtNow.Minute) // return; // Set the modify time. If possible tack this on to the last Undo task (or the current one, if a // transaction is open). if (m_cache.ActionHandlerAccessor != null && m_cache.VwOleDbDaAccessor != null && ((m_cache.DatabaseAccessor != null && m_cache.DatabaseAccessor.IsTransactionOpen()) || m_cache.CanUndo)) { m_cache.ContinueUndoTask(); m_cache.SetTimeProperty(hvoMajor, flidModify, dtNow); m_cache.EndUndoTask(); } else { // We don't have an Undo task to append to, so somehow a Save has occurred // in the midst of the operation that caused the time stamp modification. // If we make an empty undo task, the user will typically have no idea what // could be undone, and will be confused. Best to make it impossible to // undo the timestamp change also. using (new SuppressSubTasks(m_cache)) { m_cache.SetTimeProperty(hvoMajor, flidModify, dtNow); } } //Trace.TraceInformation("Setting new Modify Time ({0}) for {1}\n", // dtNow, hvoMajor); } finally { m_fModifyChangeInProgress = false; } }
/// <summary> /// Return the hvo for theCmBaseAnnotation that /// matches the given boundaries in an StTxtPara object. /// If no exact match is found, return the nearest segment (preferably the following word). /// </summary> /// <param name="hvoStTxtPara"></param> /// <param name="ichMin"></param> /// <param name="ichLim"></param> /// <param name="fOnlyTWFIC">true, if restricted to TWFIC</param> /// <param name="fExactMatch"> true if we return an exact match, false otherwise.</param> /// <returns>hvo is 0 if not found.</returns> static internal int FindAnnotationHvoForStTxtPara(FdoCache cache, int hvoStTxtPara, int ichMin, int ichLim, bool fOnlyTWFIC, out bool fExactMatch) { int twficType = CmAnnotationDefn.Twfic(cache).Hvo; int textSegType = CmAnnotationDefn.TextSegment(cache).Hvo; fExactMatch = false; int clsid = cache.GetClassOfObject(hvoStTxtPara); if (clsid != StTxtPara.kClassId) { Debug.Assert(clsid != StTxtPara.kClassId, "hvoStTxtPara should be of class StTxtPara."); return 0; } int kflidParaSegment = InterlinVc.ParaSegmentTag(cache); ISilDataAccess sda = cache.MainCacheAccessor; // first find the closest segment. int[] segments = cache.GetVectorProperty(hvoStTxtPara, kflidParaSegment, true); ICmBaseAnnotation cbaClosestSeg = FindClosestAnnotation(cache, segments, textSegType, ichMin, ichLim, out fExactMatch); if (cbaClosestSeg == null) return 0; // if it was an exact match for a segment, return it. if (cbaClosestSeg != null && fExactMatch && !fOnlyTWFIC) return cbaClosestSeg.Hvo; // otherwise, see if we can find a closer wordform int[] segmentForms = cache.GetVectorProperty(cbaClosestSeg.Hvo, InterlinVc.SegmentFormsTag(cache), true); ICmBaseAnnotation cbaClosestWf = FindClosestAnnotation(cache, segmentForms, twficType, ichMin, ichLim, out fExactMatch); if (cbaClosestWf == null) { return fOnlyTWFIC ? 0 : cbaClosestSeg.Hvo; } return cbaClosestWf.Hvo; }