/// <summary> /// This is invoked (using reflection) by an XmlRDEBrowseView when the user presses /// "Enter" in an RDE view that is displaying lexeme form and definition. /// (Maybe also on loss of focus, switch domain, etc?) /// It creates a new entry, lexeme form, and sense that are linked to the specified domain. /// Typically, later, a call to RDEMergeSense will be made to see whether this /// new entry should be merged into some existing sense. /// Note that this method is NOT responsible to insert the new sense into /// the fake property tagList of hvoDomain. (The caller will do that.) /// </summary> /// <param name="hvoDomain">database id of the semantic domain</param> /// <param name="tagList">id of the inverse relation for the senses that belong to the /// domain</param> /// <param name="columns"></param> /// <param name="rgtss"></param> /// <param name="cache"></param> /// <param name="stringTbl"></param> public static int RDENewSense(int hvoDomain, int tagList, List<XmlNode> columns, ITsString[] rgtss, FdoCache cache, StringTable stringTbl) { Debug.Assert(hvoDomain != 0); Debug.Assert(rgtss.Length == columns.Count); // Make a new sense in a new entry. ILexEntry le = cache.LangProject.LexDbOA.EntriesOC.Add( new LexEntry()); IMoForm morph = null; // create a LexSense that has the given definition and semantic domain // Needs to be LexSense, since later calls use non-interface methods. LexSense ls = (LexSense)le.SensesOS.Append(new LexSense()); ILgWritingSystemFactory wsf = cache.LanguageWritingSystemFactoryAccessor; // go through each column and store the appropriate information. for (int i = 0; i < columns.Count; ++i) { // Review: Currently we key off the column labels to determine which columns // correspond to CitationForm and which correspond to Definition. // Ideally we'd like to get at the flids used to build the column display strings. // Instead of passing in only ITsStrings, we could pass in a structure containing // an index of strings with any corresponding flids. Here we'd expect strings // based upon either LexemeForm.Form or LexSense.Definition. We could probably // do this as part of the solution to handling duplicate columns in LT-3763. XmlNode column = columns[i] as XmlNode; string columnLabel = XmlUtils.GetManditoryAttributeValue(column, "label"); string[] columnLabelComponents = columnLabel.Split(new char[] {' ', ':'}); // get column label without writing system or extraneous information. string columnBasicLabel = columnLabelComponents[0]; if (!String.IsNullOrEmpty(columnBasicLabel) && stringTbl != null) columnBasicLabel = stringTbl.LocalizeAttributeValue(columnBasicLabel); ITsTextProps ttp = rgtss[i].get_PropertiesAt(0); int var; int ws = ttp.GetIntPropValues((int)FwTextPropType.ktptWs, out var); Debug.Assert(ws != 0); ITsString tssStr = rgtss[i]; string sStr = tssStr.Text; if (sStr == null) sStr = ""; // otherwise Trim below blows up. sStr = sStr.Trim(); if (columnBasicLabel == Strings.ksWord) { // This is a lexeme form. if (morph == null) morph = MoForm.MakeMorph(cache, le, tssStr); Debug.Assert(le.LexemeFormOAHvo != 0); if (morph is IMoStemAllomorph) { // Make sure we have a proper allomorph and MSA for this new entry and sense. // (See LT-1318 for details and justification.) MoMorphTypeCollection typesCol = new MoMorphTypeCollection(cache); if (sStr.IndexOf(' ') > 0) morph.MorphTypeRA = typesCol.Item(MoMorphType.kmtPhrase); else morph.MorphTypeRA = typesCol.Item(MoMorphType.kmtStem); morph.Form.SetAlternative(sStr, ws); } } else if (columnBasicLabel == Strings.ksDefinition) { // This is a Definition. if (sStr != "") ls.Definition.SetAlternative(sStr, ws); } else { Debug.Fail("column (" + columnLabel + ") not supported."); } } if (morph == null) morph = le.LexemeFormOA = new MoStemAllomorph(); ls.RDEAddDomain(hvoDomain, tagList, cache); if (le.MorphoSyntaxAnalysesOC.Count == 0) { // Commonly, it's a new entry with no MSAs; make sure it has at least one. // This way of doing it allows a good bit of code to be shared with the normal // creation path, as if the user made a stem but didn't fill in any grammatical // information. DummyGenericMSA dummyMsa = new DummyGenericMSA(); if (morph != null && morph is IMoAffixForm) dummyMsa.MsaType = MsaType.kUnclassified; else dummyMsa.MsaType = MsaType.kStem; ls.DummyMSA = dummyMsa; } // We don't want a partial MSA created, so don't bother doing anything // about setting ls.MorphoSyntaxAnalysisRA // LT-1731: adding to make sure new entries are added to the lexicon // record list (full edit,...) cache.PropChanged(null, PropChangeType.kpctNotifyAll, cache.LangProject.LexDbOA.Hvo, (int)LexDb.LexDbTags.kflidEntries, 0, 1, 0); return ls.Hvo; }
/// <summary> /// Get the morph type and class ID for the given input string. /// </summary> /// <param name="cache">The cache to look in.</param> /// <param name="types">Collection of all of the MoMorphType objects.</param> /// <param name="fullForm">The MoForm form, plus optional key characters before and/or after the form.</param> /// <param name="clsidForm">Return the clsid for the form.</param> /// <returns>The MoMorphType indicated by the possible markers.</returns> /// <exception cref="ArgumentException"> /// Thrown in the following cases: /// 1. The input form is an empty string, /// 2. The imput form is improperly marked according to the current settings of the /// MoMorphType objects. /// </exception> public static IMoMorphType FindMorphType(FdoCache cache, MoMorphTypeCollection types, ref string fullForm, out int clsidForm) { Debug.Assert(cache != null); Debug.Assert(fullForm != null); clsidForm = MoStemAllomorph.kclsidMoStemAllomorph; // default IMoMorphType mt = null; fullForm = fullForm.Trim(); if (fullForm.Length == 0) throw new ArgumentException("The form is empty.", "fullForm"); string sLeading; string sTrailing; GetAffixMarkers(cache, fullForm, out sLeading, out sTrailing); /* Not dealt with. particle (ambiguous: particle, circumfix, root, stem) circumfix (ambiguous: particle, circumfix, root, stem) root (ambiguous: particle, circumfix, root, stem) bound root (ambiguous: bound root, bound stem) infixing interfix (ambiguous: infixing interfix, infix) prefixing interfix (ambiguous: prefixing interfix, prefix) suffixing interfix (ambiguous: suffixing interfix, suffix) End of not dealt with. What we do deal with. prefix- (ambiguous: prefixing interfix, prefix) =simulfix= -suffix (ambiguous: suffixing interfix, suffix) -infix- (ambiguous: infixing interfix, infix) ~suprafix~ =enclitic proclitic= *bound stem (ambiguous: bound root, bound stem) stem (ambiguous: particle, circumfix, root, stem) End of what we do deal with. For ambiguous cases, pick 'root' and 'bound root', as per LarryH's suggestion on 11/18/2003. (Changed: May, 2004). For ambiguous cases, pick 'stem' and 'bound stem', as per WordWorks May, 2004 meeting (Andy Black & John Hatton). For ambiguous cases, pick 'infix', 'prefix', and 'suffix'. */ if (sLeading == types.Item(kmtStem).Prefix && sTrailing == types.Item(kmtStem).Postfix) { mt = types.Item(kmtStem); // may be ambiguous with particle, root, and circumfix } else if (sLeading == types.Item(kmtPrefix).Prefix && sTrailing == types.Item(kmtPrefix).Postfix) { mt = types.Item(kmtPrefix); // may be ambiguous with prefixing interfix clsidForm = MoAffixAllomorph.kclsidMoAffixAllomorph; } else if (sLeading == types.Item(kmtInfix).Prefix && sTrailing == types.Item(kmtInfix).Postfix) { mt = types.Item(kmtInfix); // may be ambiguous with infixing interfix clsidForm = MoAffixAllomorph.kclsidMoAffixAllomorph; } else if (sLeading == types.Item(kmtSuffix).Prefix && sTrailing == types.Item(kmtSuffix).Postfix) { mt = types.Item(kmtSuffix); // may be ambiguous with suffixing interfix clsidForm = MoAffixAllomorph.kclsidMoAffixAllomorph; } else if (sLeading == types.Item(kmtBoundStem).Prefix && sTrailing == types.Item(kmtBoundStem).Postfix) { mt = types.Item(kmtBoundStem); // may be ambiguous with bound root } else if (sLeading == types.Item(kmtProclitic).Prefix && sTrailing == types.Item(kmtProclitic).Postfix) { mt = types.Item(kmtProclitic); } else if (sLeading == types.Item(kmtEnclitic).Prefix && sTrailing == types.Item(kmtEnclitic).Postfix) { mt = types.Item(kmtEnclitic); } else if (sLeading == types.Item(kmtSimulfix).Prefix && sTrailing == types.Item(kmtSimulfix).Postfix) { mt = types.Item(kmtSimulfix); clsidForm = MoAffixAllomorph.kclsidMoAffixAllomorph; } else if (sLeading == types.Item(kmtSuprafix).Prefix && sTrailing == types.Item(kmtSuprafix).Postfix) { mt = types.Item(kmtSuprafix); clsidForm = MoAffixAllomorph.kclsidMoAffixAllomorph; } else if (sLeading == types.Item(kmtBoundRoot).Prefix && sTrailing == types.Item(kmtBoundRoot).Postfix) { mt = types.Item(kmtBoundRoot); } else if (sLeading == types.Item(kmtRoot).Prefix && sTrailing == types.Item(kmtRoot).Postfix) { mt = types.Item(kmtRoot); } else if (sLeading == types.Item(kmtParticle).Prefix && sTrailing == types.Item(kmtParticle).Postfix) { mt = types.Item(kmtParticle); } else if (sLeading == types.Item(kmtCircumfix).Prefix && sTrailing == types.Item(kmtCircumfix).Postfix) { mt = types.Item(kmtCircumfix); clsidForm = MoAffixAllomorph.kclsidMoAffixAllomorph; } else if (sLeading == types.Item(kmtPrefixingInterfix).Prefix && sTrailing == types.Item(kmtPrefixingInterfix).Postfix) { mt = types.Item(kmtPrefixingInterfix); clsidForm = MoAffixAllomorph.kclsidMoAffixAllomorph; } else if (sLeading == types.Item(kmtInfixingInterfix).Prefix && sTrailing == types.Item(kmtInfixingInterfix).Postfix) { mt = types.Item(kmtInfixingInterfix); clsidForm = MoAffixAllomorph.kclsidMoAffixAllomorph; } else if (sLeading == types.Item(kmtSuffixingInterfix).Prefix && sTrailing == types.Item(kmtSuffixingInterfix).Postfix) { mt = types.Item(kmtSuffixingInterfix); clsidForm = MoAffixAllomorph.kclsidMoAffixAllomorph; } else { if (sLeading == null && sTrailing == null) throw new Exception(String.Format(Strings.ksInvalidUnmarkedForm0, fullForm)); else if (sLeading == null) throw new Exception(String.Format(Strings.ksInvalidForm0Trailing1, fullForm, sTrailing)); else if (sTrailing == null) throw new Exception(String.Format(Strings.ksInvalidForm0Leading1, fullForm, sLeading)); else throw new Exception(String.Format(Strings.ksInvalidForm0Leading1Trailing2, fullForm, sLeading, sTrailing)); } if (sLeading != null) fullForm = fullForm.Substring(sLeading.Length); if (sTrailing != null) fullForm = fullForm.Substring(0, fullForm.Length - sTrailing.Length); // Handle prhase if (mt.Guid.ToString().ToLower() == MoMorphType.kguidMorphStem) { if (fullForm.IndexOf(" ") != -1) mt = types.Item(kmtPhrase); } // Check to see if it has any of the reserved characters remaining, // as we have now stripped them off the ends, // and it is illegal to have them internal to the form. // (SteveMc) But is it? What about hyphenated words? Or contractions? // if ((MiscUtils.IndexOfAnyString(fullForm, prefixMarkers, 0, out iMatchedPrefix) > -1) || // (MiscUtils.IndexOfAnyString(fullForm, postfixMarkers, 0, out iMatchedPrefix) > -1)) // { // throw new Exception("\"" + fullForm + "\" is not a valid morpheme. It should not have a reserved morpheme marker within the form. Did you forget spaces?"); // } return mt; }
/// <summary> /// Get a set of hvos that are suitable for targets to a reference property. /// Subclasses should override this method to return a sensible list of IDs. /// </summary> /// <param name="flid">The reference property that can store the IDs.</param> /// <returns>A set of hvos.</returns> public override Set<int> ReferenceTargetCandidates(int flid) { Set<int> set = null; switch (flid) { case (int)MoForm.MoFormTags.kflidMorphType: set = new Set<int>(m_cache.LangProject.LexDbOA.MorphTypesOA.PossibilitiesOS.HvoArray); // Remove affix types. MoMorphTypeCollection types = new MoMorphTypeCollection(m_cache); set.Remove(types.Item(MoMorphType.kmtCircumfix).Hvo); set.Remove(types.Item(MoMorphType.kmtInfix).Hvo); set.Remove(types.Item(MoMorphType.kmtPrefix).Hvo); set.Remove(types.Item(MoMorphType.kmtSimulfix).Hvo); set.Remove(types.Item(MoMorphType.kmtSuffix).Hvo); set.Remove(types.Item(MoMorphType.kmtSuprafix).Hvo); set.Remove(types.Item(MoMorphType.kmtInfixingInterfix).Hvo); set.Remove(types.Item(MoMorphType.kmtPrefixingInterfix).Hvo); set.Remove(types.Item(MoMorphType.kmtSuffixingInterfix).Hvo); break; case (int)MoStemAllomorph.MoStemAllomorphTags.kflidPhoneEnv: set = PhEnvironment.ValidEnvironments(m_cache); break; case (int)MoStemAllomorph.MoStemAllomorphTags.kflidStemName: set = new Set<int>(); //List<CmPossibility> poses = m_cache.LangProject.PartsOfSpeechOA.ReallyReallyAllPossibilities; int ownerID = OwnerHVO; int ownerClass = m_cache.GetIntProperty(ownerID, (int)CmObjectFields.kflidCmObject_Class); if (ownerClass == LexEntry.kclsidLexEntry) { ILexEntry entry = LexEntry.CreateFromDBObject(m_cache, ownerID); foreach (IMoMorphSynAnalysis msa in entry.MorphoSyntaxAnalysesOC) { if (msa is IMoStemMsa) { IMoStemMsa infstemmsa = (IMoStemMsa)msa; IPartOfSpeech pos = infstemmsa.PartOfSpeechRA; if (pos != null) { foreach (IMoStemName sn in pos.AllStemNames) set.Add(sn.Hvo); } } } } break; default: set = base.ReferenceTargetCandidates(flid); break; } return set; }
/// <summary> /// Get a set of hvos that are suitable for targets to a reference property. /// Subclasses should override this method to return a sensible list of IDs. /// </summary> /// <param name="flid">The reference property that can store the IDs.</param> /// <returns>A set of hvos.</returns> public override Set<int> ReferenceTargetCandidates(int flid) { Set<int> set = null; switch (flid) { case (int)MoForm.MoFormTags.kflidMorphType: set = new Set<int>(m_cache.LangProject.LexDbOA.MorphTypesOA.PossibilitiesOS.HvoArray); // Remove root and stem types. MoMorphTypeCollection types = new MoMorphTypeCollection(m_cache); set.Remove(types.Item(MoMorphType.kmtBoundRoot).Hvo); set.Remove(types.Item(MoMorphType.kmtBoundStem).Hvo); set.Remove(types.Item(MoMorphType.kmtClitic).Hvo); set.Remove(types.Item(MoMorphType.kmtEnclitic).Hvo); set.Remove(types.Item(MoMorphType.kmtParticle).Hvo); set.Remove(types.Item(MoMorphType.kmtProclitic).Hvo); set.Remove(types.Item(MoMorphType.kmtRoot).Hvo); set.Remove(types.Item(MoMorphType.kmtStem).Hvo); set.Remove(types.Item(MoMorphType.kmtPhrase).Hvo); set.Remove(types.Item(MoMorphType.kmtDiscontiguousPhrase).Hvo); if (OwningFlid == (int)LexEntry.LexEntryTags.kflidAlternateForms) set.Remove(types.Item(MoMorphType.kmtCircumfix).Hvo); // only for lexemeform break; case (int)MoAffixForm.MoAffixFormTags.kflidInflectionClasses: set = new Set<int>(); //List<CmPossibility> poses = m_cache.LangProject.PartsOfSpeechOA.ReallyReallyAllPossibilities; int ownerID = OwnerHVO; int ownerClass = m_cache.GetIntProperty(ownerID, (int)CmObjectFields.kflidCmObject_Class); if (ownerClass == LexEntry.kclsidLexEntry) { ILexEntry entry = LexEntry.CreateFromDBObject(m_cache, ownerID); foreach (IMoMorphSynAnalysis msa in entry.MorphoSyntaxAnalysesOC) { if (msa is IMoInflAffMsa) { IMoInflAffMsa infafxmsa = (IMoInflAffMsa)msa; IPartOfSpeech pos = infafxmsa.PartOfSpeechRA; if (pos != null) { foreach (IMoInflClass ic in pos.AllInflectionClasses) set.Add(ic.Hvo); } } // Review: is this correct? I think the TO POS is the relevant // one for derivational affixes, but maybe nothing is. // HAB says: From is the correct one to use for the allomorphs. The From indicates // the category to which the affix attaches. This category is the one that // may have the inflection classes, one or more of which this allomorph may go with. else if (msa is IMoDerivAffMsa) { IMoDerivAffMsa drvafxmsa = (IMoDerivAffMsa)msa; IPartOfSpeech pos = drvafxmsa.FromPartOfSpeechRA; if (pos != null) { foreach (IMoInflClass ic in pos.AllInflectionClasses) set.Add(ic.Hvo); } } } } break; default: set = base.ReferenceTargetCandidates(flid); break; } return set; }
/// <summary> /// Gets a set of all hvos of all valid morph type references for this MoForm /// </summary> /// <returns>A set of hvos.</returns> public Set<int> GetAllMorphTypeReferenceTargetCandidates() { Set<int> set = new Set<int>(m_cache.LangProject.LexDbOA.MorphTypesOA.PossibilitiesOS.HvoArray); MoMorphTypeCollection types = new MoMorphTypeCollection(m_cache); if (OwningFlid == (int)LexEntry.LexEntryTags.kflidAlternateForms) set.Remove(types.Item(MoMorphType.kmtCircumfix).Hvo); // only for lexemeform return set; }
private bool IsStemType(int hvo) { MoMorphTypeCollection types = new MoMorphTypeCollection(m_cache); if ((hvo == types.Item(MoMorphType.kmtBoundRoot).Hvo) || (hvo == types.Item(MoMorphType.kmtBoundStem).Hvo) || (hvo == types.Item(MoMorphType.kmtEnclitic).Hvo) || (hvo == types.Item(MoMorphType.kmtParticle).Hvo) || (hvo == types.Item(MoMorphType.kmtProclitic).Hvo) || (hvo == types.Item(MoMorphType.kmtRoot).Hvo) || (hvo == types.Item(MoMorphType.kmtStem).Hvo) || (hvo == types.Item(MoMorphType.kmtClitic).Hvo) || // Andy: no! circumfixes are affixes, not stems: (hvo == types.Item(MoMorphType.kmtCircumfix).Hvo) || (hvo == types.Item(MoMorphType.kmtPhrase).Hvo) || (hvo == types.Item(MoMorphType.kmtDiscontiguousPhrase).Hvo) ) return true; return false; }