示例#1
0
        /// <summary>
        /// Change the affix to a stem (possibly)
        /// </summary>
        /// <param name="entry"></param>
        /// <param name="selectedHvo"></param>
        /// <param name="sUndo"></param>
        /// <param name="sRedo"></param>
        /// <returns>true if change made; false otherwise</returns>
        private bool ChangeAffixToStem(ILexEntry entry, int selectedHvo, string sUndo, string sRedo)
        {
            IMoAffixForm affix = m_obj as IMoAffixForm;

            if (affix == null)
            {
                throw new ApplicationException("Affix form is not defined");
            }
            List <IMoMorphSynAnalysis> rgmsaOld = new List <IMoMorphSynAnalysis>();

            if (m_obj.OwningFlid == (int)LexEntry.LexEntryTags.kflidLexemeForm)
            {
                foreach (IMoMorphSynAnalysis msa in entry.MorphoSyntaxAnalysesOC)
                {
                    if (!(msa is IMoStemMsa))
                    {
                        rgmsaOld.Add(msa);
                    }
                }
            }
            if (CheckForAffixDataLoss(affix, rgmsaOld))
            {
                return(false);
            }
            FdoCache cache = m_cache;

            cache.BeginUndoTask(sUndo, sRedo);
            IMoStemAllomorph stem = new MoStemAllomorph();

            SwapValues(entry, affix, stem, selectedHvo, rgmsaOld);              // may cause slice/button to be disposed...
            cache.EndUndoTask();
            return(true);
        }
示例#2
0
        private bool ChangeStemToAffix(ILexEntry entry, int selectedHvo, string sUndo, string sRedo)
        {
            IMoStemAllomorph stem = m_obj as IMoStemAllomorph;

            if (stem == null)
            {
                throw new ApplicationException("Stem allomorph is not defined");
            }
            List <IMoMorphSynAnalysis> rgmsaOld = new List <IMoMorphSynAnalysis>();

            if (m_obj.OwningFlid == (int)LexEntry.LexEntryTags.kflidLexemeForm)
            {
                foreach (IMoMorphSynAnalysis msa in entry.MorphoSyntaxAnalysesOC)
                {
                    if (msa is IMoStemMsa)
                    {
                        rgmsaOld.Add(msa);
                    }
                }
            }
            if (CheckForStemDataLoss(stem, rgmsaOld))
            {
                return(false);
            }
            FdoCache cache = m_cache;

            cache.BeginUndoTask(sUndo, sRedo);
            IMoAffixAllomorph affix = new MoAffixAllomorph();

            SwapValues(entry, stem, affix, selectedHvo, rgmsaOld);
            cache.EndUndoTask();
            return(true);
        }
示例#3
0
        public bool OnMoveReversalPOS(object cmd)
        {
            FdoCache cache = Cache;
            ObjectLabelCollection labels = new ObjectLabelCollection();

            foreach (IPartOfSpeech pos in MergeOrMoveCandidates)
            {
                labels.Add(ObjectLabel.CreateObjectLabelOnly(cache, pos.Hvo, "ShortNameTSS", "best analysis"));
            }
            using (SimpleListChooser dlg = new SimpleListChooser(cache, null, labels, 0,
                                                                 LexEdStrings.ksCategoryToMoveTo, null))
            {
                if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    IPartOfSpeech currentPOS = POS;
                    IPartOfSpeech newOwner   = PartOfSpeech.CreateFromDBObject(cache, dlg.ChosenOne.Hvo);
                    cache.BeginUndoTask(LexEdStrings.ksUndoMoveRevCategory,
                                        LexEdStrings.ksRedoMoveRevCategory);
                    ICmObject newOwningObj = newOwner.MoveIfNeeded(currentPOS);
                    newOwner.SubPossibilitiesOS.Append(currentPOS);
                    cache.EndUndoTask();
                    // Note: PropChanged should happen on the old owner and the new in the 'Add" method call.
                    // Have to jump to a main PartOfSpeech, as RecordClerk doesn't know anything about subcategories.
                    m_mediator.BroadcastMessageUntilHandled("JumpToRecord", newOwner.MainPossibility.Hvo);
                }
            }

            return(true);
        }
