示例#1
0
		private static int GetWfiAnalysisFromWficInstanceOf(FdoCache cache, int hvoInstanceOf, out int hvoWordform)
		{
			hvoWordform = 0;
			int hvoWfiAnalysis = 0;
			int classid = cache.GetClassOfObject(hvoInstanceOf);
			switch (classid)
			{
				case WfiWordform.kclsidWfiWordform:
					hvoWordform = hvoInstanceOf;
					return 0;  // need use or make a guess for analysis
				case WfiAnalysis.kclsidWfiAnalysis:
					hvoWfiAnalysis = hvoInstanceOf;
					break;
				case WfiGloss.kclsidWfiGloss:
					hvoWfiAnalysis = cache.GetOwnerOfObject(hvoInstanceOf);
					break;
				default:
					throw new ArgumentException("cba.InstanceOf(" + hvoInstanceOf + ") class(" +
							   classid + ") is not WfiWordform, WfiAnalysis, or WfiGloss.");
			}
			return hvoWfiAnalysis;
		}
示例#2
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Refreshes cache for all footnotes in the StText containing the paragraph.  We only
		/// use this method when verses of a paragraph are changed - this will only happen on
		/// content paragraphs of a ScrSection.
		/// </summary>
		/// <param name="cache"></param>
		/// <param name="hvoObj"></param>
		/// ------------------------------------------------------------------------------------
		internal static void RefreshCacheForParagraph(FdoCache cache, int hvoObj)
		{
			int hvoPara = hvoObj;
			if (cache.GetClassOfObject(hvoObj) == CmTranslation.kClassId)
				hvoPara = cache.GetOwnerOfObject(hvoObj);

			int hvoText = cache.GetOwnerOfObject(hvoPara);
			IStText text = new StText(cache, hvoText);
			ScrSection section = new ScrSection(cache, text.OwnerHVO);
			BCVRef verseRef = new BCVRef(section.VerseRefStart);

			Dictionary<int, FootnoteHashEntry> dict;
			// Don't bother on empty cache - it will be created when needed. Need to use HVO to get GUID so we
			// don't create the book and potentially cause the refresh routine to be called.
			Guid bookGuid = cache.GetGuidFromId(section.OwnerHVO);
			if (!cache.TryGetHashtable<int, FootnoteHashEntry>(bookGuid, out dict) ||
				dict.Count == 0)
			{
				return;
			}

			AddFootnoteRefsInText(text, dict, ref verseRef);
		}
示例#3
0
		/// <summary>
		/// Get a wordform from an HVO that may be a WfiWordform, WfiAnalysis, or WfiGloss (or 0).
		/// Answer 0 if arguent is zero, fail if it is some other class.
		/// </summary>
		public static int GetWordformFromWag(FdoCache cache, int cbaInstanceOf)
		{
			int hvoWordform = 0;
			if (cbaInstanceOf != 0)
			{
				int classid = cache.GetClassOfObject(cbaInstanceOf);
				switch (classid)
				{
					case WfiWordform.kclsidWfiWordform:
						hvoWordform = cbaInstanceOf;
						break;
					case WfiAnalysis.kclsidWfiAnalysis:
						hvoWordform = cache.GetOwnerOfObject(cbaInstanceOf);
						break;
					case WfiGloss.kclsidWfiGloss:
						int hvoAnalysis = cache.GetOwnerOfObject(cbaInstanceOf);
						hvoWordform = cache.GetOwnerOfObject(hvoAnalysis);
						break;
					default:
						Debug.Fail("Actual cba (" + cbaInstanceOf + "): Class of InstanceOf (" +
								   classid + ") is not WfiWordform, WfiAnalysis, or WfiGloss.");
						break;
				}
			}
			return hvoWordform;
		}
