/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Creates a simulated range selection
		/// </summary>
		/// <param name="hvoPara1"></param>
		/// <param name="hvoPara2"></param>
		/// <param name="ichAnchor"></param>
		/// <param name="ichEnd"></param>
		/// ------------------------------------------------------------------------------------
		public void SetupSelectionForParas(int hvoPara1, int hvoPara2, int ichAnchor, int ichEnd)
		{
			CheckDisposed();

			DynamicMock fakeSelHelper = new DynamicMock(typeof(SelectionHelper));
			fakeSelHelper.SetupResult("NumberOfLevels", 1);
			SelLevInfo[] topInfo = new SelLevInfo[1];
			topInfo[0].tag = StTextTags.kflidParagraphs;
			topInfo[0].hvo = hvoPara1;
			SelLevInfo[] bottomInfo = new SelLevInfo[1];
			bottomInfo[0].tag = StTextTags.kflidParagraphs;
			bottomInfo[0].hvo = hvoPara2;
			fakeSelHelper.SetupResult("LevelInfo", topInfo);
			fakeSelHelper.SetupResult("IchAnchor", ichAnchor);
			fakeSelHelper.SetupResult("IchEnd", ichEnd);
			fakeSelHelper.SetupResultForParams("GetLevelInfo", topInfo,
				SelectionHelper.SelLimitType.Top);
			fakeSelHelper.SetupResultForParams("GetLevelInfo", topInfo,
				SelectionHelper.SelLimitType.Anchor);
			fakeSelHelper.SetupResultForParams("GetLevelInfo", bottomInfo,
				SelectionHelper.SelLimitType.Bottom);
			fakeSelHelper.SetupResultForParams("GetLevelInfo", bottomInfo,
				SelectionHelper.SelLimitType.End);
			fakeSelHelper.SetupResultForParams("GetIch", ichAnchor,
				SelectionHelper.SelLimitType.Top);
			fakeSelHelper.SetupResultForParams("GetIch", ichEnd,
				SelectionHelper.SelLimitType.Bottom);
			m_currentSelection = (SelectionHelper)fakeSelHelper.MockInstance;
		}
		/// -----------------------------------------------------------------------------------
		/// <summary>
		/// Make one and hook it up to be called at the appropriate time.
		/// </summary>
		/// -----------------------------------------------------------------------------------
		public RequestSelectionHelper(IActionHandlerExtensions hookup, IVwRootBox rootb, int ihvoRoot,
			SelLevInfo[] rgvsli, int tagTextProp, int cpropPrevious, int ich, int wsAlt, bool fAssocPrev,
			ITsTextProps selProps)
		{
			m_hookup = hookup;
			m_rootb = rootb;
			m_ihvoRoot = ihvoRoot;
			m_rgvsli = rgvsli;
			m_tagTextProp = tagTextProp;
			m_cpropPrevious = cpropPrevious;
			m_ich = ich;
			m_wsAlt = wsAlt;
			m_fAssocPrev = fAssocPrev;
			m_selProps = selProps;
			m_hookup.DoAtEndOfPropChanged(m_hookup_PropChangedCompleted);
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Setup the selection in footnote.
		/// </summary>
		/// <param name="footnote">The footnote.</param>
		/// <param name="book">The book.</param>
		/// <param name="iBook">The 0-based index of the book.</param>
		/// <param name="ichStart">The 0-based starting character index.</param>
		/// <param name="ichEnd">The 0-based ending character index.</param>
		/// ------------------------------------------------------------------------------------
		public void SetupSelectionInFootnote(IStFootnote footnote, IScrBook book,
			int iBook, int ichStart, int ichEnd)
		{
			CheckDisposed();

			DynamicMock fakeSelHelper = new DynamicMock(typeof(SelectionHelper));
			fakeSelHelper.SetupResult("GetTextPropId", StTxtParaTags.kflidContents, typeof(SelectionHelper.SelLimitType));
			fakeSelHelper.SetupResult("NumberOfLevels", 3);
			// Setup the anchor
			SelLevInfo[] topInfo = new SelLevInfo[3];
			IStTxtPara para = footnote[0];
			topInfo[0].tag = StTextTags.kflidParagraphs;
			topInfo[0].ihvo = 0;	// only one para per footnote allowed
			topInfo[0].hvo = para.Hvo;

			topInfo[1].tag = ScrBookTags.kflidFootnotes;
			topInfo[1].ihvo = footnote.IndexInOwner;
			topInfo[1].hvo = footnote.Hvo;

			topInfo[2].tag = BookFilter.Tag;
			topInfo[2].ihvo = iBook;
			topInfo[2].hvo = book.Hvo;

			// Setup the end
			SelLevInfo[] bottomInfo = new SelLevInfo[3];
			for(int i = 0; i < 3; i++)
				bottomInfo[i] = topInfo[i];

			fakeSelHelper.SetupResult("LevelInfo", topInfo);
			fakeSelHelper.SetupResult("IchAnchor", ichStart);
			fakeSelHelper.SetupResult("IchEnd", ichEnd);
			fakeSelHelper.SetupResultForParams("GetLevelInfo", topInfo,
				SelectionHelper.SelLimitType.Top);
			fakeSelHelper.SetupResultForParams("GetLevelInfo", topInfo,
				SelectionHelper.SelLimitType.Anchor);
			fakeSelHelper.SetupResultForParams("GetLevelInfo", bottomInfo,
				SelectionHelper.SelLimitType.Bottom);
			fakeSelHelper.SetupResultForParams("GetLevelInfo", bottomInfo,
				SelectionHelper.SelLimitType.End);
			fakeSelHelper.SetupResultForParams("GetIch", ichStart,
				SelectionHelper.SelLimitType.Top);
			fakeSelHelper.SetupResultForParams("GetIch", ichEnd,
				SelectionHelper.SelLimitType.Bottom);
			m_currentSelection = (SelectionHelper)fakeSelHelper.MockInstance;
		}
		/// <summary>
		/// Sets up the tags for the 0 level of a selection of a free translation or note.
		/// This will be the level "inside" the ones that select the paragraph and segment.
		/// For a note, we need to select the first note.
		/// For a free translation, we need to insert the level for the 'self' property
		/// which the VC inserts to isolate the free translations and make it easier to update them.
		/// </summary>
		/// <param name="tagTextProp">The segment or note tag of an annotation to be selected.</param>
		private SelLevInfo MakeInnerLevelForFreeformSelection(int tagTextProp)
		{
			var noteLevel = new SelLevInfo();
			noteLevel.ihvo = 0;
			if (tagTextProp == NoteTags.kflidContent)
			{
				noteLevel.tag = SegmentTags.kflidNotes;
			}
			else
			{
				noteLevel.tag = Cache.MetaDataCacheAccessor.GetFieldId2(CmObjectTags.kClassId, "Self", false);
			}
			return noteLevel;
		}
		/// <summary>
		/// Select the first non-null translation or note in the current segment
		/// of the current analysis occurance.
		/// </summary>
		/// <returns>true if successful, false if there is no real translation or note</returns>
		internal bool SelectFirstTranslationOrNote()
		{
			int ws;
			int annotationFlid = GetFirstVisibleTranslationOrNoteFlid(SelectedOccurrence.Segment, out ws);
			if (annotationFlid == 0) return false;
			var sel = MakeSandboxSel();
			int clev = sel.CLevels(true);
			clev--; // result it returns is one more than what the AllTextSelInfo routine wants.
			SelLevInfo[] rgvsli;
			using (ArrayPtr rgvsliTemp = MarshalEx.ArrayToNative<SelLevInfo>(clev))
			{
				int ihvoRoot;
				int cpropPrevious;
				int ichAnchor;
				int ichEnd;
				int ihvoEnd1;
				int tag, ws1;
				bool fAssocPrev;
				ITsTextProps ttp;
				sel.AllTextSelInfo(out ihvoRoot, clev, rgvsliTemp, out tag, out cpropPrevious,
								   out ichAnchor, out ichEnd, out ws1, out fAssocPrev, out ihvoEnd1, out ttp);
				rgvsli = MarshalEx.NativeToArray<SelLevInfo>(rgvsliTemp, clev);
			}
			// What non-word "choice" ie., translation text or note is on this line?
			int tagTextProp = ConvertTranslationOrNoteFlidToSegmentFlid(annotationFlid, SelectedOccurrence.Segment, ws);
			int levels;
			SelLevInfo noteLevel = MakeInnerLevelForFreeformSelection(tagTextProp);
			var vsli = new SelLevInfo[3];
			vsli[0] = noteLevel; // note or translation line
			vsli[1] = rgvsli[0]; // segment
			vsli[2] = rgvsli[1]; // para
			int cPropPrevious = 0; // todo: other if not the first WS for tagTextProp
			TryHideFocusBoxAndUninstall();
			RootBox.MakeTextSelection(0, vsli.Length, vsli, tagTextProp, cPropPrevious,
									  0, 0, 0, false, -1, null, true);
			Focus();
			return true;
		}
		/// <summary>
		/// Gets the current selection and returns enough data to move the IP.
		/// </summary>
		/// <param name="clev">The number of levels of selection range results.</param>
		/// <param name="rgvsli">The selection range with clev levels of structure.</param>
		/// <param name="tag">The property of the bottom-level [0] object that is of interest.</param>
		/// <param name="ichAnchor">The start index of the text selection.</param>
		/// <param name="ichEnd">The end index of the text selection.</param>
		/// <param name="ws">Index of the writing system of the selection.</param>
		/// <returns>true if a selection was made, false if something prevented it.</returns>
		private bool GetCurrentSelection(out int clev, out SelLevInfo[] rgvsli, out int tag, out int ichAnchor, out int ichEnd, out int ws)
		{
			clev = -1;
			rgvsli = null;
			tag = -1;
			ichAnchor = -1;
			ichEnd = -1;
			ws = -1;
			var sel = EditingHelper.RootBoxSelection;
			if (sel == null)
				return false;
			// which "line choice" is active in this segment?
			if (sel.SelType != VwSelType.kstText || !sel.IsValid || !sel.IsEditable)
				return false;
			clev = sel.CLevels(true);
			ITsTextProps ttp;
			using (ArrayPtr rgvsliTemp = MarshalEx.ArrayToNative<SelLevInfo>(clev))
			{
				int ihvoRoot;
				int ihvoEnd1;
				int cpropPrevious;
				bool fAssocPrev;
				sel.AllTextSelInfo(out ihvoRoot, clev, rgvsliTemp, out tag, out cpropPrevious,
								   out ichAnchor, out ichEnd, out ws, out fAssocPrev, out ihvoEnd1, out ttp);
				rgvsli = MarshalEx.NativeToArray<SelLevInfo>(rgvsliTemp, clev);
			}
			return true;
		}
		public override void SelectionChanged(IVwRootBox rootb, IVwSelection vwselNew)
		{
			CheckDisposed();
			if (vwselNew == null)
				return;
			bool hasFoc = Focused;

			base.SelectionChanged(rootb, vwselNew);

			ITsString tss;
			int ichAnchor;
			bool fAssocPrev;
			int hvoObj;
			int tag;
			int ws; // NB: This will be 0 after each call, since the string does
			// not have alternatives. Ws would be the WS of an alternative,
			// if there were any.
			vwselNew.TextSelInfo(false, out tss, out ichAnchor, out fAssocPrev, out hvoObj,
				out tag, out ws);

			int ichEnd;
			int hvoObjEnd;
			vwselNew.TextSelInfo(true, out tss, out ichEnd, out fAssocPrev, out hvoObjEnd,
				out tag, out ws);

			if (hvoObjEnd != hvoObj)
			{
				CheckHeight();
				return;
			}
			if (m_hvoOldSelection > 0 && hvoObj != m_hvoOldSelection)
			{
				// Try to validate previously selected string rep.
				if (m_silCache.get_StringProp(m_hvoOldSelection, kEnvStringRep).Length==0)
				{
					// Remove it from the dummy cache, since its length is 0.
					int limit = m_silCache.get_VecSize(m_rootObj.Hvo, kMainObjEnvironments);
					for (int i = 0; i < limit; ++i)
					{
						if (m_hvoOldSelection ==
							m_silCache.get_VecItem(m_rootObj.Hvo, kMainObjEnvironments, i))
						{
							RemoveFromDummyCache(i);
							break;
						}
					}
				}
				else // Validate previously selected string rep.
				{
					ValidateStringRep(m_hvoOldSelection);
				}
			}
			if (hvoObj != kDummyPhoneEnvID)
			{
				m_hvoOldSelection = hvoObj;
				CheckHeight();
				return;
			}
			if (tss.Length == 0)
			{
				CheckHeight();
				return;
			}
			// Create a new object, and recreate a new empty object. Make this part of the Undo
			// Task with the character we typed.
			m_silCache.GetActionHandler().ContinueUndoTask();
			int count = m_silCache.get_VecSize(m_rootObj.Hvo, kMainObjEnvironments);
			int hvoNew = InsertNewEnv(count - 1);
			m_silCache.SetString(hvoNew, kEnvStringRep, tss);
			m_silCache.SetString(kDummyPhoneEnvID, kEnvStringRep, DummyString);
			m_silCache.EndUndoTask();
			// Refresh
			m_silCache.PropChanged(null, (int)PropChangeType.kpctNotifyAll,
				m_rootObj.Hvo, kMainObjEnvironments, count - 1, 2, 1);

			// Reset selection.
			SelLevInfo[] rgvsli = new SelLevInfo[1];
			rgvsli[0].cpropPrevious = 0;
			rgvsli[0].tag = kMainObjEnvironments;
			rgvsli[0].ihvo = count - 1;
			m_rootb.MakeTextSelection(0, rgvsli.Length, rgvsli, tag, 0, ichAnchor, ichEnd, ws,
				fAssocPrev, -1, null, true);

			m_hvoOldSelection = hvoNew;
			CheckHeight();
		}
		public IVwSelection MakeSelInObj(int ihvoRoot, int cvsli, SelLevInfo[] _rgvsli, int tag,
			bool fInstall)
		{
			throw new NotImplementedException();
		}
		public IVwSelection MakeTextSelection(int ihvoRoot, int cvlsi, SelLevInfo[] _rgvsli,
			int tagTextProp, int cpropPrevious, int ichAnchor, int ichEnd, int ws, bool fAssocPrev,
			int ihvoEnd, ITsTextProps _ttpIns, bool fInstall)
		{
			return new DummyVwSelection(this, ichAnchor, ichEnd);
		}
		protected override SelLevInfo[] GetLevelInfo(int cellId, int cellIndex)
		{
			SelLevInfo[] levels = null;
			switch (cellId)
			{
				case AffixRuleFormulaVc.ktagLeftEmpty:
				case AffixRuleFormulaVc.ktagRightEmpty:
					break;

				case MoAffixProcessTags.kflidOutput:
					if (cellIndex >= 0)
					{
						levels = new SelLevInfo[1];
						levels[0].tag = cellId;
						levels[0].ihvo = cellIndex;
					}
					break;

				default:
					var ctxtOrVar = m_cache.ServiceLocator.GetInstance<IPhContextOrVarRepository>().GetObject(cellId);
					if (cellIndex < 0 || ctxtOrVar.ClassID != PhSequenceContextTags.kClassId)
					{
						levels = new SelLevInfo[1];
						levels[0].tag = MoAffixProcessTags.kflidInput;
						levels[0].ihvo = ctxtOrVar.IndexInOwner;
					}
					else
					{
						levels = new SelLevInfo[2];
						levels[0].tag = PhSequenceContextTags.kflidMembers;
						levels[0].ihvo = cellIndex;
						levels[1].tag = MoAffixProcessTags.kflidInput;
						levels[1].ihvo = ctxtOrVar.IndexInOwner;
					}
					break;

			}
			return levels;
		}
			/// <summary>
			/// Reestablish a selection, if possible.
			/// </summary>
			public void MakeSel()
			{
				if (m_tagSel == -1)
					return;
				int clev = 2; // typically two level
				if (m_tagSel != ktagSbNamedObjName)
					clev--; // prefix and postfix are one level less embedded
				SelLevInfo[] rgsli = new SelLevInfo[clev];
				// The selection is in the morphemes of the root object
				rgsli[clev - 1].ihvo = m_ihvoSelMorph;
				rgsli[clev - 1].tag = ktagSbWordMorphs;
				if (clev > 1)
					rgsli[0].tag = ktagSbMorphForm; // leave other slots zero
				try
				{
					m_sandbox.RootBox.MakeTextSelection(
						m_sandbox.IndexOfCurrentItem, // which root,
						clev, rgsli,
						m_tagSel,
						0, // no previous occurrence
						m_ichSelOutput, m_ichSelOutput, m_wsVern,
						false, // needs to be false here to associate with trailing character
						// esp. for when the cursor is at the beginning of the morpheme (LT-7773)
						-1, // end not in different object
						null, // no special props to use for typing
						true); // install it.
				}
				catch (Exception)
				{
					// Ignore anything that goes wrong making a selection. At worst we just don't have one.
				}
			}
Beispiel #12
0
		public void GetParagraphProps()
		{
			CheckDisposed();

			// we want more paragraphs with different Hvos
			MakeEnglishParagraphs();

			ShowForm(Lng.English, DummyBasicViewVc.DisplayType.kNormal);
			IVwRootBox rootBox = m_basicView.RootBox;
			IVwSelection vwsel;
			int hvoText, tagText, ihvoFirst, ihvoLast;
			IVwPropertyStore[] vqvps;
			ITsTextProps[] vqttp;

			// Test 1: selection in one paragraph
			rootBox.MakeSimpleSel(false, true, false, true);
			IVwSelection sel = rootBox.Selection;
			ITsString tss;
			int ich, hvoObj, tag, ws;
			bool fAssocPrev;
			sel.TextSelInfo(true, out tss, out ich, out fAssocPrev, out hvoObj, out tag, out ws);
			int clev = sel.CLevels(true);
			clev--; // result it returns is one more than what the AllTextSelInfo routine wants.
			int ihvoRoot;
			int cpropPrevious;
			int ichAnchor;
			int ichEnd;
			int ihvoEnd1;
			ITsTextProps ttp;
			using (ArrayPtr rgvsliTemp = MarshalEx.ArrayToNative(clev, typeof(SelLevInfo)))
			{
				sel.AllTextSelInfo(out ihvoRoot, clev, rgvsliTemp, out tag, out cpropPrevious,
					out ichAnchor, out ichEnd, out ws, out fAssocPrev, out ihvoEnd1, out ttp);
				SelLevInfo[] rgvsli = (SelLevInfo[])MarshalEx.NativeToArray(rgvsliTemp, clev,
					typeof(SelLevInfo));
				int ichInsert = 0;
				rootBox.MakeTextSelection(ihvoRoot, clev, rgvsli, tag, cpropPrevious, ichInsert,
					ichInsert + 5, ws, fAssocPrev, ihvoEnd1, ttp, true);

				bool fRet = m_basicView.GetParagraphProps(out vwsel, out hvoText, out tagText,
					out vqvps, out ihvoFirst, out ihvoLast, out vqttp);

				Assert.IsTrue(fRet, "Test 1 ");
				Assert.AreEqual(ihvoFirst, ihvoLast, "Test 1 ");
				Assert.AreEqual(1, vqttp.Length, "Test 1 ");

				// Test 2: selection across two sections
				SelLevInfo[] rgvsliEnd = new SelLevInfo[clev];
				rgvsli.CopyTo(rgvsliEnd, 0);
				rgvsli[0].ihvo = 0; // first paragraph
				rgvsli[clev-1].ihvo = 2; // third section
				rootBox.MakeTextSelInObj(ihvoRoot, clev, rgvsli, clev, rgvsliEnd, false, true, true, true,
					true);

				fRet = m_basicView.GetParagraphProps(out vwsel, out hvoText, out tagText,
					out vqvps, out ihvoFirst, out ihvoLast, out vqttp);

				Assert.IsFalse(fRet, "Test 2 ");
			}
		}
Beispiel #13
0
		public void LoseFocusToView_RangeSel_FlagSet()
		{
			CheckDisposed();

			ShowForm(Lng.English, DummyBasicViewVc.DisplayType.kNormal);

			IVwRootBox rootBox = m_basicView.RootBox;
			rootBox.Activate(VwSelectionState.vssEnabled);
			m_basicView.ShowRangeSelAfterLostFocus = true;

			// Select the first four characters in the first paragraph
			SelLevInfo[] levelInfo = new SelLevInfo[2];
			levelInfo[1].tag = m_flidContainingTexts;
			levelInfo[1].cpropPrevious = 0;
			levelInfo[1].ihvo = 0;
			levelInfo[0].tag = (int)StText.StTextTags.kflidParagraphs;
			levelInfo[0].cpropPrevious = 0;
			levelInfo[0].ihvo = 0;
			rootBox.MakeTextSelection(0, 2, levelInfo,
				(int)StTxtPara.StTxtParaTags.kflidContents, 0, 0, 3, 0, true, 0, null, true);

			// Lets pretend we a different view gets the focus (although it's the same)
			m_basicView.KillFocus(m_basicView);

			Assert.IsTrue(rootBox.Selection.IsEnabled,
				"Selection should still be enabled if the ShowRangeSelAfterLostFocus flag is set");
		}
Beispiel #14
0
		public void LoseFocusToNonView_RangeSel()
		{
			CheckDisposed();

			ShowForm(Lng.English, DummyBasicViewVc.DisplayType.kNormal);

			IVwRootBox rootBox = m_basicView.RootBox;
			rootBox.Activate(VwSelectionState.vssEnabled);

			// Select the first four characters in the first paragraph
			SelLevInfo[] levelInfo = new SelLevInfo[2];
			levelInfo[1].tag = m_flidContainingTexts;
			levelInfo[1].cpropPrevious = 0;
			levelInfo[1].ihvo = 0;
			levelInfo[0].tag = (int)StText.StTextTags.kflidParagraphs;
			levelInfo[0].cpropPrevious = 0;
			levelInfo[0].ihvo = 0;
			rootBox.MakeTextSelection(0, 2, levelInfo,
				(int)StTxtPara.StTxtParaTags.kflidContents, 0, 0, 3, 0, true, 0, null, true);

			// We have to set up a form that contains the view and the control that we pretend
			// gets focus.
			using (Form parentForm = new Form())
			using (Control control = new Control())
			{
				m_basicView.Parent = parentForm;
				control.Parent = parentForm;
				// Lets pretend we a non-view gets the focus (although it's the same)
				m_basicView.KillFocus(control);

				Assert.IsTrue(rootBox.Selection.IsEnabled,
					"Selection should still be enabled if non-view window got focus");
			}
		}
Beispiel #15
0
		public void MergeBTsWhenParasMerge_FromMiddleOfPara1ToMiddleOfPara2_aKey()
		{
			CheckDisposed();

			ShowForm(Lng.English, DummyBasicViewVc.DisplayType.kNormal);

			IVwRootBox rootBox = m_basicView.RootBox;

			// Add a second paragraph to the first text and create some Back Translations on
			// both paragraphs
			ScrBook book = new ScrBook(Cache, m_hvoRoot);
			StText text1 = (StText)book.FootnotesOS[0];
			StTxtPara para1 = (StTxtPara)text1.ParagraphsOS[0];
			StTxtPara para2 = m_scrInMemoryCache.AddParaToMockedText(text1.Hvo, string.Empty);
			m_scrInMemoryCache.AddRunToMockedPara(para2, DummyBasicView.kSecondParaEng, m_wsEng);
			// We'll just re-use our "vernacular" WS for the back translation, for testing purposes.
			ICmTranslation trans1 = m_inMemoryCache.AddBtToMockedParagraph(para1, m_wsEng);
			m_inMemoryCache.AddRunToMockedTrans(trans1, m_wsEng, "BT1", null);
			ICmTranslation trans2 = m_inMemoryCache.AddBtToMockedParagraph(para2, m_wsEng);
			m_inMemoryCache.AddRunToMockedTrans(trans2, m_wsEng, "BT2", null);

			Cache.PropChanged(null, PropChangeType.kpctNotifyAll, text1.Hvo,
				(int)StText.StTextTags.kflidParagraphs, 1, 1, 0);

			// Make a selection from the end of first paragraph to the beginning of the second.
			SelLevInfo[] levelInfo = new SelLevInfo[2];
			levelInfo[1].tag = m_flidContainingTexts;
			levelInfo[1].cpropPrevious = 0;
			levelInfo[1].ihvo = 0;
			levelInfo[0].tag = (int)StText.StTextTags.kflidParagraphs;
			levelInfo[0].cpropPrevious = 0;
			levelInfo[0].ihvo = 0;
			int ichAnchor = DummyBasicView.kFirstParaEng.Length - 2;
			int ichEnd = 2;
			rootBox.MakeTextSelection(0, 2, levelInfo,
				(int)StTxtPara.StTxtParaTags.kflidContents, 0, ichAnchor, ichEnd, 0, true, 1, null,
				true);
			TypeChar('a');

			Assert.AreEqual(DummyBasicView.kFirstParaEng.Substring(0, ichAnchor) + "a" +
				DummyBasicView.kSecondParaEng.Substring(ichEnd), para1.Contents.Text);
			Assert.AreEqual("BT1 BT2", trans1.Translation.GetAlternative(m_wsEng).Text);
		}
		/// <summary>
		/// COPIED from INTERLINPRINTVIEW temporarily to (temporarily) preserve Print View functionality.
		/// </summary>
		/// <param name="rgvsli"></param>
		/// <returns></returns>
		private int FindBaseAnnInSelLevInfo(SelLevInfo[] rgvsli)
		{
			for (int i = 0; i < rgvsli.Length; i++)
			{
				int hvoAnn = rgvsli[i].hvo;
				if (hvoAnn > 0 && HvoIsRealBaseAnnotation(hvoAnn))
					return hvoAnn;
			}
			return 0;
		}
Beispiel #17
0
		/// -------------------------------------------------------------------------------------
		/// <summary>
		/// The layout manager is informed by this method that the (primary) layout stream 'lay'
		/// has determined that references to the objects objectGuids occur on the page. The input
		/// value of dysAvailHeight indicates how much of the height allocated to 'lay' for this
		/// page will remain available if the text containing these references is added to the
		/// page (assuming that adding them does not reduce the space available for 'lay').
		/// This is an alternative implementation of AddDependentObjects for the case where
		/// RootOnEachPage is true.
		/// </summary>
		/// <param name="lay">The primary layout stream filling the page</param>
		/// <param name="vg">The graphics object being used to layout the page</param>
		/// <param name="hPage">The handle to the page being laid out</param>
		/// <param name="cguid">Number of elements in objectGuids array</param>
		/// <param name="objectGuids">Array of GUIDS representing objects to be laid out in a
		/// separate layout stream</param>
		/// <param name="fAllowFail">Indicates whether this method can fail (return
		/// <c>fFailed == true</c>). If this is false, this method should force the requested
		/// objects to be laid out within the available space, even if it requires omitting or
		/// truncating some or all of them</param>
		/// <param name="fFailed">If the available height would become negative (typically
		/// because the objects must share space with 'lay' and they don't fit in the available
		/// height), this will be set to true (unless fAllowFail is false).</param>
		/// <param name="dysAvailHeight">Input value indicates how much of the height allocated
		/// to 'lay' for this page will remain available if the text containing these references
		/// is added to the page, assuming that adding them does not reduce the space available
		/// for 'lay'. The output value indicates how much is left after laying out these
		/// dependent objects.</param>
		/// -------------------------------------------------------------------------------------
		public virtual void AddDependentObjectsToPageRoot(IVwLayoutStream lay, IVwGraphics vg,
			int hPage, int cguid, Guid[] objectGuids, bool fAllowFail, out bool fFailed,
			ref int dysAvailHeight)
		{
			int dysAvailableHeight = dysAvailHeight;
			fFailed = false;

			int[] rgHvo = new int[cguid];
			int i = 0;
			foreach (Guid guid in objectGuids)
			{
				int hvo = m_configurer.GetIdFromGuid(guid);
				if (hvo != 0)
					rgHvo[i++] = hvo; // only add the ones we can match.
				else
					cguid--; // found unmatched guid
			}
			Page page = Publication.FindPage(hPage);
			if (page.DoingTrialLayout)
			{
				page.NoteDependentRoots(rgHvo);
				// note that we do not need to adjust dysAvailHeight, because in trial mode the
				// INITIAL height is set to the space available minus the old dependent root
				// objects view's height.
				return;
			}

			// Collect some information we need
			IVwLayoutStream dependentStream = page.DependentObjectsRootStream;
			IVwRootBox dependentRootbox = (IVwRootBox)dependentStream;
			int hvoRoot = m_configurer.DependentRootHvo;
			int dependentObjTag = m_configurer.DependentRootTag;
			int dependentObjFrag = m_configurer.DependentRootFrag;
			IDependentObjectsVc depObjVc;
			ISilDataAccess sda = m_configurer.DataAccess;
			int oldHeight = 0;
			int startIndex = -1;
			int endIndex = -1;
			int prevStartIndex;
			int prevEndIndex;
			if (dependentRootbox == null)
			{
				// no pre-existing rootbox for this page so create a new one
				depObjVc = m_configurer.DependentRootVc;
				dependentStream = VwLayoutStreamClass.Create();
				dependentStream.SetManager(this);
				page.DependentObjectsRootStream = dependentStream;
				dependentRootbox = (IVwRootBox)dependentStream;
				dependentRootbox.SetSite(Publication);
				dependentRootbox.DataAccess = sda;
				dependentRootbox.SetRootObject(hvoRoot, depObjVc, dependentObjFrag, m_configurer.StyleSheet);
				// Set up the view constructor to show the correct objects
				if (cguid > 0)
				{
					startIndex = sda.GetObjIndex(hvoRoot, dependentObjTag, rgHvo[0]);
					endIndex = sda.GetObjIndex(hvoRoot, dependentObjTag, rgHvo[cguid - 1]);
					Debug.Assert(startIndex >= 0 && endIndex >= 0);
				}
				depObjVc.StartingObjIndex = startIndex;
				depObjVc.EndingObjIndex = endIndex;
				prevStartIndex = prevEndIndex = -1;
			}
			else
			{
				// A rootbox was already created for this page, just update what is shown
				oldHeight = dependentRootbox.Height;
				IVwViewConstructor vc;
				IVwStylesheet ss;
				dependentRootbox.GetRootObject(out hvoRoot, out vc, out dependentObjFrag, out ss);
				depObjVc = (IDependentObjectsVc)vc;

				prevStartIndex = depObjVc.StartingObjIndex;
				prevEndIndex = depObjVc.EndingObjIndex;
				// Update the view constructor with the new objects
				if (cguid > 0)
				{
					startIndex = sda.GetObjIndex(hvoRoot, dependentObjTag, rgHvo[0]);
					endIndex = sda.GetObjIndex(hvoRoot, dependentObjTag, rgHvo[cguid - 1]);
					Debug.Assert(startIndex >= 0 && endIndex >= 0);
					Debug.Assert(startIndex > depObjVc.EndingObjIndex && endIndex > depObjVc.EndingObjIndex);

					if (depObjVc.StartingObjIndex == -1)
					{
						// Most likely all the shown objects were removed from the view constructor.
						// We need to make sure we have a valid starting index.
						depObjVc.StartingObjIndex = startIndex;
					}
					depObjVc.EndingObjIndex = endIndex;
				}
			}

			if (startIndex < 0 || endIndex < 0)
			{
				fFailed = fAllowFail;
				return;
			}

			// update the rootbox with the new items.
			try
			{
				// propChanged generates a PageBroken notification we need to ignore.
				m_hPageBeingBuilt = hPage;
				int count = endIndex - startIndex + 1;
				dependentRootbox.PropChanged(hvoRoot, dependentObjTag, startIndex, count, count);
			}
			finally
			{
				m_hPageBeingBuilt = 0;
			}

			PublicationControl.SetAccessibleStreamName(dependentStream,
				"Dependent stream for page " + page.PageNumber);

			// The actual laying out is probably redundant, but this lets the dependent stream
			// know what page it's on, which is useful for notifications. With an interface
			// change we could do this more efficiently, I think.
			for (int ihvo = startIndex; ihvo <= endIndex; ihvo++)
			{
				SelLevInfo[] rgSelLevInfo = new SelLevInfo[1];
				rgSelLevInfo[0].tag = dependentObjTag;
				rgSelLevInfo[0].ihvo = ihvo - depObjVc.StartingObjIndex;

				dependentStream.LayoutObj(vg, AvailablePageWidthInPrinterPixels, 0,
					rgSelLevInfo.Length, rgSelLevInfo, hPage);
			}
			int newHeight = dependentRootbox.Height;
			int dysHeightUsed = newHeight - oldHeight;

			// If this stream is just now being added to the page, need to allow for gap between elements.
			if (oldHeight == 0)
				dysHeightUsed += VerticalGapBetweenElements * vg.YUnitsPerInch / MiscUtils.kdzmpInch;

			if ((dysHeightUsed * m_numberMainStreamColumns) > dysAvailHeight)
			{
				// We can't add everything needed for the current chunk (in the main stream),
				// so we need to fail (if that's permitted), and roll everything back
				if (fAllowFail)
				{
					fFailed = true;
					// roll back: remove the extra objects.
					try
					{
						int newStartObjIndex = depObjVc.StartingObjIndex;
						int newEndObjIndex = depObjVc.EndingObjIndex;

						depObjVc.StartingObjIndex = prevStartIndex;
						depObjVc.EndingObjIndex = prevEndIndex;
						int count = endIndex - newStartObjIndex + 1;
						dependentRootbox.PropChanged(hvoRoot, dependentObjTag, newStartObjIndex, count, count);
					}
					finally
					{
						m_hPageBeingBuilt = 0;
					}
					return;
				}
				else
					dysAvailableHeight = 0;
			}
			else
			{
				// When we layout with multiple columns, we pretend to have one large
				// page. But the substreams are still only one column which means
				// they affect all columns, so we have to multiply the height used
				// with the number of columns.
				dysAvailableHeight -= (dysHeightUsed * m_numberMainStreamColumns);
			}

			// Now we know all the objects fit (or else we weren't allowed to fail), so
			// adjust the rectangle occupied by the element.

			// First time thru, the previous "element" is the bottom page margin.
			// So far we only have one, but the code here shows vestiges of the loop in the
			// main AddDependentObjects.
			int ysTopOfPrevElement = Publication.PageHeightInPrinterPixels - BottomMarginInPrinterPixels;
			if (newHeight > 0)
				AddOrAdjustPageElement(page, ysTopOfPrevElement, newHeight, dependentStream, 0);

			dysAvailHeight = dysAvailableHeight;
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// If we need to make a selection, but we can't because edits haven't been updated in the
		/// view, this method requests creation of a selection after the unit of work is complete.
		/// Specifically, when all PropChanged calls have been made for the UOW.
		/// The arguments are as for MakeTextSelection, except that we only include the ones
		/// necessary to specify an insertion point, and of course don't return the selection,
		/// which typically won't be made until later. The selection made is always installed.
		/// </summary>
		/// ------------------------------------------------------------------------------------
		public void RequestSelectionAtEndOfUow(IVwRootBox rootb, int ihvoRoot, int cvlsi,
			SelLevInfo[] rgvsli, int tagTextProp, int cpropPrevious, int ich, int wsAlt,
			bool fAssocPrev, ITsTextProps selProps)
		{
			// Creating one hooks it up; it will free itself when invoked.
			new RequestSelectionHelper((IActionHandlerExtensions)m_cache.ActionHandlerAccessor,
				rootb, ihvoRoot, rgvsli, tagTextProp, cpropPrevious, ich, wsAlt, fAssocPrev, selProps);

			// We don't want to continue using the old, out-of-date selection.
			rootb.DestroySelection();
		}
		public IVwSelection MakeTextSelInObj(int ihvoRoot, int cvsli, SelLevInfo[] _rgvsli,
			int cvsliEnd, SelLevInfo[] _rgvsliEnd, bool fInitial, bool fEdit, bool fRange,
			bool fWholeObj, bool fInstall)
		{
			throw new NotImplementedException();
		}
		public void UpdateGoToSubItems_EnabledWhenRequiredSelectionIsPresent()
		{
			CheckDisposed();

			m_mainWnd.m_mockedBookFilter.SetupResult("BookCount", 1);
			DynamicMock sel = new DynamicMock(typeof(IVwSelection));
			DynamicMock selHelper = new DynamicMock(typeof(SelectionHelper));
			SelLevInfo[] levInfo = new SelLevInfo[1];
			selHelper.SetupResult("LevelInfo", levInfo);

			selHelper.SetupResult("Selection", sel.MockInstance);
			m_mainWnd.m_mockedEditingHelper.SetupResult("CurrentSelection", selHelper.MockInstance);

			Assert.IsTrue(m_mainWnd.UpdateGoToSubItems(m_dummyItemProps, true));

			Assert.IsTrue(m_dummyItemProps.Enabled,
				"Go to Prev/Next subitem should be enabled when there is a selection.");
		}
Beispiel #21
0
		/// <summary>
		/// print root sites are never used for editing, so this routine should never be called.
		/// </summary>
		public void RequestSelectionAtEndOfUow(IVwRootBox _rootb, int ihvoRoot, int cvlsi,
			SelLevInfo[] rgvsli, int tagTextProp, int cpropPrevious, int ich, int wsAlt,
			bool fAssocPrev, ITsTextProps selProps)
		{
			throw new NotImplementedException();
		}
			public override void SelectionChanged(IVwRootBox rootb, IVwSelection vwselNew)
			{
				CheckDisposed();

				if (vwselNew == null)
					return;

				base.SelectionChanged(rootb, vwselNew);

				ITsString tss;
				int ichAnchor;
				bool fAssocPrev;
				int hvoObj;
				int tag;
				int ws;
				vwselNew.TextSelInfo(false, out tss, out ichAnchor, out fAssocPrev, out hvoObj, out tag, out ws);
				int ichEnd;
				int hvoObjEnd;
				vwselNew.TextSelInfo(true, out tss, out ichEnd, out fAssocPrev, out hvoObjEnd, out tag, out ws);
				if (hvoObjEnd != hvoObj)
				{
					// Can't do much with a multi-object selection.
					CheckHeight();
					return;
				}

				// The next level out in the view should be the entry in the index.
				int hvoIndex, ihvoEntry, cpropPrevious, tagEntry;
				IVwPropertyStore vps;
				vwselNew.PropInfo(false, 1, out hvoIndex, out tagEntry, out ihvoEntry, out cpropPrevious, out vps);
				// And the next one is the relevant index.
				int hvoSense, tagIndex, ihvoIndex;
				vwselNew.PropInfo(false, 2, out hvoSense, out tagIndex, out ihvoIndex, out cpropPrevious, out vps);

				int count = m_silCache.get_VecSize(hvoIndex, kFlidEntries);
				int lastEntryHvo = m_silCache.get_VecItem(hvoIndex, kFlidEntries, count - 1);

				//string oldForm = m_silCache.get_UnicodeProp(m_hvoOldSelection, (int)ReversalIndexEntry.ReversalIndexEntryTags.kflidForm);
				string oldForm = null;
				int wsIndex = m_silCache.get_IntProp(hvoIndex, (int)ReversalIndex.ReversalIndexTags.kflidWritingSystem);
				ITsString tssEntry = m_silCache.get_MultiStringAlt(m_hvoOldSelection,
					(int)ReversalIndexEntry.ReversalIndexEntryTags.kflidReversalForm, wsIndex);
				if (tssEntry != null)
					oldForm = tssEntry.Text;
				if (m_hvoOldSelection != 0
					&& hvoObj != m_hvoOldSelection
					&& (oldForm == null || oldForm.Length  == 0))
				{
					// Remove the old string from the dummy cache, since its length is 0.
					for (int i = 0; i < count; ++i)
					{
						if (m_hvoOldSelection == m_silCache.get_VecItem(hvoIndex, kFlidEntries, i))
						{
							RemoveFromDummyCache(hvoIndex, i);
							break;
						}
					}
				}
				// If it's not the last index in the list, we can just go on editing it.
				if (hvoObj != lastEntryHvo)
				{
					m_hvoOldSelection = hvoObj;
					CheckHeight();
					return;
				}
				// Even if it's the last object, if it's empty we don't need to do anything.
				if (tss.Length == 0)
				{
					CheckHeight();
					return;
				}
				// Create a new object, and recreate a new empty object.
				count = m_silCache.get_VecSize(hvoIndex, kFlidEntries);
				// Assign a new dummy ID.
				m_dummyId--;
				// Insert it at the end of the list.
				m_vwCache.CacheReplace(hvoIndex, kFlidEntries, count, count, new int[] {m_dummyId}, 1);
				Cache.EnableUndo = false;	// Things have changed in a way we can't Undo.
				// Set its 'form' to be an empty string in the appropriate writing system.
				ITsTextProps props = tss.get_PropertiesAt(0);
				int nVar;
				ws = props.GetIntPropValues((int)FwTextPropType.ktptWs, out nVar);
				//m_vwCache.CacheUnicodeProp(m_dummyId, (int)ReversalIndexEntry.ReversalIndexEntryTags.kflidForm, String.Empty, 0);
				//m_vwCache.CacheIntProp(m_dummyId, (int)ReversalIndexEntry.ReversalIndexEntryTags.kflidWritingSystem, ws);
				ITsString tssEmpty = m_tsf.MakeString("", ws);
				m_vwCache.CacheStringAlt(m_dummyId, (int)ReversalIndexEntry.ReversalIndexEntryTags.kflidReversalForm,
					ws, tssEmpty);
				// Refresh
				m_silCache.PropChanged(null, (int)PropChangeType.kpctNotifyAll,
					hvoIndex, kFlidEntries, count, 1, 0);

				// Reset selection.
				SelLevInfo[] rgvsli = new SelLevInfo[2];
				rgvsli[0].cpropPrevious = 0;
				rgvsli[0].tag = kFlidEntries;
				rgvsli[0].ihvo = count - 1;
				rgvsli[1].cpropPrevious = 0;
				rgvsli[1].tag = kFlidIndices;
				rgvsli[1].ihvo = ihvoIndex;
				try
				{
					m_rootb.MakeTextSelection(0, rgvsli.Length, rgvsli, tag, 0, ichAnchor, ichEnd, ws, fAssocPrev, -1, null, true);
				}
				catch (Exception e)
				{
					Debug.WriteLine(e.ToString());
					throw;
				}

				m_hvoOldSelection = hvoObj;
				CheckHeight();
			}
		/// <summary>
		/// Retrieves the selected objects and data from the selection range.
		/// </summary>
		/// <param name="clev">The number of levels of selection range results.</param>
		/// <param name="rgvsli">The selection range with clev levels of structure.</param>
		/// <param name="tag">The property of the bottom-level [0] object that is of interest.</param>
		/// <param name="curParaIndex">The index of the paragraph containing the selected text.</param>
		/// <param name="curSegIndex">The index of the segment containing the selected text.</param>
		/// <param name="curNoteIndex">if tag indicates a note, the note index in its segment sequence otherwise -1.</param>
		/// <param name="curSeg">The selected segment object</param>
		/// <param name="curNote">The selected note object or null if curNoteIndex is -1.</param>
		private void GetCurrentTextObjects(int clev, SelLevInfo[] rgvsli, int tag, out int curParaIndex, out int curSegIndex, out int curNoteIndex, out ISegment curSeg, out INote curNote)
		{
			curParaIndex = rgvsli[clev - 2].ihvo;
			var curPara = (IStTxtPara)RootStText.ParagraphsOS[curParaIndex];
			Debug.Assert(curPara != null, "Moving from a non-exisiting paragraph in interlinear Doc.");
			curSegIndex = rgvsli[clev - 3].ihvo;
			curSeg = curPara.SegmentsOS[curSegIndex];
			Debug.Assert(curSeg != null, "Moving from a non-exisiting segment in interlinear Doc.");
			curNote = null;
			curNoteIndex = -1;
			if (tag == NoteTags.kflidContent)
			{
				//if clev == 5 then we have both a Free Translation and some number of Notes
				//otherwise I assume we have only a Free Translation if clev == 4
				if (clev == 5)
				{
					curNoteIndex = rgvsli[0].ihvo; //if there are multiple Notes the index could be more than 0
					curNote = curSeg.NotesOS[curNoteIndex];
				}
			}
		}
		private bool TryGetWficLevelsAndEndLevels(IVwSelection vwselNew, out SelLevInfo[] wficLevels, out SelLevInfo[] endLevels)
		{
			endLevels = null;
			wficLevels = GetWficLevelsFromSelection(vwselNew);
			if (wficLevels == null)
				return false;

			SelLevInfo[] rgvsliEnd = GetOneEndPointOfSelection(vwselNew, true);

			// wficLevels[0] contains info about the sequence of wfics property. We want the corresponding
			// level in rgvsliEnd to have the same tag but not necessarily the same ihvo.
			// All the higher levels should be exactly the same. The loop checks this, and if successful
			// sets iend to the index of the property correponding to wficLevels[0].
			endLevels = null;
			int iend;
			if (AreHigherLevelsSameObject(wficLevels, rgvsliEnd, out iend))
			{
				endLevels = wficLevels.Clone() as SelLevInfo[];
				endLevels[0] = new SelLevInfo(); // clone is SHALLOW; don't modify element of wficLevels.
				endLevels[0].ihvo = rgvsliEnd[iend].ihvo;
				endLevels[0].tag = wficLevels[0].tag;
			}
			return endLevels != null;
		}
		public void AddNote(Command command)
		{
			IVwSelection sel = MakeSandboxSel();
			// If there's no sandbox selection, there may be one in the site itself, perhaps in another
			// free translation.
			if (sel == null && RootBox != null)
				sel = RootBox.Selection;
			if (sel == null)
				return; // Enhance JohnT: give an error, or disable the command.
			int cvsli = sel.CLevels(false);
			cvsli--; // CLevels includes the string property itself, but AllTextSelInfo doesn't need it.

			// Out variables for AllTextSelInfo.
			int ihvoRoot;
			int tagTextProp;
			int cpropPrevious;
			int ichAnchor;
			int ichEnd;
			int ws;
			bool fAssocPrev;
			int ihvoEnd;
			ITsTextProps ttpBogus;
			// Main array of information retrived from sel that made combo.
			SelLevInfo[] rgvsli = SelLevInfo.AllTextSelInfo(sel, cvsli,
				out ihvoRoot, out tagTextProp, out cpropPrevious, out ichAnchor, out ichEnd,
				out ws, out fAssocPrev, out ihvoEnd, out ttpBogus);

			// Identify the segment.
			// This is important because although we are currently displaying just an StTxtPara,
			// eventually it might be part of a higher level structure. We want this to work
			// no matter how much higher level structure there is.
			int itagSegments = -1;
			for (int i = rgvsli.Length; --i >= 0; )
			{
				if (rgvsli[i].tag == StTxtParaTags.kflidSegments)
				{
					itagSegments = i;
					break;
				}
			}
			if (itagSegments == -1)
				return; // Enhance JohnT: throw? disable command? Give an error?

			int hvoSeg = rgvsli[itagSegments].hvo;
			var seg = Cache.ServiceLocator.GetObject(hvoSeg) as ISegment;
			UndoableUnitOfWorkHelper.Do(command.UndoText, command.RedoText, Cache.ActionHandlerAccessor,
				() =>
				{
					var note = Cache.ServiceLocator.GetInstance<INoteFactory>().Create();
					seg.NotesOS.Add(note);
				});

			TryHideFocusBoxAndUninstall();
			if (m_vc.LineChoices.IndexOf(InterlinLineChoices.kflidNote) < 0)
			{
				m_vc.LineChoices.Add(InterlinLineChoices.kflidNote);
				PersistAndDisplayChangedLineChoices();
			}

			// Now try to make a new selection in the note we just made.
			// The elements of rgvsli from itagSegments onwards form a path to the segment.
			// In the segment we want the note propery, specifically the new one we just made.
			// We want to select at the start of it.
			// LT-12613: We're adding an extra segment here:
			SelLevInfo[] rgvsliNew = new SelLevInfo[rgvsli.Length - itagSegments + 2];
			for (int i = 2; i < rgvsliNew.Length; i++)
				rgvsliNew[i] = rgvsli[i + itagSegments - 2];
			rgvsliNew[0].ihvo = seg.NotesOS.Count - 1;
			rgvsliNew[0].tag = SegmentTags.kflidNotes;
			rgvsliNew[0].cpropPrevious = 0;
			// LT-12613: Define extra segment here:
			rgvsliNew[1].ihvo = 0;
			rgvsliNew[1].tag = Cache.MetaDataCacheAccessor.GetFieldId2(CmObjectTags.kClassId, "Self", false);
			rgvsliNew[1].cpropPrevious = 0;
			RootBox.MakeTextSelInObj(0, rgvsliNew.Length, rgvsliNew, 0, null, true, true, false, false, true);
			// Don't steal the focus from another window.  See FWR-1795.
			if (ParentForm == Form.ActiveForm)
				Focus(); // So we can actually see the selection we just made.
		}
		/// <summary>
		/// Updates the list of selected wfics as well as the current StTxtPara.
		/// </summary>
		/// <param name="wficLevels">The wfic levels.</param>
		/// <param name="iend">The iend.</param>
		private List<int> GetSelectedWfics(SelLevInfo[] wficLevels, int iend)
		{
			int hvoSegment = wficLevels[1].hvo;
			int flidWfics = wficLevels[0].tag;

			int ianchor = wficLevels[0].ihvo;

			// These two lines are in case the user selects "backwards"
			int first = Math.Min(ianchor, iend);
			int last = Math.Max(ianchor, iend);

			List<int> selectedWfics = new List<int>();
			for (int i = first; i <= last; i++)
				selectedWfics.Add(Cache.GetVectorItem(hvoSegment, flidWfics, i));
			return selectedWfics;
		}
		/// <summary>
		/// Return the first non-null translation or note selection in the specified segment.
		/// The segment does not need to be the current occurance.
		/// </summary>
		/// <param name="segment">A valid segment.</param>
		/// <returns>The selection or null if there is no real translation or note.</returns>
		internal IVwSelection SelectFirstTranslationOrNote(ISegment segment)
		{
			if (segment == null)
				return null;
			int ws;
			int annotationFlid = GetFirstVisibleTranslationOrNoteFlid(segment, out ws);
			if (annotationFlid == 0)
				return null;
			int tagTextProp = ConvertTranslationOrNoteFlidToSegmentFlid(annotationFlid, segment, ws);
			SelLevInfo noteLevel = MakeInnerLevelForFreeformSelection(tagTextProp);
			// notes and translation lines have 3 levels: 2:para, 1:seg, 0:content or self property
			var vsli = new SelLevInfo[3];
			vsli[0] = noteLevel;  // note or translation line
			vsli[1].ihvo = segment.IndexInOwner; // specifies where segment is in para
			vsli[1].tag = StTxtParaTags.kflidSegments;
			vsli[2].ihvo = segment.Paragraph.IndexInOwner; // specifies where para is in IStText.
			vsli[2].tag = StTextTags.kflidParagraphs;
			int cPropPrevious = 0; // todo: other if not the first WS for tagTextProp
			var sel = RootBox.MakeTextSelection(0, vsli.Length, vsli, tagTextProp, cPropPrevious,
												0, 0, 0, false, 0, null, true);
			Focus();
			TryHideFocusBoxAndUninstall();
			return sel;
		}
		private static SelLevInfo[] GetWficLevelsFromSelLevInfo(SelLevInfo[] rgvsli)
		{
			if (rgvsli == null)
				return null;
			int itagWfic = GetWfiAnalysisIndexInSelLevInfoArray(rgvsli) + 1;
			if (itagWfic <= 0)
				return null;
			SelLevInfo[] result = new SelLevInfo[rgvsli.Length - itagWfic];
			Array.Copy(rgvsli, itagWfic, result, 0, rgvsli.Length - itagWfic);
			return result;
		}
		/// <summary>
		/// Overridden for subclasses needing a Sandbox.
		/// </summary>
		/// <param name="rgvsli"></param>
		/// <returns></returns>
		protected override IVwSelection MakeWordformSelection(SelLevInfo[] rgvsli)
		{
			// top prop is atomic, leave index 0. Specifies displaying the contents of the Text.
			IVwSelection sel;
			try
			{
				// This is fine for InterlinDocForAnalysis, since it treats the area that the sandbox
				// will fill as a picture. Not so good for panes (see above).
				sel = RootBox.MakeSelInObj(0, rgvsli.Length, rgvsli, 0, false);
			}
			catch (Exception e)
			{
				Debug.WriteLine(e.StackTrace);
				return null;
			}
			return sel;
		}
		private static bool AreHigherLevelsSameObject(SelLevInfo[] wficLevels, SelLevInfo[] rgvsliEnd, out int iend)
		{
			iend = rgvsliEnd.Length - 1;
			for (int ianchor = wficLevels.Length - 1; ianchor > 0 && iend >= 0; ianchor--, iend--)
			{
				if (rgvsliEnd[iend].tag != wficLevels[ianchor].tag)
					return false;
				if (rgvsliEnd[iend].ihvo != wficLevels[ianchor].ihvo)
					return false;
			}
			if (iend < 0)
				return false; // not enough levels in the end selection, very unlikely.
			if (wficLevels[0].tag != rgvsliEnd[iend].tag)
				return false;
			return true;
		}