示例#4
0
        private bool RunMergeEntryDialog(object argument, bool fLoseNoTextData)
        {
            ICmObject obj = m_mediator.PropertyTable.GetValue("ActiveClerkSelectedObject") as ICmObject;

            Debug.Assert(obj != null);
            if (obj == null)
            {
                return(false);                          // should never happen, but nothing we can do if it does!
            }
            FdoCache cache = (FdoCache)m_mediator.PropertyTable.GetValue("cache");

            Debug.Assert(cache != null);
            Debug.Assert(cache == obj.Cache);
            ILexEntry currentEntry = obj as ILexEntry;

            if (currentEntry == null)
            {
                int hvoEntry = cache.GetOwnerOfObjectOfClass(obj.Hvo, LexEntry.kclsidLexEntry);
                if (hvoEntry != 0)
                {
                    currentEntry = LexEntry.CreateFromDBObject(cache, hvoEntry);
                }
            }
            Debug.Assert(currentEntry != null);
            if (currentEntry == null)
            {
                return(false);
            }

            using (MergeEntryDlg dlg = new MergeEntryDlg())
            {
                Debug.Assert(argument != null && argument is XCore.Command);
                dlg.SetDlgInfo(cache, m_mediator, currentEntry);
                if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    int       entryID  = dlg.SelectedID;
                    ILexEntry survivor = LexEntry.CreateFromDBObject(cache, entryID);
                    Debug.Assert(survivor != currentEntry);
                    cache.BeginUndoTask(SIL.FieldWorks.LexText.Controls.LexTextControls.ksUndoMergeEntry,
                                        SIL.FieldWorks.LexText.Controls.LexTextControls.ksRedoMergeEntry);
                    // If lexeme forms differ, make the source lexeme form an allomorph of the target entry.
                    if (survivor.LexemeFormOA.Form.VernacularDefaultWritingSystem !=
                        currentEntry.LexemeFormOA.Form.VernacularDefaultWritingSystem)
                    {
                        survivor.AlternateFormsOS.Append(currentEntry.LexemeFormOA.Hvo);
                    }
                    survivor.MergeObject(currentEntry, fLoseNoTextData);
                    cache.EndUndoTask();
                    survivor.DateModified = DateTime.Now;
                    MessageBox.Show(null,
                                    SIL.FieldWorks.LexText.Controls.LexTextControls.ksEntriesHaveBeenMerged,
                                    SIL.FieldWorks.LexText.Controls.LexTextControls.ksMergeReport,
                                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                    m_mediator.SendMessage("JumpToRecord", entryID);
                }
            }
            return(true);
        }