示例#4
0
		/// <summary>
		/// Checks for and reports any disallowed discourse template moves.
		/// </summary>
		/// <param name="cache"></param>
		/// <param name="movingColumn">The proposed possibility item (template column) to move.</param>
		/// <param name="hvoTemplate">The hvo of the affected Chart Template (only 'default' exists so far).</param>
		/// <param name="hvoTemplateList">The hvo of the Template List.</param>
		/// <param name="hvoDest">The hvo of the destination item.</param>
		/// <returns>true means we found and reported a bad move.</returns>
		private bool CheckAndReportBadDiscourseTemplateMove(FdoCache cache, CmPossibility movingColumn, int hvoTemplate,
			int hvoTemplateList, int hvoDest)
		{
			// First, check whether we're allowed to manipulate this column at all. This is the same check as
			// whether we're allowed to delete it.
			if (movingColumn.CheckAndReportProtectedChartColumn())
				return true;
			// Other things being equal, we now need to make sure we aren't messing up the chart levels
			// Unless something is badly wrong, the destination is either the root template,
			// a column group one level down from the root template, a column two levels down,
			// or the base list.
			if (hvoDest == hvoTemplateList)
			{
				MessageBox.Show(m_tree, xWorksStrings.ksCantPromoteGroupToTemplate,
								xWorksStrings.ksProhibitedMovement, MessageBoxButtons.OK, MessageBoxIcon.Warning);
				return true;
			}
			// if the destination IS the root, that's fine...anything can move there.
			if (hvoDest == hvoTemplate)
				return false;
			// It's OK to move a leaf to a group (one level down from the root, as long as
			// the destination 'group' isn't a column that's in use.
			bool moveColumnIsLeaf = movingColumn.SubPossibilitiesOS.Count == 0;
			if (cache.GetOwnerOfObject(hvoDest) == hvoTemplate && moveColumnIsLeaf)
			{
				CmPossibility dest = (CmPossibility.CreateFromDBObject(cache, hvoDest))
									 as CmPossibility;
				// If it isn't already a group, we can only turn it into one if it's empty
				if (dest.SubPossibilitiesOS.Count == 0)
					return dest.CheckAndReportProtectedChartColumn();
				// If it's already a group it should be fine as a destination.
				return false;
			}
			// Anything else represents an attempt to make the tree too deep, e.g., moving a
			// column into child column, or a group into another group.
			MessageBox.Show(m_tree, xWorksStrings.ksTemplateTooDeep,
							xWorksStrings.ksProhibitedMovement, MessageBoxButtons.OK, MessageBoxIcon.Warning);
			return true;
		}
