private void EnsureSyncText() { if (m_selHelper != null && m_selHelper.Selection != null && m_selHelper.Selection.RootBox != null) { TextSelInfo tsi = new TextSelInfo(m_selHelper.Selection); m_selHelper.RootSite.RootBox.PropChanged(tsi.HvoAnchor, tsi.TagAnchor, 0, 0, 0); if (tsi.Hvo(false) != tsi.Hvo(true)) { m_selHelper.RootSite.RootBox.PropChanged(tsi.Hvo(true), tsi.Tag(true), 0, 0, 0); } } }
protected override bool OnRightMouseUp(Point pt, Rectangle rcSrcRoot, Rectangle rcDstRoot) { IVwSelection sel = RootBox.MakeSelAt(pt.X, pt.Y, rcSrcRoot, rcDstRoot, false); TextSelInfo tsi = new TextSelInfo(sel); return HandleRightClickOnObject(tsi.Hvo(false)); }
protected override bool OnRightMouseUp(Point pt, Rectangle rcSrcRoot, Rectangle rcDstRoot) { // if we don't install the selection here, a previous selection may give us // spurious results later on when handling the UI this right click brings up; // see LT-12154. IVwSelection sel = RootBox.MakeSelAt(pt.X, pt.Y, rcSrcRoot, rcDstRoot, true); TextSelInfo tsi = new TextSelInfo(sel); return HandleRightClickOnObject(tsi.Hvo(false)); }
protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); if (e.Button == MouseButtons.Left && (ModifierKeys & Keys.Control) == Keys.Control) { // Control-click: take the first jump-to-tool command from the right-click menu for this location. // Create a selection where we right clicked IVwSelection sel = GetSelectionAtPoint(new Point(e.X, e.Y), false); TextSelInfo tsi = new TextSelInfo(sel); int hvoTarget = tsi.Hvo(false); // May be (for example) dummy ID used for type-ahead object in reference vector list. if (hvoTarget == 0 || !Cache.ServiceLocator.IsValidObjectId(hvoTarget)) return; using (ReferenceBaseUi ui = GetCmObjectUiForRightClickMenu(hvoTarget)) { ui.HandleCtrlClick(Mediator, this); } } }
private void EnsureSyncText() { if (m_selHelper != null && m_selHelper.Selection != null && m_selHelper.Selection.RootBox != null) { TextSelInfo tsi = new TextSelInfo(m_selHelper.Selection); m_selHelper.RootSite.RootBox.PropChanged(tsi.HvoAnchor, tsi.TagAnchor, 0, 0, 0); if (tsi.Hvo(false) != tsi.Hvo(true)) m_selHelper.RootSite.RootBox.PropChanged(tsi.Hvo(true), tsi.Tag(true), 0, 0, 0); } }
/// <summary> /// If the key is Enter, and the selection is in the contents of an StTxtPara, save information we will need /// to adjust things after the keypress executes. /// </summary> public void StartKeyPressed(KeyPressEventArgs e, Keys modifiers) { if (m_segDefn_note == 0) //|| !m_parentEditingHelper.Editable return; // in-memory testing or we can't edit the view anyways m_tsiOrig = new TextSelInfo(m_parentEditingHelper.EditedRootBox); // Enhance JohnT: maybe there is something useful we could do if the other end of the selection isn't in the // same text, but it's not enough to just get the objects after the end; that produces a crash. // A temporary patch is to not attempt this adjustment at all in this case. See TE-8416. // This means segmented BT is lost on the trailing part of the paragraph when Enter is used // to replace a range, also some precision is lost on scripture notes on that segment. See TE-8419. // It should be fixed in the re-architecture, where the delete is handled as a separate UOW. if (e.KeyChar == '\r' && (modifiers & Keys.Shift) == 0 && m_tsiOrig.Selection != null && m_tsiOrig.Tag(true) == kflidContents && m_tsiOrig.Tag(false) == kflidContents && m_cache.GetOwnerOfObject(m_tsiOrig.Hvo(false)) == m_cache.GetOwnerOfObject(m_tsiOrig.Hvo(true))) { // collect annotations that come after the selection, so we can move those into the new paragraph. if (m_tsiOrig.Selection.EndBeforeAnchor) { // The 'end' of the selection (the boundary after which stuff will be moved) // is really the anchor. m_hvoParaSelEnd = m_tsiOrig.Hvo(false); m_ichSelEnd = m_tsiOrig.IchAnchor; m_hvoStText = m_tsiOrig.ContainingObject(1, false); } else { m_hvoParaSelEnd = m_tsiOrig.Hvo(true); m_ichSelEnd = m_tsiOrig.IchEnd; m_hvoStText = m_tsiOrig.ContainingObject(1, true); } m_ihvoParaPrev = m_cache.GetObjIndex(m_hvoStText, kflidParagraphs, m_hvoParaSelEnd); string sql = String.Format("select cba.BeginObject, cba.Id, cba.AnnotationType, cba.BeginOffset, cba.EndOffset from CmBaseAnnotation_ cba " + "where cba.BeginObject = {0} and " + "cba.BeginOffset >= {1} " + "order by cba.BeginOffset, cba.EndOffset", new object[] { m_hvoParaSelEnd, m_ichSelEnd }); m_cbaHvosAffectedByEdit = GetCbasPotentiallyAffectedByTextEdit(m_cache, m_hvoParaSelEnd, sql); // we will need to subtract the difference from the selection's end. m_cchAdjust = -m_ichSelEnd; m_parasWeHaveAdjusted.Add(m_hvoParaSelEnd); } else { m_hvoStText = 0; // this functionality does not apply. } if (m_cbaHvosAffectedByEdit != null) m_movedAnnsFromAfterInsertBreak.AddRange(m_cbaHvosAffectedByEdit); }
/// <summary> /// Gets the selection HVO from a slice control. /// </summary> /// <param name="slice">The non-null slice to get the selection from.</param> /// <returns>The HVO of the selection or 0 if there is none.</returns> private int GetSelectionHvoFromControls(Slice slice) { if (slice.Control == null || slice.Control.Controls.Count == 0) return 0; foreach (Control x in slice.Control.Controls) { if (x is RootSiteControl) { var site = x as SimpleRootSite; if (site != null && site.RootBox != null) { var tsi = new TextSelInfo(site.RootBox); return tsi.Hvo(true); } } } return 0; // no selection found }
/// ------------------------------------------------------------------------------------ /// <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; }
override protected bool HandleContextMenuFromKeyboard(IVwSelection sel, Point center) { TextSelInfo tsi = new TextSelInfo(sel); return HandleRightClickOnObject(tsi.Hvo(false)); }
internal string BuildCurrentMorphsString(IVwSelection sel) { CheckDisposed(); int ichSel = -1; int hvoObj = 0; int tag = 0; m_needDelayedSelection = false; if (sel != null) { TextSelInfo selInfo = new TextSelInfo(sel); // Receiving data from TSF on Windows creates a range covering the inserted character instead // of an insertion point following the inserted character. Anchor marks the beginning of that // range and End marks the end of the range. We want an insertion point at the end. ichSel = selInfo.IchEnd; hvoObj = selInfo.Hvo(true); tag = selInfo.Tag(true); if (Environment.OSVersion.Platform == PlatformID.Win32NT && ichSel != selInfo.IchAnchor) { // TSF also replaces our carefully created selection, adjusted carefully to follow the // inserted character, with one of its own choosing after we return, so flag that we'll // need to recreate the desired selection at idle time when TSF has quit interfering. m_needDelayedSelection = true; } } // for now, we'll just configure getting the string for the primary morpheme line. int ws = this.VernWsForPrimaryMorphemeLine; m_ichSel = -1; ITsStrBldr builder = TsStrBldrClass.Create(); ITsString space = TsStringUtils.MakeTss(" ", ws); ISilDataAccess sda = m_sandbox.Caches.DataAccess; ITsString tssWordform = m_sandbox.SbWordForm(ws); // we're dealing with a phrase if there are spaces in the word. bool fBaseWordIsPhrase = SandboxBase.IsPhrase(tssWordform.Text); int cmorphs = m_sda.get_VecSize(m_hvoSbWord, SandboxBase.ktagSbWordMorphs); for (int imorph = 0; imorph < cmorphs; ++imorph) { int hvoMorph = m_sda.get_VecItem(m_hvoSbWord, SandboxBase.ktagSbWordMorphs, imorph); if (imorph != 0) { builder.ReplaceTsString(builder.Length, builder.Length, space); // add a second space to separate morphs in a phrase. if (fBaseWordIsPhrase) builder.ReplaceTsString(builder.Length, builder.Length, space); } int hvoMorphForm = sda.get_ObjectProp(hvoMorph, SandboxBase.ktagSbMorphForm); if (hvoMorph == hvoObj && tag == SandboxBase.ktagSbMorphPrefix) m_ichSel = builder.Length + ichSel; builder.ReplaceTsString(builder.Length, builder.Length, sda.get_StringProp(hvoMorph, SandboxBase.ktagSbMorphPrefix)); if (hvoMorphForm == hvoObj && tag == SandboxBase.ktagSbNamedObjName) m_ichSel = builder.Length + ichSel; builder.ReplaceTsString(builder.Length, builder.Length, sda.get_MultiStringAlt(hvoMorphForm, SandboxBase.ktagSbNamedObjName, ws)); if (hvoMorph == hvoObj && tag == SandboxBase.ktagSbMorphPostfix) m_ichSel = builder.Length + ichSel; builder.ReplaceTsString(builder.Length, builder.Length, sda.get_StringProp(hvoMorph, SandboxBase.ktagSbMorphPostfix)); } if (cmorphs == 0) { if (m_hvoSbWord == hvoObj && tag == SandboxBase.ktagMissingMorphs) m_ichSel = ichSel; m_morphString = SandboxBase.InterlinComboHandler.StrFromTss(tssWordform); } else { m_morphString = SandboxBase.InterlinComboHandler.StrFromTss(builder.GetString()); } return m_morphString; }