示例#5
0
        /// <summary>
        /// Add the specified type of freeform annotation to the given segment.
        /// Undoable by default.
        /// </summary>
        /// <param name="hvoSeg"></param>
        /// <param name="hvoType">freeform annotation type</param>
        /// <returns></returns>
        public ICmIndirectAnnotation AddFreeformAnnotation(int hvoSeg, int hvoType)
        {
            using (SuppressSubTasks suppressor = new SuppressSubTasks(m_fdoCache, true))
            {
                // convert any preceeding dummy segments, so paragraph parser does not push this to the first dummy sentence. (LT-7318)
                int       hvoPara = m_fdoCache.GetObjProperty(hvoSeg, (int)CmBaseAnnotation.CmBaseAnnotationTags.kflidBeginObject);
                StTxtPara para    = StTxtPara.CreateFromDBObject(m_fdoCache, hvoPara) as StTxtPara;
                para.EnsurePreceedingSegmentsAreReal(hvoSeg);

                string undoString = "";
                string redoString = "";
                if (hvoType == ktagSegFF_freeTranslation)
                {
                    undoString = ITextStrings.ksUndoAddFreeformTranslation;
                    redoString = ITextStrings.ksRedoAddFreeformTranslation;
                }
                else if (hvoType == ktagSegFF_literalTranslation)
                {
                    undoString = ITextStrings.ksUndoAddLiteralTranslation;
                    redoString = ITextStrings.ksRedoAddLiteralTranslation;
                }
                else if (hvoType == ktagSegFF_note)
                {
                    undoString = ITextStrings.ksUndoAddNote;
                    redoString = ITextStrings.ksRedoAddNote;
                }
                else
                {
                    throw new ArgumentException(String.Format("segment freeform type {0} is not yet supported here.", hvoType));
                }
                ICmIndirectAnnotation ann;
                m_fdoCache.BeginUndoTask(undoString, redoString);
                {
                    ann = CmIndirectAnnotation.CreateUnownedIndirectAnnotation(m_fdoCache);
                    ann.AppliesToRS.Append(hvoSeg);
                    ann.AnnotationTypeRAHvo = hvoType;
                    // Add it to the cached collection of freeform annotations. This is a bit clumsy because
                    // it isn't a real property so we can't just use the normal methods for modifying a property.
                    // Enhance JohnT: put it with the other ones of the same type.
                    ISilDataAccess sda       = m_fdoCache.MainCacheAccessor;
                    IVwCacheDa     cda       = (IVwCacheDa)sda;
                    int            cFreeForm = sda.get_VecSize(hvoSeg, ktagSegFF);
                    int[]          freeForms = new int[cFreeForm + 1];
                    for (int i = 0; i < cFreeForm; i++)
                    {
                        freeForms[i] = sda.get_VecItem(hvoSeg, ktagSegFF, i);
                    }
                    freeForms[cFreeForm] = ann.Hvo;
                    cda.CacheVecProp(hvoSeg, ktagSegFF, freeForms, cFreeForm + 1);
                    sda.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoSeg,
                                    ktagSegFF, cFreeForm, 1, 0);
                }
                m_fdoCache.EndUndoTask();
                return(ann);
            }
        }
示例#6
0
 public void HandleDeleteMenuItem(Object src, System.EventArgs ea)
 {
     m_cache.BeginUndoTask(DetailControlsStrings.ksUndoDelete,
                           DetailControlsStrings.ksRedoDelete);
     using (CmObjectUi ui = CmObjectUi.MakeUi(m_cache, m_hvoDeleteTarget))
     {
         ui.Mediator = m_sliceTreeNode.Slice.ContainingDataTree.Mediator;
         ui.DeleteUnderlyingObject();
     }
     m_cache.EndUndoTask();
 }
        public override void AddToDatabase(FdoCache cache)
        {
            CheckDisposed();

            if (m_fInDatabase)
            {
                return;                 // It's already in the database, so nothing more can be done.
            }
            cache.BeginUndoTask(MGAStrings.ksUndoCreateInflectionFeature,
                                MGAStrings.ksRedoCreateInflectionFeature);
            m_featDefn = FsFeatureSystem.AddFeatureAsXml(cache, m_node);
            cache.EndUndoTask();
        }