示例#5
0
		// Is hvoAnn, currently analyzed as hvoAnalysis, fully analyzed?
		// This means:
		//  -- it isn't a default (property InterlinVc.m_vc.ktagTwficDefault isn't cached)
		//  -- It's a WfiGloss, with non-empty form.
		//  -- Owner is a WfiAnalysis with non-empty Category.
		//  -- Owner has at least one WfiMorphBundle.
		//  -- For each WfiMorphBundle, Form, Msa, and Sense are all filled in.
		// Alternatively, if hvoAnalysis is zero, the annotation is punctuation, which we don't analyze further;
		// so return true to indicate that it needs no further attention.
		internal bool FullyAnalyzed(FdoCache fdoCache, WsListManager listman, int hvoAnn, int hvoAnalysis)
		{
			int ktagTwficDefault = StTxtPara.TwficDefaultFlid(fdoCache);
			if (hvoAnalysis == 0)
				return true; // punctuation, treat as fully analyzed.
			ISilDataAccess sda = fdoCache.MainCacheAccessor;
			// Check for default. If the analysis we're showing is a default it needs at least confirmation.
			if (sda.get_IsPropInCache(hvoAnn, ktagTwficDefault, (int)CellarModuleDefns.kcptReferenceAtom, 0)
				&& sda.get_ObjectProp(hvoAnn, ktagTwficDefault) != 0)
				return false;

			int analysisClass = fdoCache.GetClassOfObject(hvoAnalysis);
			if (analysisClass != (int)WfiGloss.kclsidWfiGloss && analysisClass != (int)WfiAnalysis.kclsidWfiAnalysis)
				return false; // Has to BE an analysis...unless pathologically everything is off? Too bad if so...
			int hvoWfiAnalysis = fdoCache.GetOwnerOfObject(hvoAnalysis);
			int hvoWordform;
			if (analysisClass == (int)WfiAnalysis.kclsidWfiAnalysis)
			{
				hvoWordform = hvoWfiAnalysis;
				hvoWfiAnalysis = hvoAnalysis;
			}
			else
			{
				hvoWordform = fdoCache.GetOwnerOfObject(hvoWfiAnalysis);
			}

			foreach (InterlinLineSpec spec in m_vc.LineChoices)
			{
				// see if the information required for this linespec is present.
				switch (spec.Flid)
				{
					case InterlinLineChoices.kflidWord:
						int ws = m_vc.GetRealWs(hvoWordform, spec);
						if (sda.get_MultiStringAlt(hvoWordform, (int)WfiWordform.WfiWordformTags.kflidForm, ws).Length == 0)
							return false;
						break;
					case InterlinLineChoices.kflidLexEntries:
						if (!CheckPropSetForAllMorphs(sda, hvoWfiAnalysis, (int)WfiMorphBundle.WfiMorphBundleTags.kflidMorph))
							return false;
						break;
					case InterlinLineChoices.kflidMorphemes:
						if (!CheckPropSetForAllMorphs(sda, hvoWfiAnalysis, (int)WfiMorphBundle.WfiMorphBundleTags.kflidMorph))
							return false;
						break;
					case InterlinLineChoices.kflidLexGloss:
						if (!CheckPropSetForAllMorphs(sda, hvoWfiAnalysis, (int)WfiMorphBundle.WfiMorphBundleTags.kflidSense))
							return false;
						break;
					case InterlinLineChoices.kflidLexPos:
						if (!CheckPropSetForAllMorphs(sda, hvoWfiAnalysis, (int)WfiMorphBundle.WfiMorphBundleTags.kflidMsa))
							return false;
						break;
					case InterlinLineChoices.kflidWordGloss:
						// If it isn't a WfiGloss the user needs a chance to supply a word gloss.
						if (analysisClass != WfiGloss.kclsidWfiGloss)
							return false;
						// If it is empty for the (possibly magic) ws specified here, it needs filling in.
						int ws1 = m_vc.GetRealWs(hvoAnalysis, spec);
						if (sda.get_MultiStringAlt(hvoAnalysis, (int)WfiGloss.WfiGlossTags.kflidForm, ws1).Length == 0)
							return false;
						break;
					case InterlinLineChoices.kflidWordPos:
						if (sda.get_ObjectProp(hvoWfiAnalysis, (int)WfiAnalysis.WfiAnalysisTags.kflidCategory) == 0)
							return false;
						break;
					case InterlinLineChoices.kflidFreeTrans:
					case InterlinLineChoices.kflidLitTrans:
					case InterlinLineChoices.kflidNote:
					default:
						// unrecognized or non-word-level annotation, nothing required.
						break;
				}
			}

			return true; // If we can't find anything to complain about, it's fully analyzed.
		}
示例#6
0
		/// <summary>
		/// get the index of an item in the list that has a root object that is owned by hvo
		/// </summary>
		/// <param name="hvo"></param>
		/// <returns>-1 if the object is not in the list</returns>
		public int IndexOfChildOf(int hvoTarget, FdoCache cache)
		{
			CheckDisposed();

			int i = 0;
			foreach (ManyOnePathSortItem item in SortedObjects)
			{
				ICmObject orange = item.RootObject;
				for (int hvoOwner = cache.GetOwnerOfObject(orange.Hvo);
					hvoOwner != 0;
					hvoOwner = cache.GetOwnerOfObject(hvoOwner))
				{
					if (hvoOwner == hvoTarget)
						return i;
				}
				++i;
			}
			return -1;
		}
