/// <summary> /// Checks for and reports any disallowed discourse template moves. /// </summary> /// <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(ICmPossibility movingColumn, int hvoTemplate, int hvoTemplateList, int hvoDest) { using (var movingColumnUI = new CmPossibilityUi(movingColumn)) { // 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 (movingColumnUI.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 (m_objRepo.GetObject(hvoDest).Owner.Hvo == hvoTemplate && moveColumnIsLeaf) { ICmPossibility dest = m_possRepo.GetObject(hvoDest); using (var destUI = new CmPossibilityUi(dest)) { // If it isn't already a group, we can only turn it into one if it's empty if (dest.SubPossibilitiesOS.Count == 0) return destUI.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; }
private static CmObjectUi MakeUi(FdoCache cache, int hvo, int clsid) { IFwMetaDataCache mdc = cache.DomainDataByFlid.MetaDataCache; // If we've encountered an object with this Clsid before, and this clsid isn't in // the switch below, the dictioanry will give us the appropriate clsid that IS in the // map, so the loop below will have only one iteration. Otherwise, we start the // search with the clsid of the object itself. int realClsid = m_subclasses.ContainsKey(clsid) ? m_subclasses[clsid] : clsid; // Each iteration investigates whether we have a CmObjectUi subclass that // corresponds to realClsid. If not, we move on to the base class of realClsid. // In this way, the CmObjectUi subclass we return is the one designed for the // closest base class of obj that has one. CmObjectUi result = null; while (result == null) { switch (realClsid) { // Todo: lots more useful cases. case WfiAnalysisTags.kClassId: result = new WfiAnalysisUi(); break; case PartOfSpeechTags.kClassId: result = new PartOfSpeechUi(); break; case CmPossibilityTags.kClassId: result = new CmPossibilityUi(); break; case CmObjectTags.kClassId: result = new CmObjectUi(); break; case LexPronunciationTags.kClassId: result = new LexPronunciationUi(); break; case LexSenseTags.kClassId: result = new LexSenseUi(); break; case LexEntryTags.kClassId: result = new LexEntryUi(); break; case MoMorphSynAnalysisTags.kClassId: result = new MoMorphSynAnalysisUi(); break; case MoStemMsaTags.kClassId: result = new MoStemMsaUi(); break; case MoDerivAffMsaTags.kClassId: result = new MoDerivAffMsaUi(); break; case MoInflAffMsaTags.kClassId: result = new MoInflAffMsaUi(); break; case MoAffixAllomorphTags.kClassId: case MoStemAllomorphTags.kClassId: result = new MoFormUi(); break; case ReversalIndexEntryTags.kClassId: result = new ReversalIndexEntryUi(); break; case WfiWordformTags.kClassId: result = new WfiWordformUi(); break; case WfiGlossTags.kClassId: result = new WfiGlossUi(); break; default: realClsid = mdc.GetBaseClsId(realClsid); // This isn't needed because CmObject.kClassId IS 0. // if (realClsid == 0) // { // // Somehow the class doesn't have CmObject in its inheritance path! // Debug.Assert(false); // // this may help make us more robust if this somehow happens. // realClsid = (uint)CmObject.kClassId; // } break; } } if (realClsid != clsid) m_subclasses[clsid] = realClsid; result.m_hvo = hvo; result.m_cache = cache; return result; }
/// <summary> /// Move the clicked item the specified distance (currently +/- 1) in its owning list. /// </summary> /// <param name="distance"></param> void MoveItem(int distance) { int hvoMove = ClickObject; if (hvoMove == 0) { return; } ICmPossibility column = m_possRepo.GetObject(hvoMove); using (var columnUI = new CmPossibilityUi(column)) { if (columnUI.CheckAndReportProtectedChartColumn()) return; } var owner = column.Owner; if (owner == null) // probably not possible return; int hvoOwner = owner.Hvo; int ownFlid = column.OwningFlid; int oldIndex = m_cache.DomainDataByFlid.GetObjIndex(hvoOwner, ownFlid, column.Hvo); int newIndex = oldIndex + distance; if (newIndex < 0) return; int cobj = m_cache.DomainDataByFlid.get_VecSize(hvoOwner, ownFlid); if (newIndex >= cobj) return; // Without this, we insert it before the next object, which is the one it's already before, // so it doesn't move. if (distance > 0) newIndex++; UndoableUnitOfWorkHelper.Do(xWorksStrings.UndoMoveItem, xWorksStrings.RedoMoveItem, m_cache.ActionHandlerAccessor, () => m_cache.DomainDataByFlid.MoveOwnSeq( hvoOwner, ownFlid, oldIndex, oldIndex, hvoOwner, ownFlid, newIndex)); }
private static bool CheckAndReportBadDiscourseTemplateAdd(FdoCache cache, int hvoItem, int hvoRootItem, int hvoList) { if (cache.ServiceLocator.GetInstance<ICmObjectRepository>().GetObject(hvoList).OwningFlid != 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. ICmPossibility poss = cache.ServiceLocator.GetInstance<ICmPossibilityRepository>().GetObject(hvoItem); using (var col = new CmPossibilityUi(poss)) { // 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 (poss.SubPossibilitiesOS.Count == 0 && poss.Owner is ICmPossibility && col.CheckAndReportProtectedChartColumn()) return true; } // Finally, we have to confirm the three-level rule. var owner = cache.ServiceLocator.GetInstance<ICmObjectRepository>().GetObject(hvoItem).Owner; if (hvoItem != hvoRootItem && owner != null && owner.Hvo != hvoRootItem) { MessageBox.Show(FdoUiStrings.ksTemplateTooDeep, FdoUiStrings.ksHierarchyLimit, MessageBoxButtons.OK, MessageBoxIcon.Warning); return true; } return false; }