示例#8
0
 protected virtual void ReallyDeleteReversalIndex(IReversalIndex ri)
 {
     try
     {
         Debug.Assert(ri.Hvo == m_list.OwningObject.Hvo);
         m_list.ListModificationInProgress = true;                       // can't reload deleted list! (LT-5353)
         // Clear out any virtual data stored in the cache for this reversal index.
         IVwCacheDa        cda = m_cache.MainCacheAccessor as IVwCacheDa;
         IVwVirtualHandler vh  = cda.GetVirtualHandlerName("LexSense",
                                                           LexSenseReversalEntriesTextHandler.StandardFieldName);
         if (vh != null)
         {
             int wsDel = ri.WritingSystemRAHvo;
             IEnumerator <IReversalIndexEntry> erie = ri.EntriesOC.GetEnumerator();
             while (erie.MoveNext())
             {
                 foreach (LinkedObjectInfo loi in erie.Current.BackReferences)
                 {
                     if (loi.RelObjClass == (int)LexSense.kClassId)
                     {
                         vh.Load(loi.RelObjId, vh.Tag, wsDel, cda);
                     }
                 }
             }
         }
         m_cache.BeginUndoTask(LexEdStrings.ksUndoDelete, LexEdStrings.ksRedoDelete);
         int cobjOld = m_cache.LangProject.LexDbOA.ReversalIndexesOC.Count;
         ri.DeleteUnderlyingObject();
         int cobjNew;
         int hvoIdxNew = ReversalIndexAfterDeletion(m_cache, out cobjNew);
         m_cache.EndUndoTask();
         SetReversalIndexHvo(hvoIdxNew);
         // Without this, switching to the ReversalEntries tool can crash if it was
         // displaying data from the deleted reversal entry.
         m_cache.PropChanged(null, PropChangeType.kpctNotifyAll,
                             m_cache.LangProject.LexDbOAHvo,
                             (int)LexDb.LexDbTags.kflidReversalIndexes,
                             0, cobjNew, cobjOld);
     }
     finally
     {
         m_list.ListModificationInProgress = false;
     }
     // Can't do this until ListModificationInProgress flag is cleared because it
     // redisplays everything after reloading the list: if the list isn't actually
     // reloaded, it tries to display a deleted object -- CRASH!
     ChangeOwningObjectIfPossible();
     // Without this, stale data can still display in the BulkEditSenses tool if you
     // recreate the deleted reversal index.
     m_mediator.SendMessage("MasterRefresh", null);
 }
示例#9
0
        public void Init()
        {
            CheckDisposed();
            m_builder = new DummySFFileListBuilder();
            m_cache   = FdoCache.Create("TestLangProj");

            if (!m_cache.DatabaseAccessor.IsTransactionOpen())
            {
                m_cache.DatabaseAccessor.BeginTrans();
            }

            m_cache.BeginUndoTask("Undo SfFileListBuilderTest", "Redo SfFileListBuilderTest");

            m_settings = new ScrImportSet();
            m_cache.LangProject.TranslatedScriptureOA.DefaultImportSettings = m_settings;
        }
示例#10
0
        private void AddNewSenseDlg_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            switch (DialogResult)
            {
            default:
            {
                Debug.Assert(false, "Unexpected DialogResult.");
                break;
            }

            case DialogResult.Cancel:
            {
                break;
            }

            case DialogResult.OK:
            {
                if (m_fwtbGloss.Text == String.Empty)
                {
                    e.Cancel = true;
                    MessageBox.Show(this, LexTextControls.ksFillInGloss,
                                    LexTextControls.ksMissingInformation,
                                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                Cursor = Cursors.WaitCursor;

                m_cache.BeginUndoTask(LexTextControls.ksUndoCreateNewSense,
                                      LexTextControls.ksRedoCreateNewSense);

                ILexSense lsNew = m_le.SensesOS.Append(new LexSense());
                lsNew.Gloss.AnalysisDefaultWritingSystem = m_fwtbGloss.Text;

                (lsNew as LexSense).DummyMSA = m_msaGroupBox.DummyMSA;
                m_newSenseID = lsNew.Hvo;

                m_cache.EndUndoTask();

                Cursor = Cursors.Default;
                break;
            }
            }
        }
        public bool OnMoveReversalindexEntry(object cmd)
        {
            using (ReversalEntryGoDlg dlg = new ReversalEntryGoDlg())
            {
                Slice slice = m_dataEntryForm.CurrentSlice;
                Debug.Assert(slice != null, "No slice was current");
                IReversalIndexEntry        currentEntry    = (IReversalIndexEntry)slice.Object;
                List <IReversalIndexEntry> filteredEntries = new List <IReversalIndexEntry>();
                filteredEntries.Add(currentEntry);
                IReversalIndexEntry owningEntry = currentEntry.OwningEntry;
                if (owningEntry != null)
                {
                    filteredEntries.Add(owningEntry);
                }

                WindowParams wp = new WindowParams();
                wp.m_btnText = LexEdStrings.ks_MoveEntry;
                wp.m_label   = LexEdStrings.ks_Find_;
                wp.m_title   = LexEdStrings.ksMoveRevEntry;
                dlg.SetDlgInfo(m_mediator, wp, filteredEntries);                 // , true
                if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    FdoCache            cache    = (FdoCache)m_mediator.PropertyTable.GetValue("cache");
                    IReversalIndexEntry newOwner = ReversalIndexEntry.CreateFromDBObject(cache, dlg.SelectedID);
                    cache.BeginUndoTask(LexEdStrings.ksUndoMoveRevEntry,
                                        LexEdStrings.ksRedoMoveRevEntry);
                    ICmObject newOwningObj = newOwner.MoveIfNeeded(currentEntry);
                    newOwner.SubentriesOC.Add(currentEntry);
                    cache.EndUndoTask();
                    RecordClerk clerk = m_mediator.PropertyTable.GetValue("ActiveClerk") as RecordClerk;
                    if (clerk != null)
                    {
                        clerk.RemoveItemsFor(currentEntry.Hvo);
                    }
                    // Note: PropChanged should happen on the old owner and the new in the 'Add" method call.
                    // Have to jump to a main entry, as RecordClerk doesn't know anything about subentries.
                    m_mediator.BroadcastMessageUntilHandled("JumpToRecord", newOwner.MainEntry.Hvo);
                }
            }

            return(true);
        }