示例#7
0
		/// <summary>
		/// Checks for and reports any disallowed tag list moves.
		/// </summary>
		/// <param name="cache"></param>
		/// <param name="movingTagItem">The proposed tag item to move.</param>
		/// <param name="hvoSubListRoot">The hvo of the top-level Tag Type Possibility containing the moving item.</param>
		/// <param name="hvoMainTagList">The hvo of the main PossiblityList grouping all TextMarkup Tags.</param>
		/// <param name="hvoDest">The hvo of the destination tag item.</param>
		/// <returns>true if we found and reported a bad move.</returns>
		private bool CheckAndReportBadTagListMove(FdoCache cache, CmPossibility movingTagItem, int hvoSubListRoot,
			int hvoMainTagList, int hvoDest)
		{
			// Check if movingTagItem is a top-level Tag Type.
			if (movingTagItem.Hvo == hvoSubListRoot)
			{
				if (hvoDest == hvoMainTagList) // top-level Tag Type can move to main list (probably already there)
					return false;

				// The moving item is a top-level Tag Type, it cannot be demoted.
				MessageBox.Show(m_tree, xWorksStrings.ksCantDemoteTagList,
								xWorksStrings.ksProhibitedMovement, MessageBoxButtons.OK, MessageBoxIcon.Warning);
				return true;
			}
			// Unless something is badly wrong, the destination is either the tag type root,
			// a tag one level down from the root, or the base list.
			if (cache.GetOwnerOfObject(hvoDest) == hvoMainTagList)
			{
				// Destination is Tag Type root, not a problem
				return false;
			}
			if (hvoDest == hvoMainTagList)
			{
				// Can't promote tag to Tag Type root
				MessageBox.Show(m_tree, xWorksStrings.ksCantPromoteTag,
								xWorksStrings.ksProhibitedMovement, MessageBoxButtons.OK, MessageBoxIcon.Warning);
				return true;
			}
			// This would give us hierarchy too deep (at least for now)
			MessageBox.Show(m_tree, xWorksStrings.ksTagListTooDeep,
							xWorksStrings.ksProhibitedMovement, MessageBoxButtons.OK, MessageBoxIcon.Warning);
			return true;
		}
示例#8
0
		public static int GetParentOfClass(FdoCache m_cache, int hvo, int classIdOfParentToSearchFor)
		{
			//save the caller the need to see if this property was empty or not
			if(hvo <1)
				return -1;

			int classId = m_cache.GetClassOfObject(hvo) ;

			while((!m_cache.IsSameOrSubclassOf(classId,classIdOfParentToSearchFor))
				&& (classId != FDO.LangProj.LangProject.kClassId))
			{
				hvo = m_cache.GetOwnerOfObject(hvo);
				classId = m_cache.GetClassOfObject(hvo) ;
			}
			if((!m_cache.IsSameOrSubclassOf(classId,classIdOfParentToSearchFor)))
				return -1;
			else
				return hvo;
		}
示例#9
0
		/// <summary>
		/// Test whether a particular StTxtPara is part of Scripture.
		/// </summary>
		/// <param name="hvoPara"></param>
		/// <param name="cache"></param>
		/// <returns></returns>
		public static bool IsScripturePara(int hvoPara, FdoCache cache)
		{
			int flidOfOwnerOfSttext = cache.GetOwningFlidOfObject(cache.GetOwnerOfObject(hvoPara));
			return Scripture.Scripture.IsScriptureTextFlid(flidOfOwnerOfSttext);
		}
示例#10
0
				/// <summary>
				/// for variant relationships, return the primary entry
				/// (of which this morph is a variant). Otherwise,
				/// return the owning entry of the morph.
				/// </summary>
				/// <param name="cache"></param>
				/// <returns></returns>
				public int GetPrimaryOrOwningEntry(FdoCache cache)
				{
					int hvoMorphEntryReal;
					if (m_hvoEntry != 0)
					{
						// for variant relationships, we want to allow trying to create a
						// new sense on the entry of which we are a variant.
						hvoMorphEntryReal = m_hvoEntry;
					}
					else
					{
						hvoMorphEntryReal = cache.GetOwnerOfObject(m_hvoMorph);
					}
					return hvoMorphEntryReal;
				}
