/// <summary> /// Try to keep the selection from including any of the characters in a writing system label. /// See LT-8396. /// </summary> protected override void HandleSelectionChange(IVwRootBox prootb, IVwSelection vwselNew) { base.HandleSelectionChange(prootb, vwselNew); // 1) We don't want to recurse into here. // 2) If the selection is invalid we can't use it. // 3) If the selection is entirely formattable ("IsSelectionInOneFormattableProp"), we don't need to do // anything. if (s_fProcessingSelectionChanged || !vwselNew.IsValid || EditingHelper.IsSelectionInOneFormattableProp()) { return; } try { s_fProcessingSelectionChanged = true; SelectionHelper hlpr = SelectionHelper.Create(vwselNew, this); bool fRange = hlpr.IsRange; bool fChangeRange = false; if (fRange) { bool fAnchorEditable = vwselNew.IsEditable; hlpr.GetIch(SelectionHelper.SelLimitType.Anchor); int tagAnchor = hlpr.GetTextPropId(SelectionHelper.SelLimitType.Anchor); hlpr.GetIch(SelectionHelper.SelLimitType.End); int tagEnd = hlpr.GetTextPropId(SelectionHelper.SelLimitType.End); bool fEndBeforeAnchor = vwselNew.EndBeforeAnchor; if (fEndBeforeAnchor) { if (fAnchorEditable && tagAnchor > 0 && tagEnd < 0) { hlpr.SetTextPropId(SelectionHelper.SelLimitType.End, tagAnchor); hlpr.SetIch(SelectionHelper.SelLimitType.End, 0); fChangeRange = true; } } else { if (!fAnchorEditable && tagAnchor < 0 && tagEnd > 0) { hlpr.SetTextPropId(SelectionHelper.SelLimitType.Anchor, tagEnd); hlpr.SetIch(SelectionHelper.SelLimitType.Anchor, 0); fChangeRange = true; } } } if (fChangeRange) { hlpr.SetSelection(true); } } finally { s_fProcessingSelectionChanged = false; } }
private void UpdateSelectionForReplacingPreeditText(SelectionHelper selHelper, int countBackspace) { if ((m_ActionHandler == null || !m_ActionHandler.get_TasksSinceMark(true)) && m_InitialSelection != null && m_EndOfPreedit != null) { // we don't have an action handler (or we have nothing to rollback) which means // we didn't roll back the preedit. This means we have to create a range selection // that deletes the preedit. var bottom = selHelper.GetIch(SelectionHelper.SelLimitType.Bottom); selHelper.IchAnchor = Math.Max(0, m_InitialSelection.SelectionHelper.GetIch(SelectionHelper.SelLimitType.Top) - countBackspace); selHelper.IchEnd = Math.Max(bottom, m_EndOfPreedit.GetIch(SelectionHelper.SelLimitType.Bottom)); selHelper.SetSelection(true); } }
protected virtual int GetInsertionIndex(ICmObject[] objs, SelectionHelper sel) { if (objs.Length == 0) { return 0; } ICmObject curObj = GetCmObject(sel, SelectionHelper.SelLimitType.Top); int ich = sel.GetIch(SelectionHelper.SelLimitType.Top); for (int i = 0; i < objs.Length; i++) { // if the current ich is 0, then we can safely assume we are at the beginning of // the current item, so insert before it, otherwise we are in the middle in which // case the entire item is selected or at the end, so we insert after if (objs[i] == curObj) return ich == 0 ? i : i + 1; } return objs.Length; }
private void GetInsertionIndex(SelectionHelper sel, out ComplexConcPatternNode parent, out int index) { ComplexConcPatternNode curNode = GetNode(sel, SelectionHelper.SelLimitType.Top); if (m_patternModel.Root.IsLeaf || curNode == null) { parent = m_patternModel.Root; index = 0; return; } parent = curNode.Parent; int ich = sel.GetIch(SelectionHelper.SelLimitType.Top); index = GetNodeIndex(curNode); if (ich != 0) { index++; } }
/// <summary> /// This method must be called by the GUI thread only. /// It shows the current Preedit as a selection. /// </summary> private void ShowPreedit(string text, bool visible) { // Don't allow modifying the preedit if an undo or redo is in progress. if (m_dataChanging) { return; } if (AssociatedSimpleRootSite.InvokeRequired) { throw new ApplicationException( "Programming Error: ShowPreedit should only be called on GUI thread"); } if (AssociatedSimpleRootSite.RootBox == null) { return; } if (AssociatedSimpleRootSite.RootBox.Selection == null) { return; } // Some IME send a initial empty preedit, which can clear an existing selection // TODO: we could also check the selection is a range if this is neccessary if (string.IsNullOrEmpty(text) && m_ignoreInitialPreedit) { return; } m_ignoreInitialPreedit = false; IActionHandler actionHandler = AssociatedSimpleRootSite.DataAccess.GetActionHandler(); try { if (actionHandler != null) { actionHandler.BeginUndoTask(Resources.ksUndoTyping, Resources.ksRedoTyping); } AssociatedSimpleRootSite.EditingHelper.DeleteRangeIfComplex( AssociatedSimpleRootSite.RootBox); // update the current preedit selection with new preedit text. var selHelper = new SelectionHelper( AssociatedSimpleRootSite.EditingHelper.CurrentSelection); ITsString str = CreateTsStringUsingSelectionProps(text, selHelper); selHelper.Selection.ReplaceWithTsString(str); // make the selection fit the new text selHelper.SetIch(SelectionHelper.SelLimitType.Anchor, selHelper.GetIch(SelectionHelper.SelLimitType.Top)); selHelper.SetIch(SelectionHelper.SelLimitType.End, selHelper.IchAnchor + str.Length); // make the selection visible selHelper.SetSelection(true); } finally { if (actionHandler != null) { actionHandler.EndUndoTask(); } } // Update the position where a preedit window will appear SetImeCursorLocation(); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Compare the values of <see cref="SelectionHelper"/> with the expected values /// </summary> /// <param name="type"></param> /// <param name="selectionHelper"></param> /// <param name="ihvoRoot"></param> /// <param name="nPrevProps"></param> /// <param name="ich"></param> /// <param name="nWs"></param> /// <param name="fAssocPrev"></param> /// <param name="nLevels"></param> /// <param name="tag1"></param> /// <param name="cpropPrev1"></param> /// <param name="ihvo1"></param> /// <param name="tag0"></param> /// <param name="cpropPrev0"></param> /// <param name="ihvo0"></param> /// ------------------------------------------------------------------------------------ protected void CheckSelectionHelperValues(SelectionHelper.SelLimitType type, SelectionHelper selectionHelper, int ihvoRoot, int nPrevProps, int ich, int nWs, bool fAssocPrev, int nLevels, int tag1, int cpropPrev1, int ihvo1, int tag0, int cpropPrev0, int ihvo0) { Assert.IsTrue(m_basicView.IsSelectionVisible(null), "Selection not visible"); Assert.AreEqual(ihvoRoot, selectionHelper.GetIhvoRoot(type), "ihvoRoot differs"); Assert.AreEqual(nPrevProps, selectionHelper.GetNumberOfPreviousProps(type), "nPrevProps differs"); Assert.AreEqual(ich, selectionHelper.GetIch(type), "ich differs"); Assert.AreEqual(nWs, selectionHelper.GetWritingSystem(type), "ws differs"); Assert.AreEqual(fAssocPrev, selectionHelper.GetAssocPrev(type), "fAssocPrev differs"); Assert.AreEqual(nLevels, selectionHelper.GetNumberOfLevels(type), "Number of levels differs"); if (nLevels >= 2) { Assert.AreEqual(tag1, selectionHelper.GetLevelInfo(type)[1].tag, "tag (level 1) differs"); Assert.AreEqual(cpropPrev1, selectionHelper.GetLevelInfo(type)[1].cpropPrevious, "cpropPrev (level 1) differs"); Assert.AreEqual(ihvo1, selectionHelper.GetLevelInfo(type)[1].ihvo, "ihvo (level 1) differs"); } Assert.AreEqual(tag0, selectionHelper.GetLevelInfo(type)[0].tag, "tag (level 0) differs"); Assert.AreEqual(cpropPrev0, selectionHelper.GetLevelInfo(type)[0].cpropPrevious, "cpropPrev (level 0) differs"); Assert.AreEqual(ihvo0, selectionHelper.GetLevelInfo(type)[0].ihvo, "ihvo (level 0) differs"); }
/// ------------------------------------------------------------------------------------ /// <summary> /// This is called by a view when the views code is about to delete a paragraph. We /// need to save the back translations by moving them to whatever paragraph the deleted /// one is merging with. /// </summary> /// <param name="selHelper">The selection helper</param> /// <param name="hvoObject">Paragraph to be deleted</param> /// <param name="hvoOwner">StText that owns the para</param> /// <param name="tag">flid in which para is owned</param> /// <param name="ihvo">index of paragraph in text</param> /// <param name="fMergeNext"><c>true</c> if this paragraph is merging with the /// following paragraph.</param> /// ------------------------------------------------------------------------------------ public virtual void AboutToDelete(SelectionHelper selHelper, int hvoObject, int hvoOwner, int tag, int ihvo, bool fMergeNext) { CheckDisposed(); if (tag != (int)StText.StTextTags.kflidParagraphs) { return; } StTxtPara paraToDelete = new StTxtPara(m_cache, hvoObject); // If the paragraph that is being deleted is empty, then do not attempt to save a back // translation for it. if (paraToDelete.Contents.Text == null) { return; } // ihvoTop is either the paragraph before the IP or the first paragraph in a range selection int ihvoTop = ihvo - 1; int hvoOwnerSurviving = hvoOwner; // Figure out what is being deleted and what is staying. // NOTE: it is possible that the selection is no longer valid. This is ok for our purposes here, // since all information we access here is already retrieved and stored in member variables of // SelectionHelper. if (selHelper.IsRange) { int paraLev = selHelper.GetLevelForTag(tag, SelectionHelper.SelLimitType.Top); SelLevInfo[] rgSelLevInfo = selHelper.GetLevelInfo(SelectionHelper.SelLimitType.Top); ihvoTop = rgSelLevInfo[paraLev].ihvo; if (paraLev + 1 < rgSelLevInfo.Length) { hvoOwnerSurviving = rgSelLevInfo[paraLev + 1].hvo; } int ihvoBottom = selHelper.GetLevelInfoForTag(tag, SelectionHelper.SelLimitType.Bottom).ihvo; // Pretty sure that if we get here top will NEVER equal bottom. Debug.Assert(ihvoTop != ihvoBottom || hvoOwnerSurviving != hvoOwner); if (hvoOwnerSurviving == hvoOwner) { if (ihvoTop == ihvoBottom) { return; } int ichEnd = selHelper.GetIch(SelectionHelper.SelLimitType.Bottom); // No need to merge because entire paragraph (with its contents) is going away. if (ihvo == ihvoBottom && ichEnd == paraToDelete.Contents.Length) { return; } // No need to merge because entire paragraph (with its contents) is going away. if (ihvo > ihvoTop && ihvo < ihvoBottom) { return; } } } // Determine the surviving paragraph. StText text = new StText(m_cache, hvoOwnerSurviving); StTxtPara paraSurviving; if (fMergeNext) { // when merging with next and there are no more paragraphs, then the BT can be discarded. if (text.ParagraphsOS.Count < ihvo + 1) { return; } // The surviving paragraph will be the one following the one that is deleted paraSurviving = (StTxtPara)text.ParagraphsOS[ihvo + 1]; } else { // If we are deleting the first paragraph in the surviving text, the BT should // also be deleted, so we're done. if (ihvo == 0 && hvoOwnerSurviving == hvoOwner) { return; } // The surviving paragraph will be the top one in the selection paraSurviving = (StTxtPara)text.ParagraphsOS[ihvoTop]; } ITsStrBldr bldr; ILgWritingSystemFactory wsf; List <int> writingSystems = GetWsList(out wsf); foreach (ICmTranslation transToDelete in paraToDelete.TranslationsOC) { // Find or create surviving translation of the same type. ICmTranslation transSurviving = paraSurviving.GetOrCreateTrans(transToDelete.TypeRA); // Merge back translations of the surviving and paragraph to be deleted for each writing system foreach (int ws in writingSystems) { TsStringAccessor tssAccToDelete = transToDelete.Translation.GetAlternative(ws); if (tssAccToDelete.Text != null) { TsStringAccessor tssAccSurviving = transSurviving.Translation.GetAlternative(ws); bldr = tssAccSurviving.UnderlyingTsString.GetBldr(); // If the surviving paragraph ends with white space of the paragraph to delete // begins with white space, add white space. string textSurviving = bldr.Text; ILgCharacterPropertyEngine charPropEng = m_cache.UnicodeCharProps; if (textSurviving != null && !charPropEng.get_IsSeparator(textSurviving[textSurviving.Length - 1]) && !charPropEng.get_IsSeparator(tssAccToDelete.Text[0])) { bldr.ReplaceRgch(textSurviving.Length, textSurviving.Length, " ", 1, null); } int cch = bldr.Length; bldr.ReplaceTsString(cch, cch, tssAccToDelete.UnderlyingTsString); tssAccSurviving.UnderlyingTsString = bldr.GetString(); } } } }