示例#12
0
 private void DoImport()
 {
     _cache.BeginUndoTask(LiftImportStrings.ksUndoLIFTImport, LiftImportStrings.ksRedoLIFTImport);
     try
     {
         FlexLiftMerger flexImporter = new FlexLiftMerger(_cache);
         this.Cursor = Cursors.WaitCursor;
         //    flexImporter.ImportLiftFile(openFileDialog1.FileName);
     }
     //catch (Exception error)
     //{
     //    //TODO: shouldn't there be a method on the cache to cancel the undo task?
     //    MessageBox.Show("Something went wrong while FieldWorks was attempting to import.");
     //    //TODO: is it may be better to just let it die of the normal green box death?
     //}
     finally
     {
         _cache.EndUndoTask();
     }
 }
        public override void AddToDatabase(FdoCache cache)
        {
            CheckDisposed();

            if (m_fInDatabase)
            {
                return;                 // It's already in the database, so nothing more can be done.
            }
            string sType = XmlUtils.GetManditoryAttributeValue(m_node, "type");

            if (sType == "feature")
            {
                cache.BeginUndoTask(MGAStrings.ksUndoCreatePhonologicalFeature,
                                    MGAStrings.ksRedoCreatePhonologicalFeature);
                ILangProject     lp      = cache.LangProject;
                IFsFeatureSystem featsys = lp.PhFeatureSystemOA as IFsFeatureSystem;
                // Since phonological features in the chooser only have features and no values,
                // we need to create the positive and negative value nodes
                string       sName     = XmlUtils.GetManditoryAttributeValue(m_node, "id");
                const string sTemplate =
                    "<item id='v{0}Positive' type='value'><abbrev ws='en'>+</abbrev><term ws='en'>positive</term>" +
                    "<fs id='v{0}PositiveFS' type='Phon'><f name='{0}'><sym value='+'/></f></fs></item>" +
                    "<item id='v{0}Negative' type='value'><abbrev ws='en'>-</abbrev><term ws='en'>negative</term>" +
                    "<fs id='v{0}NegativeFS' type='Phon'><f name='{0}'><sym value='-'/></f></fs></item>";
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat(sTemplate, sName.Substring(1));
                m_node.InnerXml += sb.ToString();
                // have to use a ndw document or, for some odd reason, it keeps on using an old value and not the new one...
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(m_node.OuterXml);
                // add positive value; note that the FsFeatDefn will be the same for both
                XmlNode valueNode = doc.SelectSingleNode("//item[contains(@id,'Positive')]");
                m_featDefn = FsFeatureSystem.AddFeatureAsXml(cache, featsys, valueNode);
                // add negative value
                valueNode  = doc.SelectSingleNode("//item[contains(@id,'Negative')]");
                m_featDefn = FsFeatureSystem.AddFeatureAsXml(cache, featsys, valueNode);
                cache.EndUndoTask();
            }
        }