示例#11
0
		private static bool CheckAndReportBadDiscourseTemplateAdd(FdoCache cache, int hvoItem, int hvoRootItem, int hvoList)
		{
			if (cache.GetOwningFlidOfObject(hvoList) != (int)DsDiscourseData.DsDiscourseDataTags.kflidConstChartTempl)
				return false; // some other list we don't care about.
			// We can't turn a column into a group if it's in use.
			CmPossibility col = CmPossibility.CreateFromDBObject(cache, hvoItem) as CmPossibility;
			// If the item doesn't already have children, we can only add them if it isn't already in use
			// as a column: we don't want to change a column into a group. Thus, if there are no
			// children, we generally call the same routine as when deleting.
			// However, that routine has a special case to prevent deletion of the default template even
			// if NOT in use...and we must not prevent adding to that when it is empty! Indeed any
			// empty CHART can always be added to, so only if col's owner is a CmPossibility (it's not a root
			// item in the templates list) do we need to check for it being in use.
			if (col.SubPossibilitiesOS.Count == 0 && col.Owner is CmPossibility && col.CheckAndReportProtectedChartColumn())
				return true;
			// Finally, we have to confirm the two-level rule.
			if (hvoItem != hvoRootItem && cache.GetOwnerOfObject(hvoItem) != hvoRootItem)
			{
				MessageBox.Show(FdoUiStrings.ksTemplateTooDeep,
								FdoUiStrings.ksHierarchyLimit, MessageBoxButtons.OK, MessageBoxIcon.Warning);
				return true;
			}
			return false;
		}
示例#12
0
		// Make a string representing a WfiAnalysis, suitable for use in a combo box item.
		static internal ITsString MakeAnalysisStringRep(int hvoWa, FdoCache fdoCache, bool fUseStyleSheet, int wsVern)
		{
			//			ITsTextProps boldItalicAnalysis = BoldItalicAnalysis(fdoCache);
			//			ITsTextProps italicAnalysis = ItalicAnalysis(fdoCache, Sandbox.SandboxVc.krgbRed);
			ITsTextProps posTextProperties = PartOfSpeechTextProperties(fdoCache, true, fUseStyleSheet);
			ITsTextProps formTextProperties = FormTextProperties(fdoCache, fUseStyleSheet, wsVern);
			ITsTextProps glossTextProperties = GlossTextProperties(fdoCache, true, fUseStyleSheet);
			ITsStrBldr tsb = TsStrBldrClass.Create();
			ISilDataAccess sda = fdoCache.MainCacheAccessor;
			int cmorph = fdoCache.GetVectorSize(hvoWa,
				(int)WfiAnalysis.WfiAnalysisTags.kflidMorphBundles);
			if (cmorph == 0)
				return fdoCache.MakeUserTss(ITextStrings.ksNoMorphemes);
			bool fRtl = fdoCache.LanguageWritingSystemFactoryAccessor.get_EngineOrNull(wsVern).RightToLeft;
			int start = 0;
			int lim = cmorph;
			int increment = 1;
			if (fRtl)
			{
				start = cmorph - 1;
				lim = -1;
				increment = -1;
			}
			for (int i = start; i != lim; i += increment)
			{
				int hvoMb = fdoCache.GetVectorItem(hvoWa,
					(int)WfiAnalysis.WfiAnalysisTags.kflidMorphBundles, i);
				int hvoMf = fdoCache.GetObjProperty(hvoMb,
					(int)WfiMorphBundle.WfiMorphBundleTags.kflidMorph);
				ITsString tssForm = null;
				if (hvoMf != 0)
				{
					int hvoEntry = fdoCache.GetOwnerOfObject(hvoMf);
					int hvoLexemeForm = sda.get_ObjectProp(hvoEntry, (int) LexEntry.LexEntryTags.kflidLexemeForm);
					if (hvoLexemeForm != 0)
					{
						tssForm = sda.get_MultiStringAlt(hvoLexemeForm, (int) MoForm.MoFormTags.kflidForm, wsVern);
					}
					if (tssForm == null || tssForm.Length == 0)
					{
						tssForm = fdoCache.MainCacheAccessor.get_MultiStringAlt(hvoEntry,
							(int)LexEntry.LexEntryTags.kflidCitationForm, wsVern);
					}
					if (tssForm.Length == 0)
					{
						// If there isn't a lexeme form OR citation form use the form of the morph.
						tssForm = fdoCache.MainCacheAccessor.get_MultiStringAlt(hvoMf,
							(int)MoForm.MoFormTags.kflidForm, wsVern);
					}
				}
				else // no MoForm linked to this bundle, use its own form.
				{
					tssForm = fdoCache.MainCacheAccessor.get_MultiStringAlt(hvoMb,
						(int)WfiMorphBundle.WfiMorphBundleTags.kflidForm, wsVern);
				}
				int ichForm = tsb.Length;
				tsb.ReplaceTsString(ichForm, ichForm, tssForm);
				tsb.SetProperties(ichForm, tsb.Length,formTextProperties);

				// add category (part of speech)
				int hvoMsa = fdoCache.GetObjProperty(hvoMb,
					(int)WfiMorphBundle.WfiMorphBundleTags.kflidMsa);
				tsb.Replace(tsb.Length, tsb.Length, " ", null);
				int ichMinMsa = tsb.Length;
				string interlinName = ksMissingString;
				if (hvoMsa != 0)
				{
					IMoMorphSynAnalysis msa =
						MoMorphSynAnalysis.CreateFromDBObject(fdoCache, hvoMsa);
					interlinName = msa.InterlinearAbbr;
				}
				tsb.Replace(ichMinMsa, ichMinMsa, interlinName, posTextProperties);

				//add sense
				int hvoSense = fdoCache.GetObjProperty(hvoMb,
					(int)WfiMorphBundle.WfiMorphBundleTags.kflidSense);
				tsb.Replace(tsb.Length, tsb.Length, " ", null);
				int ichMinSense = tsb.Length;
				if (hvoSense != 0)
				{
					ITsString tssGloss = fdoCache.MainCacheAccessor.get_MultiStringAlt(hvoSense,
						(int)LexSense.LexSenseTags.kflidGloss, fdoCache.DefaultAnalWs);
					tsb.Replace(ichMinSense, ichMinSense, tssGloss.Text, glossTextProperties);
				}
				else
					tsb.Replace(ichMinSense, ichMinSense, ksMissingString, glossTextProperties);

				// Enhance JohnT: use proper seps.
				tsb.Replace(tsb.Length, tsb.Length, ksPartSeparator, null);
			}
			// Delete the final separator. (Enhance JohnT: this needs to get smarter when we do
			// real seps.)
			int ichFrom = tsb.Length - ksPartSeparator.Length;
			if (ichFrom < 0)
				ichFrom = 0;
			tsb.Replace(ichFrom, tsb.Length, "", null);
			return tsb.GetString();
		}
