/// <summary> /// Redo it. If a Refresh is going to happen, no need to do anything. /// </summary> /// <param name="fRefreshPending"></param> /// <returns></returns> public bool Redo(bool fRefreshPending) { if (m_fForRedo && !fRefreshPending) { m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvo, m_tag, m_ihvo, m_chvoIns, m_chvoDel); } return(true); }
/// <summary> /// Add the specified type of freeform annotation to the given segment. /// Undoable by default. /// </summary> /// <param name="hvoSeg"></param> /// <param name="hvoType">freeform annotation type</param> /// <returns></returns> public ICmIndirectAnnotation AddFreeformAnnotation(int hvoSeg, int hvoType) { using (SuppressSubTasks suppressor = new SuppressSubTasks(m_fdoCache, true)) { // convert any preceeding dummy segments, so paragraph parser does not push this to the first dummy sentence. (LT-7318) int hvoPara = m_fdoCache.GetObjProperty(hvoSeg, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginObject); StTxtPara para = StTxtPara.CreateFromDBObject(m_fdoCache, hvoPara) as StTxtPara; para.EnsurePreceedingSegmentsAreReal(hvoSeg); string undoString = ""; string redoString = ""; if (hvoType == ktagSegFF_freeTranslation) { undoString = ITextStrings.ksUndoAddFreeformTranslation; redoString = ITextStrings.ksRedoAddFreeformTranslation; } else if (hvoType == ktagSegFF_literalTranslation) { undoString = ITextStrings.ksUndoAddLiteralTranslation; redoString = ITextStrings.ksRedoAddLiteralTranslation; } else if (hvoType == ktagSegFF_note) { undoString = ITextStrings.ksUndoAddNote; redoString = ITextStrings.ksRedoAddNote; } else { throw new ArgumentException(String.Format("segment freeform type {0} is not yet supported here.", hvoType)); } ICmIndirectAnnotation ann; m_fdoCache.BeginUndoTask(undoString, redoString); { ann = CmIndirectAnnotation.CreateUnownedIndirectAnnotation(m_fdoCache); ann.AppliesToRS.Append(hvoSeg); ann.AnnotationTypeRAHvo = hvoType; // Add it to the cached collection of freeform annotations. This is a bit clumsy because // it isn't a real property so we can't just use the normal methods for modifying a property. // Enhance JohnT: put it with the other ones of the same type. ISilDataAccess sda = m_fdoCache.MainCacheAccessor; IVwCacheDa cda = (IVwCacheDa)sda; int cFreeForm = sda.get_VecSize(hvoSeg, ktagSegFF); int[] freeForms = new int[cFreeForm + 1]; for (int i = 0; i < cFreeForm; i++) { freeForms[i] = sda.get_VecItem(hvoSeg, ktagSegFF, i); } freeForms[cFreeForm] = ann.Hvo; cda.CacheVecProp(hvoSeg, ktagSegFF, freeForms, cFreeForm + 1); sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoSeg, ktagSegFF, cFreeForm, 1, 0); } m_fdoCache.EndUndoTask(); return(ann); } }
/// <summary> /// Receives a notification that the selection in the root box has changed. /// /// </summary> /// <param name="rootb"></param> /// <param name="sel"></param> public void SelectionChanged(IVwRootBox rootb, IVwSelection sel) { CheckDisposed(); if (m_fInSelectionChanged) { return; } try { m_fInSelectionChanged = true; // suppress recursive calls. int hvoParent; int ihvo; int hvoSel = SelectedObject(rootb, sel, out hvoParent, out ihvo); if (hvoSel == m_hvoTa && hvoParent == m_hvoParent) { return; } int hvoTaOld = m_hvoTa; m_hvoTa = hvoSel; // must change before PropChange converting old one back. if (hvoTaOld != 0) { // Convert current object back to normal name. We replace the object with itself (without actually changing anything) // to force a redisplay, with different results because it is no longer the current object. m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvoParent, m_virtualTagObj, m_ihvoTa, 1, 1); } if (hvoSel != 0) { ParentObject = hvoParent; m_ihvoTa = ihvo; // Ensure the initial tag name matches the real one. (m_sda as IVwCacheDa).CacheStringProp(hvoSel, m_taTagName, m_sda.get_StringProp(hvoSel, m_snTagName)); SwitchTagAndFixSel(m_taTagName, rootb); } else { ParentObject = m_ihvoTa = 0; } } finally { m_fInSelectionChanged = false; } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Raises the <see cref="E:System.Windows.Forms.Control.LostFocus"/> event. /// </summary> /// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param> /// ------------------------------------------------------------------------------------ protected override void OnLostFocus(EventArgs e) { m_xmlVc.HasFocus = false; // Our selected objects are no longer treated as such. ISilDataAccess sda = Cache.MainCacheAccessor; IVwCacheDa cda = Cache.VwCacheDaAccessor; foreach (int hvo in m_selectedObjects) { cda.CacheIntProp(hvo, m_xmlVc.IsObjectSelectedTag, 0); sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvo, m_xmlVc.IsObjectSelectedTag, 0, 1, 1); } base.OnLostFocus(e); }
/// <summary> /// This is a demonstration of one way to handle special tricks as the user types. /// This is an oversimplified way of forcing numbers to be treated as verse numbers... /// for example, it will cause '5000' in the 'feeding of the 5000' to be treated as a verse number. /// </summary> /// <param name="vwselNew"></param> protected override void HandleSelectionChange(IVwSelection vwselNew) { base.HandleSelectionChange(vwselNew); if (vwselNew == null) { return; // Not sure whether this happens, but best to be sure. } int ichSel, hvoObj, tag, ws; bool fAssocPrev; ITsString tss; vwselNew.TextSelInfo(false, out tss, out ichSel, out fAssocPrev, out hvoObj, out tag, out ws); string text = tss.get_Text(); if (text == null) { return; // empty string. } ITsStrBldr tsb = null; for (int ich = 0; ich < text.Length; ++ich) { if (Char.IsDigit(text[ich])) { ITsTextProps ttp = tss.get_PropertiesAt(ich); string styleName = ttp.GetStrPropValue((int)FwKernelLib.FwTextPropType.ktptNamedStyle); if (styleName != "verseNumber") { // We'll change just this one character. We could make this more efficient for dealing with // long strings of digits, but it's unlikely we'll ever have to deal with more than one. if (tsb == null) { tsb = tss.GetBldr(); } tsb.SetStrPropValue(ich, ich + 1, (int)FwKernelLib.FwTextPropType.ktptNamedStyle, "verseNumber"); } } } if (tsb != null) { ISilDataAccess sda = m_rootb.get_DataAccess(); // In this sample the only string is a multistring. If in doubt, we could test for ws == 0 to // see whether it is a simple string. sda.SetMultiStringAlt(hvoObj, tag, ws, tsb.GetString()); sda.PropChanged(null, (int)FwViews.PropChangeType.kpctNotifyAll, hvoObj, tag, 0, tss.get_Length(), tss.get_Length()); } }
public override void MakeRoot() { CheckDisposed(); if (m_fdoCache == null || DesignMode || m_slice.ContainingDataTree == null) { return; } m_rootb = VwRootBoxClass.Create(); m_rootb.SetSite(this); if (m_ws == 0) { m_ws = m_fdoCache.DefaultAnalWs; } m_hvoStText = m_fdoCache.GetObjProperty(m_hvoOwner, m_flid); // If we don't already have an StText in this field, make one now. if (m_hvoStText == 0) { ISilDataAccess sda = m_fdoCache.MainCacheAccessor; // Create one and initialize it. Don't use the FdoCache method, because it's important NOT to notify // our own data tree of the change...if we do, it could start a new regenerate in the middle of an // existing one with bad consequences. m_hvoStText = sda.MakeNewObject(StText.kclsidStText, m_hvoOwner, m_flid, -2); int hvoStTxtPara = sda.MakeNewObject(StTxtPara.kclsidStTxtPara, m_hvoStText, (int)StText.StTextTags.kflidParagraphs, 0); ITsStrFactory tsf = TsStrFactoryClass.Create(); sda.SetString(hvoStTxtPara, (int)StTxtPara.StTxtParaTags.kflidContents, tsf.MakeString("", m_ws)); // Notify change on the main property. The other properties we changed are part of the new object, and nothing // can know their previous state and need to see the change. sda.PropChanged(m_slice.ContainingDataTree, (int)PropChangeType.kpctNotifyAllButMe, m_hvoOwner, m_flid, 0, 1, 0); } m_vc = new StVc("Normal", m_ws); m_vc.Cache = m_fdoCache; m_vc.Editable = true; m_rootb.DataAccess = m_fdoCache.MainCacheAccessor; m_rootb.SetRootObject(m_hvoStText, m_vc, (int)StTextFrags.kfrText, m_styleSheet); base.MakeRoot(); m_dxdLayoutWidth = kForceLayout; // Don't try to draw until we get OnSize and do layout. //TODO: //ptmw->RegisterRootBox(qrootb); }
/// <summary> /// Insert breaks for the text in the indicated range of the indicate StTxtPara /// </summary> /// <param name="ichMin"></param> /// <param name="ichLim"></param> /// <param name="hvoPara"></param> public void Guess(int ichMin, int ichLim1, int hvoPara) { Setup(hvoPara); ITsString tss = m_sda.get_StringProp(hvoPara, (int)StTxtPara.StTxtParaTags.kflidContents); ITsStrBldr bldr = tss.GetBldr(); int ichLim = ichLim1; if (ichLim1 == -1) { ichLim = tss.Length; } string txt = tss.Text; int offset = 0; // offset in tsb caused by previously introduced spaces. for (int ichStart = 0; ichStart < ichLim;) // no advance! decide inside loop. { int cch = Match(ichStart, ichLim, txt); if (cch < 0) { // no match ichStart++; } else { // match, ensure spaces. if (ichStart > 0 && !SpaceAt(bldr, ichStart + offset - 1)) { InsertSpace(bldr, ichStart + offset); offset++; } if (ichStart + cch < ichLim && !SpaceAt(bldr, ichStart + cch + offset)) { InsertSpace(bldr, ichStart + cch + offset); offset++; } ichStart += cch; } } if (offset > 0) { m_sda.SetString(hvoPara, (int)StTxtPara.StTxtParaTags.kflidContents, bldr.GetString()); m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoPara, (int)StTxtPara.StTxtParaTags.kflidContents, 0, 0, 0); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// When we get focus, start filtering messages to catch characters /// </summary> /// <param name="e"></param> /// ------------------------------------------------------------------------------------ protected override void OnGotFocus(EventArgs e) { m_xmlVc.HasFocus = true; if (!m_selectedObjects.Contains(XmlVc.FocusHvo)) { m_selectedObjects.Add(XmlVc.FocusHvo); } // Whatever any other view may have done while we don't have focus, our selected objects // are now treated as selected. And, all of them need propChanged, to force redrawing. ISilDataAccess sda = Cache.MainCacheAccessor; IVwCacheDa cda = Cache.VwCacheDaAccessor; foreach (int hvo in m_selectedObjects) { cda.CacheIntProp(hvo, m_xmlVc.IsObjectSelectedTag, 1); sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvo, m_xmlVc.IsObjectSelectedTag, 0, 1, 1); } base.OnGotFocus(e); }
/// <summary> /// Parse the text in hvoPara.Contents[vc.DestWs] and make words /// </summary> /// <param name="hvoPara"></param> public void Parse(int hvoPara) { ITsString tssSrc = m_sda.get_MultiStringAlt(hvoPara, ViewSampleVc.ktagParaContents, m_vc.DestWs); WordMaker wm = new WordMaker(tssSrc, m_wsf); int ichMin, ichLim; int cbundle = m_sda.get_VecSize(hvoPara, ViewSampleVc.ktagParaBundles); // Clean it out. This wouldn't normally be appropriate for an owning property, but we can get away // with it for a non-database cache. if (cbundle != 0) { m_sda.Replace(hvoPara, ViewSampleVc.ktagParaBundles, 0, cbundle, new int[0], 0); } int ibundle = 0; ITsPropsFactory tpf = (ITsPropsFactory) new FwKernelLib.TsPropsFactoryClass(); ITsTextProps ttp = tpf.MakeProps(null, m_vc.SourceWs, 0); for (ITsString tssWord = wm.NextWord(out ichMin, out ichLim); tssWord != null; tssWord = wm.NextWord(out ichMin, out ichLim)) { // 4 is an arbitrary classid; this kind of cache does nothing with it. int hvoBundle = m_sda.MakeNewObject(4, hvoPara, ViewSampleVc.ktagParaBundles, ibundle); ibundle++; m_sda.SetString(hvoBundle, ViewSampleVc.ktagBundleBase, tssWord); ITsStrBldr tsb = tssWord.GetBldr(); tsb.Replace(0, 0, "idiom(", ttp); tsb.Replace(tsb.get_Length(), tsb.get_Length(), ")", ttp); m_sda.SetString(hvoBundle, ViewSampleVc.ktagBundleIdiom, tsb.GetString()); tsb = tssWord.GetBldr(); tsb.Replace(0, 0, "ling(", ttp); tsb.Replace(tsb.get_Length(), tsb.get_Length(), ")", ttp); m_sda.SetString(hvoBundle, ViewSampleVc.ktagBundleLing, tsb.GetString()); } m_sda.PropChanged(null, (int)FwViews.PropChangeType.kpctNotifyAll, hvoPara, ViewSampleVc.ktagParaBundles, 0, ibundle, cbundle); }
public override void DoIt(Set <int> itemsToChange, ProgressState state) { CheckDisposed(); ISilDataAccess sda = m_cache.MainCacheAccessor; // Make a hashtable from HVO of entry to list of modified senses. Dictionary <int, List <int> > sensesByEntry = new Dictionary <int, List <int> >(); int tagOwningEntry = m_cache.VwCacheDaAccessor.GetVirtualHandlerName("LexSense", "OwningEntry").Tag; 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 hvoSense in itemsToChange) { i++; if (i % interval == 0) { state.PercentDone = i * 20 / itemsToChange.Count; state.Breath(); } int hvoMsa = sda.get_ObjectProp(hvoSense, (int)LexSense.LexSenseTags.kflidMorphoSyntaxAnalysis); if (hvoMsa != 0 && m_cache.GetClassOfObject(hvoMsa) != MoStemMsa.kclsidMoStemMsa) { continue; // can't fix this one, not a stem. } int hvoEntry = sda.get_ObjectProp(hvoSense, tagOwningEntry); List <int> senses = null; if (!sensesByEntry.TryGetValue(hvoEntry, out senses)) { senses = new List <int>(); sensesByEntry[hvoEntry] = senses; } senses.Add(hvoSense); } m_cache.BeginUndoTask(FdoUiStrings.ksUndoBulkEditPOS, FdoUiStrings.ksRedoBulkEditPOS); BulkEditBar.ForceRefreshOnUndoRedo(sda); i = 0; interval = Math.Min(100, Math.Max(sensesByEntry.Count / 50, 1)); foreach (KeyValuePair <int, List <int> > kvp in sensesByEntry) { i++; if (i % interval == 0) { state.PercentDone = i * 80 / sensesByEntry.Count + 20; state.Breath(); } int hvoEntry = kvp.Key; List <int> sensesToChange = kvp.Value; int hvoMsmTarget = 0; int cmsa = sda.get_VecSize(hvoEntry, (int)LexEntry.LexEntryTags.kflidMorphoSyntaxAnalyses); bool fAssumeSurvives = true; // true if we know all old MSAs will survive. for (int imsa = 0; imsa < cmsa; imsa++) { int hvoMsa = sda.get_VecItem(hvoEntry, (int)LexEntry.LexEntryTags.kflidMorphoSyntaxAnalyses, imsa); if (m_cache.GetClassOfObject(hvoMsa) == MoStemMsa.kclsidMoStemMsa && sda.get_ObjectProp(hvoMsa, (int)MoStemMsa.MoStemMsaTags.kflidPartOfSpeech) == m_selectedHvo) { // Can reuse this one! hvoMsmTarget = hvoMsa; fAssumeSurvives = false; // old MSA may be redundant. break; } } if (hvoMsmTarget == 0) { // See if we can reuse an existing MoStemMsa by changing it. // This is possible if it is used only by senses in the list, or not used at all. List <int> otherSenses = new List <int>(); AddExcludedSenses(sda, hvoEntry, (int)LexEntry.LexEntryTags.kflidSenses, otherSenses, sensesToChange); for (int imsa = 0; imsa < cmsa; imsa++) { int hvoMsa = sda.get_VecItem(hvoEntry, (int)LexEntry.LexEntryTags.kflidMorphoSyntaxAnalyses, imsa); if (m_cache.GetClassOfObject(hvoMsa) != MoStemMsa.kclsidMoStemMsa) { continue; } bool fOk = true; foreach (int hvoOtherSense in otherSenses) { if (sda.get_ObjectProp(hvoOtherSense, (int)LexSense.LexSenseTags.kflidMorphoSyntaxAnalysis) == hvoMsa) { fOk = false; // we can't change it, one of the unchanged senses uses it break; } } if (fOk) { // Can reuse this one! Nothing we don't want to change uses it. Go ahead and set it to the // required POS. hvoMsmTarget = hvoMsa; int hvoOld = sda.get_ObjectProp(hvoMsmTarget, (int)MoStemMsa.MoStemMsaTags.kflidPartOfSpeech); sda.SetObjProp(hvoMsmTarget, (int)MoStemMsa.MoStemMsaTags.kflidPartOfSpeech, m_selectedHvo); sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoMsmTarget, (int)MoStemMsa.MoStemMsaTags.kflidPartOfSpeech, 0, 1, hvoOld == 0 ? 1 : 0); // compare MoStemMsa.ResetInflectionClass: changing POS requires us to clear inflection class, // if it is set. if (hvoOld != 0 && sda.get_ObjectProp(hvoMsmTarget, (int)MoStemMsa.MoStemMsaTags.kflidInflectionClass) != 0) { sda.SetObjProp(hvoMsmTarget, (int)MoStemMsa.MoStemMsaTags.kflidInflectionClass, 0); sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoMsmTarget, (int)MoStemMsa.MoStemMsaTags.kflidInflectionClass, 0, 0, 1); } break; } } } if (hvoMsmTarget == 0) { // Nothing we can reuse...make a new one. hvoMsmTarget = sda.MakeNewObject((int)MoStemMsa.kclsidMoStemMsa, hvoEntry, (int)LexEntry.LexEntryTags.kflidMorphoSyntaxAnalyses, -1); sda.SetObjProp(hvoMsmTarget, (int)MoStemMsa.MoStemMsaTags.kflidPartOfSpeech, m_selectedHvo); sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoMsmTarget, (int)MoStemMsa.MoStemMsaTags.kflidInflectionClass, m_cache.GetObjIndex(hvoEntry, (int)LexEntry.LexEntryTags.kflidMorphoSyntaxAnalyses, hvoMsmTarget), 1, 0); } // Finally! Make the senses we want to change use it. foreach (int hvoSense in sensesToChange) { int hvoOld = sda.get_ObjectProp(hvoSense, (int)LexSense.LexSenseTags.kflidMorphoSyntaxAnalysis); if (hvoOld == hvoMsmTarget) { continue; // reusing a modified msa. } LexSense.HandleOldMSA(m_cache, hvoSense, hvoMsmTarget, fAssumeSurvives); sda.SetObjProp(hvoSense, (int)LexSense.LexSenseTags.kflidMorphoSyntaxAnalysis, hvoMsmTarget); sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoSense, (int)LexSense.LexSenseTags.kflidMorphoSyntaxAnalysis, 0, 1, hvoOld == 0 ? 1 : 0); } } m_cache.EndUndoTask(); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Selections the changed. /// </summary> /// <param name="prootb">The prootb.</param> /// <param name="sel">The sel.</param> /// ------------------------------------------------------------------------------------ public override void SelectionChanged(IVwRootBox prootb, IVwSelection sel) { CheckDisposed(); if (m_fInChangeSelectedObjects) { return; } m_fInChangeSelectedObjects = true; try { int cvsli = 0; // Out variables for AllTextSelInfo. int ihvoRoot = 0; int tagTextProp = 0; int cpropPrevious = 0; int ichAnchor = 0; int ichEnd = 0; int ws = 0; bool fAssocPrev = false; int ihvoEnd = 0; ITsTextProps ttpBogus = null; SelLevInfo[] rgvsli = new SelLevInfo[0]; List <int> newSelectedObjects = new List <int>(4); newSelectedObjects.Add(XmlVc.FocusHvo); if (sel != null) { cvsli = sel.CLevels(false) - 1; // Main array of information retrived from sel that made combo. rgvsli = SelLevInfo.AllTextSelInfo(sel, cvsli, out ihvoRoot, out tagTextProp, out cpropPrevious, out ichAnchor, out ichEnd, out ws, out fAssocPrev, out ihvoEnd, out ttpBogus); for (int i = 0; i < cvsli; i++) { newSelectedObjects.Add(rgvsli[i].hvo); } } ISilDataAccess sda = Cache.MainCacheAccessor; IVwCacheDa cda = Cache.VwCacheDaAccessor; foreach (int hvo in m_selectedObjects) { if (!newSelectedObjects.Contains(hvo)) { cda.CacheIntProp(hvo, m_xmlVc.IsObjectSelectedTag, 0); sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvo, m_xmlVc.IsObjectSelectedTag, 0, 1, 1); } } foreach (int hvo in newSelectedObjects) { if (!m_selectedObjects.Contains(hvo)) { cda.CacheIntProp(hvo, m_xmlVc.IsObjectSelectedTag, 1); sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvo, m_xmlVc.IsObjectSelectedTag, 0, 1, 1); } } m_selectedObjects = newSelectedObjects; if (sel != null && !sel.IsValid) { // we wiped it out by regenerating parts of the display in our PropChanged calls! Restore it if we can. sel = m_rootb.MakeTextSelection(ihvoRoot, cvsli, rgvsli, tagTextProp, cpropPrevious, ichAnchor, ichEnd, ws, fAssocPrev, ihvoEnd, ttpBogus, true); } } finally { m_fInChangeSelectedObjects = false; } base.SelectionChanged(prootb, sel); }
/// <summary> /// Notify clients who have requested it that the specified property is changing. /// The last five arguments indicate the nature of the change, as in /// ${IVwNotifyChange#PropChanged}. In general, that method will be called for /// all clients that have requested notification. Certain variations in this /// process can be made using the first two arguments. /// If pct is kpctNotifyAll, the first argument is ignored, and all clients are /// notified in an arbitrary order. (Currently this is also the default behavior /// if some unrecognized constant is passed. This may eventually become an error.) /// If pct is kpctNotifyMeThenAll, then the object indicated by the first argument /// is notified first. This allows the main focus window to update first. /// If pct is kpctNotifyAllButMe, then the object indicated by the first argument /// is not notified at all, even if it is listed as requesting notification. This /// is useful when the object making the change has already done the work that it /// would normally do when receiving such a notification. /// /// FDO handles notification of all data changes, so this method does not pass the call on /// to the FDO SDA implementation. /// /// Decorator sublasses should intercept the 'setter' calls and notify /// their views of the change. ///</summary> /// <param name='_nchng'> </param> /// <param name='_ct'> </param> /// <param name='hvo'> </param> /// <param name='tag'> </param> /// <param name='ivMin'> </param> /// <param name='cvIns'> </param> /// <param name='cvDel'> </param> public virtual void PropChanged(IVwNotifyChange _nchng, int _ct, int hvo, int tag, int ivMin, int cvIns, int cvDel) { // TODO: Do not pass it on, as FDO handles notification on chages to any of its data properties. // Decorator m_baseSda.PropChanged(_nchng, _ct, hvo, tag, ivMin, cvIns, cvDel); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Executes in two distinct scenarios. /// 1. If disposing is true, the method has been called directly /// or indirectly by a user's code via the Dispose method. /// Both managed and unmanaged resources can be disposed. /// 2. If disposing is false, the method has been called by the /// runtime from inside the finalizer and you should not reference (access) /// other managed objects, as they already have been garbage collected. /// Only unmanaged resources can be disposed. /// </summary> /// <param name="disposing">if set to <c>true</c> [disposing].</param> /// <remarks> /// If any exceptions are thrown, that is fine. /// If the method is being done in a finalizer, it will be ignored. /// If it is thrown by client code calling Dispose, /// it needs to be handled by fixing the bug. /// If subclasses override this method, they should call the base implementation. /// </remarks> /// ------------------------------------------------------------------------------------ protected virtual void Dispose(bool disposing) { //Debug.WriteLineIf(!disposing, "****************** " + GetType().Name + " 'disposing' is false. ******************"); // Must not be run more than once. if (m_isDisposed) { return; } if (disposing && m_fTurnOnMonitor) { try { // Dispose managed resources here. if (m_sda != null) { UpdateSemaphore semaphore = s_UpdateSemaphores[m_sda]; Debug.Assert(semaphore.fDataUpdateInProgress); // Remember selection so that we can try to reconstruct it after the PropChangeds SelectionHelper selection = SelectionHelper.Create(m_rootSite); TextSelInfo tsiAfterEdit = null; if (selection != null) { tsiAfterEdit = new TextSelInfo(selection.Selection); } bool fAdjustedChangeInfo = false; foreach (VwChangeInfo changeInfo in semaphore.changeInfoQueue) { int ivIns = changeInfo.ivIns; int cvDel = changeInfo.cvDel; int cvIns = changeInfo.cvIns; // Note: m_sda.MetaDataCache increments an internal com object // ref count that may not get cleared until you do // Marshal.FinalReleaseComObject on it. if it doesn't get cleared // it may hang tests. IFwMetaDataCache mdc = m_sda.MetaDataCache; if (!fAdjustedChangeInfo && mdc != null && tsiAfterEdit != null && m_editingHelper != null && m_editingHelper.MonitorTextEdits) { // if the selection-edit resulted in keeping the cursor in the same paragraph // we may need to do some more adjustments because views code // calculates VwChangeInfo based upon a string comparison, which does not // accurately tell us where the string was actually changed if the inserted // characters match those character positions in the original string. // For example changing "this is the old text" by inserting "this is the new text, but " // at the beginning results in the string "this is the old text, but this is the new text" // In that example the views code StringCompare would say ivIns started at "old text" // rather than the beginning of the string, since "this is the " matches the old string. // The first condition prevents our trying to make these adjustments when we have a multi-para // (end-before-anchor) selection. if (m_tsi.Hvo(true) == m_tsi.Hvo(false) && m_tsi.HvoAnchor == tsiAfterEdit.HvoAnchor && m_tsi.HvoAnchor == changeInfo.hvo && m_tsi.TagAnchor == changeInfo.tag) { // Our insertion point can be at the beginning or end of the range. int ichInsertionPointOrig = Math.Min(m_tsi.IchAnchor, m_tsi.IchEnd); // we may need to adjust ivIns, but not for MultiStrings, since // ivIns in that case is a ws, not an offset. int flidtype = mdc.GetFieldType((uint)changeInfo.tag); if (flidtype == (int)CellarModuleDefns.kcptBigString || flidtype == (int)CellarModuleDefns.kcptString) { // if the anchor has moved back after a delete, use it as a starting point if (!m_tsi.IsRange && cvDel > 0 && ivIns < m_tsi.IchAnchor) { if (ivIns + cvDel == m_tsi.IchAnchor) { // user did backspace from insertion point, so effectively // move the IP back the number of characters deleted. ivIns = Math.Max(m_tsi.IchAnchor - cvDel, 0); } // ctrl-del can also cause this, but in that case, characters // after the IP may have been deleted, too. Seems best not to try to adjust. } else { // use the original IP, since changeInfo uses CompareStrings // to calculate it, and that can be wrong when pasted string has // characters that coincidentally match the original string. ivIns = ichInsertionPointOrig; } } // if the initial selection is a range selection in the same paragraph // set the number of deleted characters to be the difference between // the begin and end offsets. if (m_tsi.HvoAnchor == m_tsi.Hvo(true) && m_tsi.IsRange) { cvDel = Math.Abs(m_tsi.IchEnd - m_tsi.IchAnchor); } // Review: do we expect this string to be Normalized already? // Review: should we do nothing if the pasted string contains newline, or set cvIns to the // length of the text after the last newline, or what?? if (InsertedTss != null && InsertedTss.Text != null && InsertedTss.Text.IndexOf(Environment.NewLine) == -1) { cvIns = InsertedTss.Length; } // indicate we've adjusted the changeInfo for the next PropChange. // this should be done only once per edit action. fAdjustedChangeInfo = true; } } m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, changeInfo.hvo, changeInfo.tag, ivIns, cvIns, cvDel); } semaphore.fDataUpdateInProgress = false; semaphore.sDescr = string.Empty; semaphore.changeInfoQueue.Clear(); // It is possible that the PropChanged caused a regenerate of the view. This // turned our selection invalid. Try to recover it. if (selection != null && !selection.IsValid) { selection.SetSelection(false); } // This needs to be called after setting the selection. It can cause // AnnotationAdjuster.EndKeyPressed() to be called which expects a // selection to be set. if (m_editingHelper != null) { m_editingHelper.OnFinishedEdit(); } // It is possible that OnFinishedEdit() caused a regenerate of the view. This // turned our selection invalid. Try to recover it. if (selection != null && !selection.IsValid) { selection.SetSelection(false); } } } finally { // In case anything goes wrong, if we possibly can, do this anyway, other wise the pane // may be more-or-less permanently locked. if (m_rootSite != null) { s_sitesMonitoring.Remove(m_rootSite); } // end Wait Cursor // Since it needs m_Owner, this must be done when 'disposing' is true, // as that is a disposable object, which may be gone in // Finalizer mode. if (m_Owner != null) { m_Owner.Cursor = m_oldCursor; } } } // Dispose unmanaged resources here, whether disposing is true or false. m_sda = null; m_Owner = null; m_rootSite = null; m_oldCursor = null; m_tsi = null; m_tssIns = null; m_isDisposed = true; }
protected void IssuePropChanged(ISilDataAccess sda, int hvoItem, int hvoSel, int hvoOld) { sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoItem, m_flidAtomicProp, 0, (hvoSel == 0 ? 0 : 1), (hvoOld == 0 ? 0 : 1)); }
/// <summary> /// If object hvo has no cached value for the property flidVirtual, do nothing. /// Otherwise, compute a new value for the property, and issue a PropChanged. (Currently only string type supported) /// If it has owning properties of type clidVirtual, do the same for all their items. /// </summary> /// <param name="hvo"></param> /// <param name="flidVirtual"></param> /// <param name="mdc"></param> /// <param name="sda"></param> private void RecomputeVirtuals(int hvo, uint clidVirtual, int flidVirtual, int typeVirtual, IFwMetaDataCache mdc, ISilDataAccess sda, IVwVirtualHandler vh) { if (Cache.GetClassOfObject(hvo) != clidVirtual) return; // Unless it's a computeEveryTime property, we don't need to worry if it's not already cached. if (vh.ComputeEveryTime || sda.get_IsPropInCache(hvo, flidVirtual, typeVirtual, 0)) { vh.Load(hvo, flidVirtual, 0, Cache.VwCacheDaAccessor); switch (typeVirtual) { case (int)CellarModuleDefns.kcptString: sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvo, flidVirtual, 0, 0, 0); break; default: Debug.WriteLine("RecomputeVirtuals: unimplemented prop type"); break; } } uint[] flids = DbOps.GetFieldsInClassOfType(mdc, (int)clidVirtual, FieldType.kgrfcptOwning); foreach (uint flid in flids) { int type = mdc.GetFieldType(flid); if (type == (int)CellarModuleDefns.kfcptOwningAtom) { RecomputeVirtuals(sda.get_ObjectProp(hvo, (int)flid), clidVirtual, flidVirtual, typeVirtual, mdc, sda, vh); } else { // must be owning sequence or collection; do them all. int chvo = sda.get_VecSize(hvo, (int)flid); for (int i = 0; i < chvo; i++) RecomputeVirtuals(sda.get_VecItem(hvo, (int)flid, i), clidVirtual, flidVirtual, typeVirtual, mdc, sda, vh); } } }
/// <summary> /// /// </summary> /// <param name="_nchng"></param> /// <param name="_ct"></param> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="ivMin"></param> /// <param name="cvIns"></param> /// <param name="cvDel"></param> public void PropChanged(IVwNotifyChange _nchng, int _ct, int hvo, int tag, int ivMin, int cvIns, int cvDel) { m_sda.PropChanged(_nchng, _ct, hvo, tag, ivMin, cvIns, cvDel); }
public void DoIt(ISilDataAccess sda) { sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_obj, m_flid, m_ihvo, m_cadd, m_cdel); }
void DoNotify() { m_sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvo, m_flid, 0, 1, 1); }
protected override void IssuePropChanged(ISilDataAccess sda, int hvoItem, int newVal, int oldVal) { sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoItem, m_flid, 0, 1, 1); }
int MakeRealObject(ITsString tssTyped) { // Figure whether owning atomic or owning collection or owning sequence. Throw if none. IFwMetaDataCache mdc = m_fdoCache.MetaDataCacheAccessor; FieldType iType = m_fdoCache.GetFieldType(m_flidEmptyProp); iType &= FieldType.kcptVirtualMask; ISilDataAccess sdaReal = m_fdoCache.MainCacheAccessor; // Make a new object of the specified class in the specified property. int ord = 0; switch (iType) { default: throw new Exception("ghost string property must be owning object property"); case FieldType.kcptOwningAtom: ord = -2; break; case FieldType.kcptOwningCollection: ord = -1; break; case FieldType.kcptOwningSequence: // ord = 0 set above (inserting the first and only object at position 0). break; } string sClassRaw = mdc.GetClassName((uint)m_clidDst); string sClass = m_mediator.StringTbl.GetString(sClassRaw, "ClassNames"); string sUndo = String.Format(DetailControlsStrings.ksUndoCreate0, sClass); string sRedo = String.Format(DetailControlsStrings.ksRedoCreate0, sClass); sdaReal.BeginUndoTask(sUndo, sRedo); int hvoNewObj = sdaReal.MakeNewObject((int)m_clidDst, m_hvoObj, m_flidEmptyProp, ord); // Set its property m_flidStringProp to tssTyped. If it is multilingual, choose based on ghostWs. FieldType iTypeString = m_fdoCache.GetFieldType(m_flidStringProp); iTypeString &= FieldType.kcptVirtualMask; switch (iTypeString) { default: throw new Exception("ghost property must store strings!"); case FieldType.kcptMultiString: case FieldType.kcptMultiBigString: case FieldType.kcptMultiUnicode: case FieldType.kcptMultiBigUnicode: sdaReal.SetMultiStringAlt(hvoNewObj, m_flidStringProp, m_wsToCreate, tssTyped); break; case FieldType.kcptString: case FieldType.kcptBigString: sdaReal.SetString(hvoNewObj, m_flidStringProp, tssTyped); break; } string ghostInitMethod = XmlUtils.GetOptionalAttributeValue(m_nodeObjProp, "ghostInitMethod"); if (ghostInitMethod != null) { ICmObject obj = CmObject.CreateFromDBObject(m_fdoCache, hvoNewObj); Type objType = obj.GetType(); System.Reflection.MethodInfo mi = objType.GetMethod(ghostInitMethod); mi.Invoke(obj, null); } // Issue PropChanged for the addition of the new object. (could destroy this). sdaReal.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvoObj, m_flidEmptyProp, 0, 1, 0); sdaReal.EndUndoTask(); return(hvoNewObj); }