示例#14
0
            public void AddToDatabase(FdoCache cache, ICmPossibilityList posList, MasterCategory parent, IPartOfSpeech subItemOwner)
            {
                CheckDisposed();

                if (m_pos != null)
                {
                    return;                     // It's already in the database, so nothing more can be done.
                }
                cache.BeginUndoTask(LexTextControls.ksUndoCreateCategory,
                                    LexTextControls.ksRedoCreateCategory);
                int newOwningFlid;
                int insertLocation;
                int newOwner =
                    DeterminePOSLocationInfo(subItemOwner, parent, posList, out newOwningFlid, out insertLocation);
                ILgWritingSystemFactory wsf = cache.LanguageWritingSystemFactoryAccessor;

                Debug.Assert(m_pos != null);

                if (m_node == null)
                {                 // should not happen, but just in case... we still get something useful
                    m_pos.Name.SetAlternative(m_term, wsf.GetWsFromStr(m_termWs));
                    m_pos.Abbreviation.SetAlternative(m_abbrev, wsf.GetWsFromStr(m_abbrevWs));
                    m_pos.Description.SetAlternative(m_def, wsf.GetWsFromStr(m_defWs));
                }
                else
                {
                    SetContentFromNode(cache, "abbrev", false, m_pos.Abbreviation);
                    SetContentFromNode(cache, "term", true, m_pos.Name);
                    SetContentFromNode(cache, "def", false, m_pos.Description);
                }

                m_pos.CatalogSourceId = m_id;
                // Need a PropChanged, since it isn't done in the 'Append' for some reason.
                cache.PropChanged(null, PropChangeType.kpctNotifyAll,
                                  newOwner, newOwningFlid, insertLocation, 1, 0);
                cache.EndUndoTask();
            }