示例#13
0
		// Generate a suitable string representation of a WfiGloss.
		// Todo: finish implementing (add the gloss!)
		static internal ITsString MakeGlossStringRep(int hvoGloss, FdoCache fdoCache, bool fUseStyleSheet)
		{
			ITsStrBldr tsb = TsStrBldrClass.Create();
			int hvoWa = fdoCache.GetOwnerOfObject(hvoGloss);

			int hvoCategory = fdoCache.GetObjProperty(hvoWa,
				(int)WfiAnalysis.WfiAnalysisTags.kflidCategory);
			if(hvoCategory > 0)
			{
				ITsString tssPos = fdoCache.MainCacheAccessor.get_MultiStringAlt(hvoCategory,
					(int)CmPossibility.CmPossibilityTags.kflidAbbreviation,
					fdoCache.DefaultAnalWs);
				tsb.Replace(0, 0, tssPos.Text,
					PartOfSpeechTextProperties(fdoCache,false, fUseStyleSheet));
			}
			else
			{
				tsb.Replace(0, 0, ksMissingString,
					PartOfSpeechTextProperties(fdoCache,false, fUseStyleSheet));
			}
			tsb.Replace(tsb.Length, tsb.Length, " ", null);
			tsb.Replace(tsb.Length, tsb.Length,
				fdoCache.MainCacheAccessor.get_MultiStringAlt(hvoGloss,
				(int)WfiGloss.WfiGlossTags.kflidForm, fdoCache.DefaultAnalWs).Text,
				GlossTextProperties(fdoCache, false, fUseStyleSheet));

			//indent
			tsb.Replace(0,0, "    ", null);
			return tsb.GetString();
		}
示例#14
0
		static internal int GetParagraphIndexForAnnotation(FdoCache cache, int annHvo)
		{
			int hvoPara = cache.MainCacheAccessor.get_ObjectProp(annHvo, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginObject);
			int hvoStText = cache.GetOwnerOfObject(hvoPara);
			return GetParagraphIndexForPara(cache, hvoStText, hvoPara);
		}
示例#15
0
        /// <summary>
        /// Test whether a particular StTxtPara is part of Scripture.
        /// </summary>
        /// <param name="hvoPara"></param>
        /// <param name="cache"></param>
        /// <returns></returns>
        public static bool IsScripturePara(int hvoPara, FdoCache cache)
        {
            int flidOfOwnerOfSttext = cache.GetOwningFlidOfObject(cache.GetOwnerOfObject(hvoPara));

            return(Scripture.Scripture.IsScriptureTextFlid(flidOfOwnerOfSttext));
        }
示例#16
0
		/// <summary>
		/// Get a set of inflectional affix slots which can be prefixal or suffixal
		/// </summary>
		/// <param name="cache"></param>
		/// <param name="allSlots">Original set of all slots</param>
		/// <param name="fLookForPrefixes">whether to look for prefixal slots</param>
		/// <returns>subset of slots that are either prefixal or suffixal</returns>
		public static Set<int> GetSomeSlots(FdoCache cache, Set<int> allSlots, bool fLookForPrefixes)
		{
			Set<int> set = new Set<int>();
			//Set<int> allSlots = GetAllSlots();
			foreach (int hvoSlot in allSlots)
			{
				MoInflAffixSlot slot = CmObject.CreateFromDBObject(cache, hvoSlot) as MoInflAffixSlot;
				if (slot == null)
					continue;
				bool fStopLooking = false;
				List<int> hvosAffixes = slot.Affixes;
				if (hvosAffixes.Count == 0)
				{ // no affixes in this slot, so include it
					set.Add(hvoSlot);
					continue;
				}
				foreach (int hvoMsa in hvosAffixes)
				{
					int hvoLex = cache.GetOwnerOfObject(hvoMsa);
					LexEntry lex = CmObject.CreateFromDBObject(cache, hvoLex) as LexEntry;
					List<IMoMorphType> morphTypes = lex.MorphTypes;
					foreach (IMoMorphType morphType in morphTypes)
					{
						bool fIsCorrectType;
						if (fLookForPrefixes)
							fIsCorrectType = MoMorphType.IsPrefixishType(cache, morphType.Hvo);
						else
							fIsCorrectType = MoMorphType.IsSuffixishType(cache, morphType.Hvo);
						if (fIsCorrectType)
						{
							set.Add(hvoSlot);
							fStopLooking = true;
							break;
						}
					}
					if (fStopLooking)
						break;
				}
			}
			return set;
		}
        const int ktagMinVp = 0x7f000000;         // copied from VwCacheDa.h, mimimum value for assigned virtual props.
        /// <summary>
        /// We implement this to record modify times.
        /// </summary>
        /// <param name="hvo"></param>
        /// <param name="tag"></param>
        /// <param name="ivMin"></param>
        /// <param name="cvIns"></param>
        /// <param name="cvDel"></param>
        public void PropChanged(int hvo, int tag, int ivMin, int cvIns, int cvDel)
        {
            CheckDisposed();
            if (m_fModifyChangeInProgress)             // ignore PropChanged on the DateModified property!
            {
                return;
            }
            // Typically an Undo will restore the modify time to what it was before the
            // main change. We don't want to reverse that by recording the time of the Undo!
            // Note that there is one pathological scenario:
            // t1: make a change.
            // t2: undo the change.
            // t3: export all changed records (since before t1).
            // t4: redo the change. Record appears to have been modified at time t2.
            // t5: export all changed records (since t3).
            // If this was the only change to the record, it is not part of either export,
            // and the change might be lost.
            // To prevent this, I think the 'export changed records' function should clear
            // the Undo stack.
            if (m_cache.ActionHandlerAccessor != null && m_cache.ActionHandlerAccessor.IsUndoOrRedoInProgress)
            {
                return;
            }
            if (tag < 0 || tag >= ktagMinVp)
            {
                return;                 // phony or virtual properties, not real changes (e.g., different filter applied, or selection moving in browse).
            }
            try
            {
                DateTime dtNow    = DateTime.Now;
                int      hvoMajor = 0;            // hvo of the 'major' object that has the DateModified property.
                if (SameMinute(dtNow, m_currentMinute))
                {
                    // We can use our Dictionary
                    if (m_recentMods.ContainsKey(hvo))
                    {
                        hvoMajor = m_recentMods[hvo];
                    }
                }
                else
                {
                    ResetDelay();
                }
                int flidModify = 0;
                if (hvoMajor == 0)
                {
                    for (int hvoCandidate = hvo; hvoCandidate != 0;
                         hvoCandidate = m_cache.GetOwnerOfObject(hvoCandidate))
                    {
                        // We assume that this is a dummy object at this point and GetClassOfObject
                        // only accepts real objects. Since it's a dummy object, changes should never
                        // affect the modify time of a real object. Maybe at some point we can get an
                        // interface method to check for dummy objects.
                        if (hvoCandidate < 0)
                        {
                            return;
                        }
                        int clid = m_cache.GetClassOfObject(hvoCandidate);
                        if (clid == 0)
                        {
                            return;                             // maybe a deleted object, no good to us, we can't record modify time.
                        }
                        flidModify = (int)m_mdc.GetFieldId2((uint)clid, "DateModified", true);
                        if (flidModify != 0)
                        {
                            hvoMajor = hvoCandidate;
                            break;
                        }
                    }
                    if (hvoMajor == 0)
                    {
                        return;                         // found no owner with DateCreated property.
                    }
                    m_recentMods[hvo] = hvoMajor;       // lets us find it fast if modified again soon.
                }
                else
                {
                    // We need to set flidModify!
                    int clid = m_cache.GetClassOfObject(hvoMajor);
                    if (clid != 0)
                    {
                        flidModify = (int)m_mdc.GetFieldId2((uint)clid, "DateModified", true);
                    }
                }
                if (flidModify == 0)
                {
                    return;                     // can't set the time prop without a field...
                }
                DateTime oldModifyTime = m_cache.GetTimeProperty(hvoMajor, flidModify);
                // If we already noted a modify time in the current minute, don't do it again.
                // This is intended to keep down the overhead of recording modify times for frequently
                // modified objects.
                if (SameMinute(oldModifyTime, dtNow))
                {
                    //Trace.TraceInformation("New Modify Time ({0}) for {1} is same minute as the old ({2}).\n",
                    //    dtNow, hvoMajor, oldModifyTime);
                    return;
                }
                //				if (m_currentMinute != null &&
                //					m_currentMinute.Date == dtNow.Date && m_currentMinute.Hour = dtNow.Hour && m_currentMinute.Minute == dtNow.Minute)
                //					return;

                // Set the modify time. If possible tack this on to the last Undo task (or the current one, if a
                // transaction is open).
                if (m_cache.ActionHandlerAccessor != null && m_cache.VwOleDbDaAccessor != null &&
                    ((m_cache.DatabaseAccessor != null && m_cache.DatabaseAccessor.IsTransactionOpen()) ||
                     m_cache.CanUndo))
                {
                    m_cache.ContinueUndoTask();
                    m_cache.SetTimeProperty(hvoMajor, flidModify, dtNow);
                    m_cache.EndUndoTask();
                }
                else
                {
                    // We don't have an Undo task to append to, so somehow a Save has occurred
                    // in the midst of the operation that caused the time stamp modification.
                    // If we make an empty undo task, the user will typically have no idea what
                    // could be undone, and will be confused. Best to make it impossible to
                    // undo the timestamp change also.
                    using (new SuppressSubTasks(m_cache))
                    {
                        m_cache.SetTimeProperty(hvoMajor, flidModify, dtNow);
                    }
                }
                //Trace.TraceInformation("Setting new Modify Time ({0}) for {1}\n",
                //        dtNow, hvoMajor);
            }
            finally
            {
                m_fModifyChangeInProgress = false;
            }
        }
		/// <summary>
		/// Check whether the list should be sorted.  See LT-5149.
		/// </summary>
		/// <param name="labels"></param>
		/// <param name="cache"></param>
		/// <returns></returns>
		private static bool IsListSorted(ObjectLabelCollection labels, FdoCache cache)
		{
			if (labels.Count > 0 && cache != null)
			{
				int hvoList = cache.GetOwnerOfObject(labels[0].Hvo);
				ICmObject co = CmObject.CreateFromDBObject(cache, hvoList);
				if (co is ICmPossibilityList)
					return (co as ICmPossibilityList).IsSorted;
			}
			return true;
		}