示例#15
0
        /// <summary>
        /// Execute the change requested by the current selection in the combo.
        /// Basically we want the MoInflClass indicated by m_selectedHvo, (even if 0?? not yet possible),
        /// to become the InflectionClass of each record that is appropriate to change.
        /// We do nothing to records where the check box is turned off,
        /// and nothing to ones that currently have an MSA other than an MoStemMsa,
        /// and nothing to ones that currently have an MSA with the wrong POS.
        /// (a) If the owning entry has an MoStemMsa with the right inflection class (and presumably POS),
        /// set the sense to use it.
        /// (b) If all senses using the current MoStemMsa are to be changed, just update
        /// the inflection class of that MoStemMsa.
        /// We could add this...but very probably unused MSAs would have been taken over
        /// when setting the POS.
        /// --(c) If the entry has an MoStemMsa which is not being used at all, change it to
        /// --the required POS and inflection class and use it.
        /// (d) Make a new MoStemMsa in the LexEntry with the required POS and inflection class
        /// and point the sense at it.
        /// </summary>
        public void DoIt(Set <int> itemsToChange, ProgressState state)
        {
            CheckDisposed();

            int hvoPos = GetPOS();
            // A Set of eligible parts of speech to use in filtering.
            Set <int> possiblePOS = GetPossiblePartsOfSpeech();
            // Make a Dictionary from HVO of entry to list of modified senses.
            Dictionary <int, List <ILexSense> > sensesByEntry = new Dictionary <int, List <ILexSense> >();
            int tagOwningEntry = m_cache.VwCacheDaAccessor.GetVirtualHandlerName("LexSense", "OwningEntry").Tag;
            int i = 0;
            // Report progress 50 times or every 100 items, whichever is more (but no more than once per item!)
            int interval = Math.Min(100, Math.Max(itemsToChange.Count / 50, 1));

            foreach (int hvoSense in itemsToChange)
            {
                i++;
                if (i % interval == 0)
                {
                    state.PercentDone = i * 20 / itemsToChange.Count;
                    state.Breath();
                }
                if (!IsItemEligible(m_cache.MainCacheAccessor, hvoSense, possiblePOS))
                {
                    continue;
                }
                ILexSense           ls  = (ILexSense)CmObject.CreateFromDBObject(m_cache, hvoSense, false);
                IMoMorphSynAnalysis msa = ls.MorphoSyntaxAnalysisRA;
                int hvoEntry            = m_cache.MainCacheAccessor.get_ObjectProp(ls.Hvo, tagOwningEntry);
                if (!sensesByEntry.ContainsKey(hvoEntry))
                {
                    sensesByEntry[hvoEntry] = new List <ILexSense>();
                }
                sensesByEntry[hvoEntry].Add(ls);
            }
            m_cache.BeginUndoTask(FdoUiStrings.ksUndoBEInflClass, FdoUiStrings.ksRedoBEInflClass);
            BulkEditBar.ForceRefreshOnUndoRedo(m_cache.MainCacheAccessor);
            i        = 0;
            interval = Math.Min(100, Math.Max(sensesByEntry.Count / 50, 1));
            foreach (KeyValuePair <int, List <ILexSense> > kvp in sensesByEntry)
            {
                i++;
                if (i % interval == 0)
                {
                    state.PercentDone = i * 80 / sensesByEntry.Count + 20;
                    state.Breath();
                }
                ILexEntry        entry          = (ILexEntry)CmObject.CreateFromDBObject(m_cache, kvp.Key, false);
                List <ILexSense> sensesToChange = kvp.Value;
                IMoStemMsa       msmTarget      = null;
                foreach (IMoMorphSynAnalysis msa in entry.MorphoSyntaxAnalysesOC)
                {
                    IMoStemMsa msm = msa as IMoStemMsa;
                    if (msm != null && msm.InflectionClassRAHvo == m_selectedHvo)
                    {
                        // Can reuse this one!
                        msmTarget = msm;
                        break;
                    }
                }
                if (msmTarget == null)
                {
                    // See if we can reuse an existing MoStemMsa by changing it.
                    // This is possible if it is used only by senses in the list, or not used at all.
                    List <ILexSense> otherSenses = new List <ILexSense>();
                    if (entry.SensesOS.Count != sensesToChange.Count)
                    {
                        foreach (ILexSense ls in entry.SensesOS)
                        {
                            if (!sensesToChange.Contains(ls))
                            {
                                otherSenses.Add(ls);
                            }
                        }
                    }
                    foreach (IMoMorphSynAnalysis msa in entry.MorphoSyntaxAnalysesOC)
                    {
                        IMoStemMsa msm = msa as IMoStemMsa;
                        if (msm == null)
                        {
                            continue;
                        }
                        bool fOk = true;
                        foreach (ILexSense ls in otherSenses)
                        {
                            if (ls.MorphoSyntaxAnalysisRA == msm)
                            {
                                fOk = false;
                                break;
                            }
                        }
                        if (fOk)
                        {
                            // Can reuse this one! Nothing we don't want to change uses it.
                            // Adjust its POS as well as its inflection class, just to be sure.
                            msmTarget = msm;
                            msmTarget.PartOfSpeechRAHvo    = hvoPos;
                            msmTarget.InflectionClassRAHvo = m_selectedHvo;
                            break;
                        }
                    }
                }
                if (msmTarget == null)
                {
                    // Nothing we can reuse...make a new one.
                    msmTarget = new MoStemMsa();
                    entry.MorphoSyntaxAnalysesOC.Add(msmTarget);
                    msmTarget.PartOfSpeechRAHvo    = hvoPos;
                    msmTarget.InflectionClassRAHvo = m_selectedHvo;
                }
                // Finally! Make the senses we want to change use it.
                foreach (ILexSense ls in sensesToChange)
                {
                    ls.MorphoSyntaxAnalysisRA = msmTarget;
                }
            }
            m_cache.EndUndoTask();
        }