/// <summary> /// Process elements for each FactTypeHasRole definition added /// during deserialization. If one of our extension elements is not /// included in the set of extension elements then create a new one /// and add it. /// </summary> /// <param name="element">A Role element</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected sealed override void ProcessElement(Role element, Store store, INotifyElementAdded notifyAdded) { IORMExtendableElement extendableElement = element as IORMExtendableElement; LinkedElementCollection <ModelElement> extensions = extendableElement.ExtensionCollection; int extensionCount = extensions.Count; int i; for (i = 0; i < extensionCount; ++i) { // Look for any of our extension elements if (extensions[i] is MyCustomExtensionElement) { break; } } if (i == extensionCount) { MyCustomExtensionElement customElement = new MyCustomExtensionElement(store); ExtensionElementUtility.AddExtensionElement(extendableElement, customElement); // Always notify during deserialization. All rules are turned off, so // any additions need to be explicitly notified so that other deserialization // fixup listeners can respond appropriately. notifyAdded.ElementAdded(customElement, true); } }
/// <summary> /// This method Validates an ObjectType name. /// If the ObjectType name has a name of "ObjectType" /// followed by any digits it will create a new error. /// </summary> /// <param name="objectType">The ObjectType you wish to be validated.</param> private static void ValidateObjectTypeName(ObjectType objectType, INotifyElementAdded notifyAdded) { ORMModel model; if (!objectType.IsDeleted && null != (model = objectType.Model)) { Regex regex = objectTypeRegex; if (regex == null) { ResourceManager resMgr = ResourceAccessor <ORMModel> .ResourceManager; regex = System.Threading.Interlocked.CompareExchange <Regex>( ref objectTypeRegex, new Regex(string.Format(CultureInfo.InvariantCulture, @"\A({0}|{1})\d+\z", resMgr.GetString("ObjectModel.ValueType"), resMgr.GetString("ObjectModel.EntityType")), RegexOptions.Compiled | RegexOptions.IgnoreCase), null); regex = objectTypeRegex; } string objectTypeName = objectType.Name; Match regexMatch = regex.Match(objectType.Name); LinkedElementCollection <ModelError> extensions = objectType.ExtensionModelErrorCollection; ObjectTypeRequiresMeaningfulNameError nameError = null; int extensionCount = extensions.Count; int i; for (i = 0; i < extensionCount; ++i) { if (extensions[i] is ObjectTypeRequiresMeaningfulNameError) { nameError = extensions[i] as ObjectTypeRequiresMeaningfulNameError; break; } } if (regexMatch.Success) { if (nameError == null) { nameError = new ObjectTypeRequiresMeaningfulNameError(objectType.Store); ExtensionElementUtility.AddExtensionModelError(objectType, nameError); nameError.Model = model; nameError.GenerateErrorText(); if (notifyAdded != null) { notifyAdded.ElementAdded(nameError, true); } } else { nameError.GenerateErrorText(); } } else { if (nameError != null) { nameError.Delete(); } } } }
/// <summary> /// for many-to-many associations; it is assumed that IsSimpleManyToManyAssociation has been /// called on the passed-in concept type and returned true /// </summary> /// <param name="parentConceptType"></param> /// <param name="notifyAdded"></param> /// <param name="associationCounter"></param> private static void CreateBinaryAssociation(ConceptType parentConceptType, INotifyElementAdded notifyAdded, ref int associationCounter) { if (BinaryAssociationHasConceptType.GetBinaryAssociation(parentConceptType).Count == 0) { LinkedElementCollection <ConceptTypeChild> associationChildren = ConceptTypeHasChildAsPartOfAssociation.GetTargetCollection(parentConceptType); ConceptTypeChild relation1, relation2; ConceptType ct1, ct2; if (null != (relation1 = associationChildren[0]) && null != (relation2 = associationChildren[1]) && null != (ct1 = relation1.Target as ConceptType) && null != (ct2 = relation2.Target as ConceptType)) { // create association BinaryAssociation b = new BinaryAssociation(parentConceptType.Store, new PropertyAssignment[] { new PropertyAssignment(BinaryAssociation.NumberDomainPropertyId, associationCounter++) }); //new BinaryAssociationHasConceptTypeChild(b, relation); BinaryAssociationHasConceptType.GetConceptType(b).Add(parentConceptType); Role r1 = new Role(parentConceptType.Store, new PropertyAssignment[] { new PropertyAssignment(Role.PredicateTextDomainPropertyId, ct1.Name) }); Role r2 = new Role(parentConceptType.Store, new PropertyAssignment[] { new PropertyAssignment(Role.PredicateTextDomainPropertyId, ct2.Name) }); b.RoleCollection.Add(r1); b.RoleCollection.Add(r2); EntityType sourceEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(ct1); EntityType targetEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(ct2); sourceEntity.RoleCollection.Add(r1); targetEntity.RoleCollection.Add(r2); sourceEntity.BarkerErModel.BinaryAssociationCollection.Add(b); //determine whether roles are mandatory or optional //TODO //set multi-values r1.IsMultiValued = true; r2.IsMultiValued = true; //notify elements added if (notifyAdded != null) { notifyAdded.ElementAdded(b, true); notifyAdded.ElementAdded(r1, true); notifyAdded.ElementAdded(r2, true); } } } }
/// <summary> /// Verify that ranges are ordered and non-overlapping and handle the /// corresponding error. /// </summary> private void ValidateRanges(INotifyElementAdded notifyAdded) { LinkedElementCollection <CardinalityRange> ranges = RangeCollection; int rangeCount = ranges.Count; int prevMin = -1; int prevMax = -1; bool hasError = false; for (int i = 0; i < rangeCount; ++i) { CardinalityRange range = ranges[i]; int lower = range.LowerBound; int upper = range.UpperBound; if (upper == -1) { upper = int.MaxValue; } if (lower < 0 || lower <= prevMin || lower <= prevMax || upper <= prevMax) { hasError = true; break; } prevMin = lower; prevMax = upper; } CardinalityRangeOverlapError overlapError = this.CardinalityRangeOverlapError; if (hasError) { if (overlapError == null) { overlapError = new CardinalityRangeOverlapError(Partition); overlapError.CardinalityConstraint = this; overlapError.Model = this.Model; overlapError.GenerateErrorText(); if (notifyAdded != null) { notifyAdded.ElementAdded(overlapError, true); } } } else if (overlapError != null) { overlapError.Delete(); } }
/// <summary> /// Implements IDeserializationFixupListener.ProcessElements /// </summary> /// <param name="phase">An integer pulled from the /// phase enum passed to the DeserializationFixupManager constructor.</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected void ProcessElements(int phase, Store store, INotifyElementAdded notifyAdded) { Debug.Assert(HasElements(phase, store)); if (phase == myPhase) { // Clear the collection so it can safely be repopulated while // the iterator is active. Collection <TElement> coll = myCollection; myCollection = null; foreach (TElement element in coll) { // Call the abstract method to do the actual work ProcessElement(element, store, notifyAdded); } } }
/// <summary> /// Implements IModelErrorOwner.ValidateErrors (empty implementation) /// </summary> protected static void ValidateErrors(INotifyElementAdded notifyAdded) { }
/// <summary> /// Make sure we have our tracker attached to all loaded models. /// </summary> /// <param name="element">An ORMModel element</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected sealed override void ProcessElement(ORMModel element, Store store, INotifyElementAdded notifyAdded) { OIALModel oil = OIALModelHasORMModel.GetOIALModel(element); if (oil == null) { oil = new OIALModel(store); oil.ORMModel = element; notifyAdded.ElementAdded(oil, true); } }
/// <summary> /// Implements IModelErrorOwner.ValidateErrors /// </summary> protected new void ValidateErrors(INotifyElementAdded notifyAdded) { // Calls added here need corresponding delayed calls in DelayValidateErrors ValidateRanges(notifyAdded); }
/// <summary> /// Update the shape size on load. /// </summary> protected sealed override void ProcessElement(ModelNoteShape element, Store store, INotifyElementAdded notifyAdded) { element.AutoResize(); }
/// <summary> /// Implements IModelErrorOwner.ValidateErrors /// </summary> protected new void ValidateErrors(INotifyElementAdded notifyAdded) { ValidateRoleCountError(notifyAdded); }
/// <summary> /// for regular relationships /// </summary> /// <param name="relation"></param> /// <param name="source"></param> /// <param name="target"></param> /// <param name="notifyAdded"></param> /// <param name="associationCounter"></param> /// <returns></returns> private static bool CreateBinaryAssociation(ConceptTypeChild relation, ConceptType source, ConceptType target, INotifyElementAdded notifyAdded, ref int associationCounter) { if (BinaryAssociationHasConceptTypeChild.GetBinaryAssociation(relation).Count > 0) { //it has already been created return(true); } else if (EntityTypeIsPrimarilyForConceptType.GetEntityType(target) != null) { #region create association BinaryAssociation b = new BinaryAssociation(relation.Store, new PropertyAssignment[] { new PropertyAssignment(BinaryAssociation.NumberDomainPropertyId, associationCounter++) }); //new BinaryAssociationHasConceptTypeChild(b, relation); BinaryAssociationHasConceptTypeChild.GetConceptTypeChildPath(b).Add(relation); Role r1 = new Role(relation.Store, new PropertyAssignment[] { new PropertyAssignment(Role.PredicateTextDomainPropertyId, source.Name) }); Role r2 = new Role(relation.Store, new PropertyAssignment[] { new PropertyAssignment(Role.PredicateTextDomainPropertyId, target.Name) }); b.RoleCollection.Add(r1); b.RoleCollection.Add(r2); EntityType sourceEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(source); EntityType targetEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(target); sourceEntity.RoleCollection.Add(r1); targetEntity.RoleCollection.Add(r2); sourceEntity.BarkerErModel.BinaryAssociationCollection.Add(b); #endregion //determine whether roles are mandatory or optional List <ConceptTypeChild> links = new List <ConceptTypeChild>(1); links.Add(relation); r1.IsMandatory = AllStepsMandatory(targetEntity, links); if (relation is ConceptTypeAssimilatesConceptType) { r2.IsMandatory = AllStepsMandatory(sourceEntity, links); } #region determine whether roles are multivalued or not - and possibly rename ORMCore.ObjectType sourceObjectType = ConceptTypeIsForObjectType.GetObjectType(source); ORMCore.ObjectType targetObjectType = ConceptTypeIsForObjectType.GetObjectType(target); ORMCore.UniquenessConstraint uSource = null, uTarget = null; foreach (ORMCore.FactType factType in ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(relation)) { Debug.Assert(factType.RoleCollection.Count == 2, "Error when mapping to Barker ER; the fact type is not binary"); foreach (ORMCore.RoleBase r in factType.RoleCollection) { //need to use RoleBase because we might run into RoleProxy ORMCore.Role role = r.Role; foreach (ORMCore.ConstraintRoleSequence constraintRoleSequence in role.ConstraintRoleSequenceCollection) { ORMCore.UniquenessConstraint uninquenessConstraint = constraintRoleSequence as ORMCore.UniquenessConstraint; if (uninquenessConstraint != null && //check that it's a uniqueness constraint uninquenessConstraint.Modality == ORMCore.ConstraintModality.Alethic && //check it's alethic uninquenessConstraint.IsInternal) //check it's internal { if (role.RolePlayer == sourceObjectType) { uSource = uninquenessConstraint; } if (role.RolePlayer == targetObjectType) { uTarget = uninquenessConstraint; } } } } //name the roles properly //TODO this is a hack; proper name generation is yet to be implemented foreach (ORMCore.ReadingOrder order in factType.ReadingOrderCollection) { string text = order.ReadingText; int first = text.IndexOf('}') + 1; text = text.Substring(first, text.LastIndexOf('{') - first); text = text.Trim(); if (!string.IsNullOrEmpty(text) && order.RoleCollection != null && order.RoleCollection.Count > 0 && order.RoleCollection[0].Role != null) { ORMCore.ObjectType o = order.RoleCollection[0].Role.RolePlayer; if (o == sourceObjectType) { r1.PredicateText = text; } else if (o == targetObjectType) { r2.PredicateText = text; } } } } if (uSource != null && uSource == uTarget) { //it's many-to-many r1.IsMultiValued = true; r2.IsMultiValued = true; } else if (uSource == null || uTarget == null) { //it's one-to-many r1.IsMultiValued = uSource != null; r2.IsMultiValued = uTarget != null; } else if (uSource != null && uTarget != null) { //it's one-to-one r1.IsMultiValued = false; r2.IsMultiValued = false; } else { Debug.Fail("Found a fact type with no uniqueness constraints!"); } #endregion #region primary id? foreach (Uniqueness u in UniquenessIncludesConceptTypeChild.GetUniquenessCollection(relation)) { if (u.IsPreferred) { r1.IsPrimaryIdComponent = true; break; } } #endregion //notify elements added if (notifyAdded != null) { notifyAdded.ElementAdded(b, true); notifyAdded.ElementAdded(r1, true); notifyAdded.ElementAdded(r2, true); } return(true); } else { //should not create binary association in this case return(false); } }
private static void CreateAttributesAndBinaryRelationships(ConceptType conceptType, INotifyElementAdded notifyAdded, ref int associationCounter) { List <Attribute> attributesForConceptType = new List <Attribute>(); foreach (InformationType informationType in InformationType.GetLinksToInformationTypeFormatCollection(conceptType)) { attributesForConceptType.Add(CreateAttributeForInformationType(informationType, new Stack <ConceptTypeChild>())); } foreach (ConceptTypeRelatesToConceptType conceptTypeRelation in ConceptTypeRelatesToConceptType.GetLinksToRelatedConceptTypeCollection(conceptType)) { if (!CreateBinaryAssociation(conceptTypeRelation, conceptType, conceptTypeRelation.RelatedConceptType, notifyAdded, ref associationCounter)) { //if binary association was not created - let's create an attribute for it attributesForConceptType.AddRange(GetAttributesForConceptTypeRelation(conceptTypeRelation, new Stack <ConceptTypeChild>())); } } foreach (ConceptTypeAssimilatesConceptType conceptTypeAssimilation in ConceptTypeAssimilatesConceptType.GetLinksToAssimilatedConceptTypeCollection(conceptType)) { if (!conceptTypeAssimilation.RefersToSubtype) { CreateBinaryAssociation(conceptTypeAssimilation, conceptType, conceptTypeAssimilation.AssimilatedConceptType, notifyAdded, ref associationCounter); } } EntityType conceptTypeEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(conceptType); if (conceptTypeEntity != null) { conceptTypeEntity.AttributeCollection.AddRange(attributesForConceptType); if (notifyAdded != null) { foreach (Attribute attr in attributesForConceptType) { notifyAdded.ElementAdded(attr, true); } } } }
/// <summary> /// Makes sure that any <see cref="NameAlias"/> that fails to resolve is deleted. /// </summary> /// <param name="element">NameAlias element</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected sealed override void ProcessElement(NameAlias element, Store store, INotifyElementAdded notifyAdded) { element.DeleteIfTypeBindingFailed(); }
/// <summary> /// Utility function to verify that a role player is present for all roles /// </summary> private void VerifyRolePlayerRequiredForRule(INotifyElementAdded notifyAdded) { if (!IsDeleted) { bool hasRolePlayer = true; RolePlayerRequiredError rolePlayerRequired; if (null == RolePlayer) { FactType fact = FactType; // Don't show an error for roles on implied fact types, // this is controlled indirectly by the nested roles if (null != fact && null == fact.ImpliedByObjectification) { hasRolePlayer = false; if (null == RolePlayerRequiredError) { rolePlayerRequired = new RolePlayerRequiredError(Store); rolePlayerRequired.Role = this; rolePlayerRequired.Model = fact.Model; rolePlayerRequired.GenerateErrorText(); if (notifyAdded != null) { notifyAdded.ElementAdded(rolePlayerRequired, true); } } } } if (hasRolePlayer) { if (null != (rolePlayerRequired = RolePlayerRequiredError)) { rolePlayerRequired.Delete(); } } } }
/// <summary> /// Implements IModelErrorOwner.ValidateErrors /// Validate all errors on the external constraint. This /// is called during deserialization fixup when rules are /// suspended. /// </summary> /// <param name="notifyAdded">A callback for notifying /// the caller of all objects that are added.</param> protected new void ValidateErrors(INotifyElementAdded notifyAdded) { // Calls added here need corresponding delayed calls in DelayValidateErrors VerifyRolePlayerRequiredForRule(notifyAdded); ValidatePopulationUniquenessError(notifyAdded); }
/// <summary> /// Binarizes the unary <see cref="FactType"/> specified by <paramref name="unaryFactType"/>, defaulting /// to using open-world assumption. The caller is responsible for making sure <paramref name="unaryFactType"/> /// is in fact a unary fact type. /// </summary> public static void BinarizeUnary(FactType unaryFactType, INotifyElementAdded notifyAdded) { Store store = unaryFactType.Store; LinkedElementCollection<RoleBase> roleCollection = unaryFactType.RoleCollection; Debug.Assert(roleCollection.Count == 1, "Unaries should only have one role."); Role unaryRole = (Role)roleCollection[0]; string implicitBooleanValueTypeName = GetImplicitBooleanValueTypeName(unaryRole); // UNDONE: We are using open-world assumption now // Setup the mandatory constraint (for closed-world assumption) //MandatoryConstraint mandatoryConstraint = MandatoryConstraint.CreateSimpleMandatoryConstraint(unaryRole); //mandatoryConstraint.Model = unaryFactType.Model; //if (notifyAdded != null) //{ // notifyAdded.ElementAdded(mandatoryConstraint, true); //} // Setup the uniqueness constraint (to make the newly binarized FactType valid) if (unaryRole.SingleRoleAlethicUniquenessConstraint == null) { UniquenessConstraint uniquenessConstraint = UniquenessConstraint.CreateInternalUniquenessConstraint(unaryFactType); uniquenessConstraint.RoleCollection.Add(unaryRole); uniquenessConstraint.Model = unaryFactType.Model; if (notifyAdded != null) { notifyAdded.ElementAdded(uniquenessConstraint, true); } } // Setup the boolean role (to make the FactType a binary) Role implicitBooleanRole = new Role(store, null); implicitBooleanRole.Name = unaryRole.Name; // Setup the boolean value type (because the boolean role needs a role player) ObjectType implicitBooleanValueType = new ObjectType(store, new PropertyAssignment(ObjectType.IsImplicitBooleanValueDomainPropertyId, true)); Dictionary<object, object> contextInfo = store.TransactionManager.CurrentTransaction.TopLevelTransaction.Context.ContextInfo; try { contextInfo[ORMModel.AllowDuplicateNamesKey] = null; implicitBooleanValueType.Name = implicitBooleanValueTypeName; implicitBooleanValueType.Model = unaryFactType.Model; if (notifyAdded != null) { notifyAdded.ElementAdded(implicitBooleanValueType, true); } } finally { contextInfo.Remove(ORMModel.AllowDuplicateNamesKey); } implicitBooleanValueType.DataType = store.ElementDirectory.FindElements<TrueOrFalseLogicalDataType>(false)[0]; // Set value constraint on implicit boolean ValueType for open-world assumption ValueTypeValueConstraint implicitBooleanValueConstraint = implicitBooleanValueType.ValueConstraint = new ValueTypeValueConstraint(implicitBooleanValueType.Store, null); // Add the true-only ValueRange to the value constraint for open-world assumption implicitBooleanValueConstraint.ValueRangeCollection.Add(new ValueRange(store, new PropertyAssignment(ValueRange.MinValueDomainPropertyId, bool.TrueString), new PropertyAssignment(ValueRange.MaxValueDomainPropertyId, bool.TrueString))); // Make the boolean value type the role player for the implicit boolean role implicitBooleanRole.RolePlayer = implicitBooleanValueType; // Add the boolean role to the FactType roleCollection.Add(implicitBooleanRole); if (notifyAdded != null) { notifyAdded.ElementAdded(implicitBooleanRole, true); } }
public static void ProcessFactType(FactType factType, INotifyElementAdded notifyAdded) { LinkedElementCollection<RoleBase> roleCollection = factType.RoleCollection; int roleCollectionCount = roleCollection.Count; if (roleCollectionCount == 1) { // If we have a unary, binarize it BinarizeUnary(factType, notifyAdded); return; } else if (roleCollectionCount == 2) { // If we have a binary that has an implicit boolean role in it, make sure it matches the pattern Role implicitBooleanRole = GetImplicitBooleanRole(roleCollection); if (implicitBooleanRole != null) { Role unaryRole = implicitBooleanRole.OppositeRole.Role; Debug.Assert(unaryRole != null); // Make sure the implicit boolean role has the same name as the unary role implicitBooleanRole.Name = unaryRole.Name; string implicitBooleanValueTypeName = GetImplicitBooleanValueTypeName(unaryRole); if (implicitBooleanRole.RolePlayer.Name != implicitBooleanValueTypeName) { Dictionary<object, object> contextInfo = factType.Store.TransactionManager.CurrentTransaction.TopLevelTransaction.Context.ContextInfo; try { contextInfo[ORMModel.AllowDuplicateNamesKey] = null; implicitBooleanRole.RolePlayer.Name = implicitBooleanValueTypeName; } finally { contextInfo.Remove(ORMModel.AllowDuplicateNamesKey); } } if (!ValidateConstraints(unaryRole, implicitBooleanRole) || !ValidateImplicitBooleanValueType(implicitBooleanRole.RolePlayer)) { LinkedElementCollection<RoleBase> roles = factType.RoleCollection; DebinarizeUnary(roles, false, notifyAdded); // Append to the reading orders LinkedElementCollection<ReadingOrder> readingOrders = factType.ReadingOrderCollection; int readingOrderCount = readingOrders.Count; for (int i = 0; i < readingOrderCount; ++i) { ReadingOrder order = readingOrders[i]; LinkedElementCollection<RoleBase> readingRoles = order.RoleCollection; if (!readingRoles.Contains(implicitBooleanRole)) { readingRoles.Add(implicitBooleanRole); LinkedElementCollection<Reading> readings = order.ReadingCollection; int readingCount = readings.Count; for (int j = 0; j < readingCount; ++j) { readings[j].SetAutoText(readings[j].Text + " {1}"); } } } } } } else { // If we have an n-ary, remove any implicit boolean roles in it for (int i = roleCollectionCount - 1; i >= 0; --i) { Role implicitBooleanRole = roleCollection[i].Role; if (implicitBooleanRole != null && implicitBooleanRole.RolePlayer != null && implicitBooleanRole.RolePlayer.IsImplicitBooleanValue) { DebinarizeUnary(factType.RoleCollection, true, notifyAdded); break; } } } }
/// <summary> /// Verify that an abstraction model has an appropriate Barker ER model and bridge /// </summary> protected override void ProcessElement(AbstractionModel element, Store store, INotifyElementAdded notifyAdded) { BarkerErModel barkerModel = BarkerErModelIsForAbstractionModel.GetBarkerErModel(element); if (barkerModel == null) { // Create the initial Barker ER model and notify barkerModel = new BarkerErModel( store, new PropertyAssignment[] { new PropertyAssignment(BarkerErModel.NameDomainPropertyId, element.Name) }); new BarkerErModelIsForAbstractionModel(barkerModel, element); BarkerERModelGenerationSetting generationSetting = new BarkerERModelGenerationSetting(store, new PropertyAssignment( BarkerERModelGenerationSetting.CoreAlgorithmVersionDomainPropertyId, CurrentCoreAlgorithmVersion), new PropertyAssignment( BarkerERModelGenerationSetting.NameAlgorithmVersionDomainPropertyId, CurrentNameAlgorithmVersion)); new GenerationSettingTargetsBarkerERModel(generationSetting, barkerModel); new ORMCore.GenerationStateHasGenerationSetting(ORMCore.GenerationState.EnsureGenerationState(store), generationSetting); notifyAdded.ElementAdded(barkerModel, true); FullyGenerateBarkerERModel(barkerModel, element, notifyAdded); } else { BarkerERModelGenerationSetting generationSetting = GenerationSettingTargetsBarkerERModel.GetGenerationSetting(barkerModel); bool regenerateAll = generationSetting == null || generationSetting.CoreAlgorithmVersion != CurrentCoreAlgorithmVersion; bool regenerateNames = false; if (!regenerateAll) { foreach (EntityType barkerEntity in barkerModel.EntityTypeCollection) { if (null == EntityTypeIsPrimarilyForConceptType.GetLinkToConceptType(barkerEntity)) { regenerateAll = true; break; } // Theoretically we should also check that all attributes and uniqueness constraints // are pathed back to the abstraction model. However, this is far from a full validation, // and the scenario we're trying to cover is the abstraction model regenerating during // load and removing our bridge elements. The entity type check above is sufficient. } regenerateNames = !regenerateAll && generationSetting.NameAlgorithmVersion != CurrentNameAlgorithmVersion; generationSetting.NameAlgorithmVersion = CurrentNameAlgorithmVersion; } else { if (generationSetting == null) { generationSetting = new BarkerERModelGenerationSetting(store, new PropertyAssignment( BarkerERModelGenerationSetting.CoreAlgorithmVersionDomainPropertyId, CurrentCoreAlgorithmVersion), new PropertyAssignment( BarkerERModelGenerationSetting.NameAlgorithmVersionDomainPropertyId, CurrentNameAlgorithmVersion)); new GenerationSettingTargetsBarkerERModel(generationSetting, barkerModel); new ORMCore.GenerationStateHasGenerationSetting(ORMCore.GenerationState.EnsureGenerationState(store), generationSetting); } else { regenerateNames = generationSetting.NameAlgorithmVersion != CurrentNameAlgorithmVersion; generationSetting.CoreAlgorithmVersion = CurrentCoreAlgorithmVersion; generationSetting.NameAlgorithmVersion = CurrentNameAlgorithmVersion; } } if (regenerateAll) { barkerModel.BinaryAssociationCollection.Clear(); barkerModel.EntityTypeCollection.Clear(); barkerModel.ExclusiveArcCollection.Clear(); FullyGenerateBarkerERModel(barkerModel, element, notifyAdded); } else if (regenerateNames) { //NameGeneration.GenerateAllNames(barkerModel); } } }
/// <summary> /// Override this method to process an element /// for this phase. /// </summary> /// <param name="element">A typed element. The element /// is always castable to a model element</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected abstract void ProcessElement(TElement element, Store store, INotifyElementAdded notifyAdded);
private static void FullyGenerateBarkerERModel(BarkerErModel barkerModel, AbstractionModel sourceModel, INotifyElementAdded notifyAdded) { LinkedElementCollection <EntityType> barkerEntities = barkerModel.EntityTypeCollection; LinkedElementCollection <ConceptType> conceptTypes = sourceModel.ConceptTypeCollection; Store store = barkerModel.Store; // Generate all Barker entities List <ConceptType> manyToMany = new List <ConceptType>(); foreach (ConceptType conceptType in conceptTypes) { if (!IsSimpleManyToManyAssociation(conceptType)) { EntityType entity = new EntityType( conceptType.Store, new PropertyAssignment[] { new PropertyAssignment(EntityType.NameDomainPropertyId, conceptType.Name) }); new EntityTypeIsPrimarilyForConceptType(entity, conceptType); barkerEntities.Add(entity); if (notifyAdded != null) { notifyAdded.ElementAdded(entity, true); } } else { manyToMany.Add(conceptType); } } // For every concept type create all attributes that they represent, map uniquenesses that they participate in. int associationCounter = 0; foreach (ConceptType conceptType in conceptTypes) { if (!manyToMany.Contains(conceptType)) { CreateAttributesAndBinaryRelationships(conceptType, notifyAdded, ref associationCounter); } else { CreateBinaryAssociation(conceptType, notifyAdded, ref associationCounter); } } // For each entity type in the Barker model generate relationships it plays and detemine which of its atrributes are mandatory and nullable. foreach (EntityType entity in barkerModel.EntityTypeCollection) { GenerateMandatoryConstraints(entity); } }
/// <summary> /// Make sure we have our tracker attached to all loaded models. /// </summary> /// <param name="element">An ORMModel element</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected sealed override void ProcessElement(ORMModel element, Store store, INotifyElementAdded notifyAdded) { AbstractionModel oil = AbstractionModelIsForORMModel.GetAbstractionModel(element); if (oil == null) { // UNDONE: DelayValidateModel currently deletes and recreates any existing // bridge relationship, so there is no point deleting it up front, we'll // just retrieve it later. Also note that DelayValidateModel does not call notifyAdded. DelayValidateModel(element); oil = AbstractionModelIsForORMModel.GetAbstractionModel(element); if (oil != null) { notifyAdded.ElementAdded(oil, true); } } else { AbstractionModelGenerationSetting generationSetting; bool regenerateForVersion = null == (generationSetting = GenerationSettingTargetsAbstractionModel.GetGenerationSetting(oil)) || generationSetting.AlgorithmVersion != CurrentAlgorithmVersion; bool excludedBridgedElement = false; ORMElementGateway.Initialize( element, regenerateForVersion ? (ORMElementGateway.NotifyORMElementExcluded) null : delegate(ORMModelElement modelElement) { if (excludedBridgedElement) { return; } ObjectType objectType; FactType factType; // Note that the types we're checking here are synchronized with the ORMElementGateway.ExclusionAdded method if (null != (objectType = modelElement as ObjectType)) { if (null != ConceptTypeIsForObjectType.GetLinkToConceptType(objectType) || null != InformationTypeFormatIsForValueType.GetLinkToInformationTypeFormat(objectType)) { excludedBridgedElement = true; } } else if (null != (factType = modelElement as FactType)) { if (null != FactTypeMapsTowardsRole.GetLinkToTowardsRole(factType) || ConceptTypeChildHasPathFactType.GetLinksToConceptTypeChild(factType).Count != 0) { excludedBridgedElement = true; } } }); if (regenerateForVersion || excludedBridgedElement) { // Something is very wrong, regenerate (does not regenerate the excluded elements we already have) DelayValidateModel(element); } } }
/// <summary> /// Defer to the IModelErrorOwner.ValidateErrors method /// to fixup error problems. /// </summary> /// <param name="element">An IModelErrorOwner instance</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected sealed override void ProcessElement(IModelErrorOwner element, Store store, INotifyElementAdded notifyAdded) { element.ValidateErrors(notifyAdded); }
/// <summary> /// Process diagram items to make sure they have a current ordering representation /// </summary> protected sealed override void ProcessElement(Diagram element, Store store, INotifyElementAdded notifyAdded) { DiagramDisplayHasDiagramOrder link = DiagramDisplayHasDiagramOrder.GetLinkToDiagramDisplay(element); DiagramDisplay container = myDiagramDisplay; if (container == null) { if (link != null) { container = link.DiagramDisplay; } // Make sure we only have one container, use the one we've already grabbed ReadOnlyCollection <DiagramDisplay> containers = store.ElementDirectory.FindElements <DiagramDisplay>(false); int containerCount = containers.Count; for (int i = containerCount - 1; i >= 0; --i) { DiagramDisplay testContainer = containers[i]; if (container != null) { if (testContainer != container) { testContainer.Delete(); } } else if (i == 0) { container = testContainer; } else { testContainer.Delete(); } } if (container == null) { container = new DiagramDisplay(store); notifyAdded.ElementAdded(container, false); } myDiagramDisplay = container; if (link != null) { // There is nothing else to do, the element has been validated if (link.IsActiveDiagram) { if (mySeenActive) { link.IsActiveDiagram = false; } else { mySeenActive = true; } } return; } } if (link == null) { // This will add to the end of the existing collection link = new DiagramDisplayHasDiagramOrder(container, element); notifyAdded.ElementAdded(link, false); } else { if (link.DiagramDisplay != container) { link.DiagramDisplay = container; } if (link.IsActiveDiagram) { if (mySeenActive) { link.IsActiveDiagram = false; } else { mySeenActive = true; } } } }
/// <summary> /// Make sure the subtype fact constraint pattern /// and object types are appropriate. /// </summary> /// <param name="element">An SubtypeFact instance</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected sealed override void ProcessElement(SubtypeFact element, Store store, INotifyElementAdded notifyAdded) { // Note that the arity and types of the subtype/supertype roles are // enforced by the schema. Role superTypeMetaRole; Role subTypeMetaRole; ObjectType superType; ObjectType subType; bool valueTypeSubtype; if (null == (superTypeMetaRole = element.SupertypeRole) || null == (subTypeMetaRole = element.SubtypeRole) || null == (superType = superTypeMetaRole.RolePlayer) || null == (subType = subTypeMetaRole.RolePlayer) || // They must both be value types or object types, but can't switch ((valueTypeSubtype = (superType.DataType != null)) == (subType.DataType == null))) { RemoveFactType(element); } else { // UNDONE: We can still save explicit readings, but we won't // be able to load these in later file formats. Get rid of any serialized readings. element.ReadingOrderCollection.Clear(); Partition partition = element.Partition; // Note that rules aren't on, so we can read the Multiplicity properties, // but we can't set them. All changes must be made explicitly. if (superTypeMetaRole.Multiplicity != RoleMultiplicity.ExactlyOne) { EnsureSingleColumnUniqueAndMandatory(element, subTypeMetaRole, true, notifyAdded); } if (subTypeMetaRole.Multiplicity != RoleMultiplicity.ZeroToOne) { EnsureSingleColumnUniqueAndMandatory(element, superTypeMetaRole, false, notifyAdded); } // Switch to using the new ProvidesPreferredIdentifier path property instead of the deprecated // IsPrimary. Other equivalent paths for preferred identification are marked later in the load process. if (element.IsPrimary) { // UNDONE: Remove IsPrimary after file format change, make this // check in the format upgrade transform element.ProvidesPreferredIdentifier = true; element.IsPrimary = false; } if (valueTypeSubtype) { element.ProvidesPreferredIdentifier = true; } // Move any derivation expressions to the subtype. // Note that derivation paths have never been written to the .orm file // on a subtype, so we just look for the older expression form. // UNDONE: Do this during file format upgrade transformation FactTypeDerivationExpression factTypeDerivationExpression; if (null != (factTypeDerivationExpression = element.DerivationExpression)) { string ruleBody = factTypeDerivationExpression.Body; if (!string.IsNullOrEmpty(ruleBody)) { ObjectType subtype = element.Subtype; SubtypeDerivationExpression derivationExpression = subtype.DerivationExpression; SubtypeDerivationRule derivationRule = subtype.DerivationRule; DerivationNote derivationNote; string existingBody; // Check both the old and deprecated expression forms. Note that the derivation // expression will be merged into a note on the derivation path in another fixup // listener, so we do not need to handle merging here. if (derivationExpression == null && derivationRule == null) { notifyAdded.ElementAdded(derivationRule = new SubtypeDerivationRule( partition, new PropertyAssignment(SubtypeDerivationRule.ExternalDerivationDomainPropertyId, true))); notifyAdded.ElementAdded(new SubtypeHasDerivationRule(subtype, derivationRule)); notifyAdded.ElementAdded(derivationNote = new DerivationNote( partition, new PropertyAssignment(DerivationNote.BodyDomainPropertyId, ruleBody))); notifyAdded.ElementAdded(new SubtypeDerivationRuleHasDerivationNote(derivationRule, derivationNote)); } else if (derivationRule != null) { if (null != (derivationNote = derivationRule.DerivationNote)) { existingBody = derivationExpression.Body; derivationNote.Body = string.IsNullOrEmpty(existingBody) ? ruleBody : existingBody + "\r\n" + ruleBody; } else { notifyAdded.ElementAdded(derivationNote = new DerivationNote( partition, new PropertyAssignment(DerivationNote.BodyDomainPropertyId, ruleBody))); notifyAdded.ElementAdded(new SubtypeDerivationRuleHasDerivationNote(derivationRule, derivationNote)); } } else { existingBody = derivationExpression.Body; derivationExpression.Body = string.IsNullOrEmpty(existingBody) ? ruleBody : existingBody + "\r\n" + ruleBody; } } factTypeDerivationExpression.Delete(); } } }
private static void EnsureSingleColumnUniqueAndMandatory(SubtypeFact subtypeFact, Role role, bool requireMandatory, INotifyElementAdded notifyAdded) { LinkedElementCollection <ConstraintRoleSequence> sequences = role.ConstraintRoleSequenceCollection; int sequenceCount = sequences.Count; bool haveUniqueness = false; bool haveMandatory = !requireMandatory; SetConstraint ic; for (int i = sequenceCount - 1; i >= 0; --i) { ic = sequences[i] as SetConstraint; if (ic != null && ic.Constraint.ConstraintIsInternal) { if (ic.RoleCollection.Count == 1 && ic.Modality == ConstraintModality.Alethic) { switch (ic.Constraint.ConstraintType) { case ConstraintType.InternalUniqueness: if (haveUniqueness) { ic.Delete(); } else { haveUniqueness = true; } break; case ConstraintType.SimpleMandatory: if (haveMandatory) { ic.Delete(); } else { haveMandatory = true; } break; } } else { ic.Delete(); } } } if (!haveUniqueness || !haveMandatory) { IHasAlternateOwner <FactType> toAlternateOwner; IAlternateElementOwner <SetConstraint> alternateConstraintOwner; if (null != (toAlternateOwner = subtypeFact as IHasAlternateOwner <FactType>) && null != (alternateConstraintOwner = toAlternateOwner.AlternateOwner as IAlternateElementOwner <SetConstraint>)) { if (!haveUniqueness) { ic = UniquenessConstraint.CreateInternalUniquenessConstraint(subtypeFact); ic.RoleCollection.Add(role); notifyAdded.ElementAdded(ic, true); } } if (!haveMandatory) { ic = MandatoryConstraint.CreateSimpleMandatoryConstraint(role); notifyAdded.ElementAdded(ic, true); } } }
void IDeserializationFixupListener.ProcessElements(int phase, Store store, INotifyElementAdded notifyAdded) { Debug.Fail("Shouldn't be called if HasElements returns false"); }
void IModelErrorOwner.ValidateErrors(INotifyElementAdded notifyAdded) { ValidateErrors(notifyAdded); }
/// <summary> /// Add subtype links when possible /// </summary> /// <param name="element">An ModelHasFactType instance</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected sealed override void ProcessElement(ModelHasFactType element, Store store, INotifyElementAdded notifyAdded) { SubtypeFact subTypeFact = element.FactType as SubtypeFact; ORMModel model; if (null != (subTypeFact = element.FactType as SubtypeFact) && !subTypeFact.IsDeleted && null != (model = subTypeFact.Model)) { ObjectType rolePlayer = subTypeFact.Subtype; FactType nestedFact = rolePlayer.NestedFactType; if (FactTypeShape.ShouldDrawObjectification(nestedFact)) { Diagram.FixUpDiagram(model, nestedFact); Diagram.FixUpDiagram(nestedFact, rolePlayer); } else { Diagram.FixUpDiagram(model, rolePlayer); } rolePlayer = subTypeFact.Supertype; nestedFact = rolePlayer.NestedFactType; if (FactTypeShape.ShouldDrawObjectification(nestedFact)) { Diagram.FixUpDiagram(model, nestedFact); Diagram.FixUpDiagram(nestedFact, rolePlayer); } else { Diagram.FixUpDiagram(model, rolePlayer); } object AllowMultipleShapes; Dictionary <object, object> topLevelContextInfo; bool containedAllowMultipleShapes; if (!(containedAllowMultipleShapes = (topLevelContextInfo = store.TransactionManager.CurrentTransaction.TopLevelTransaction.Context.ContextInfo).ContainsKey(AllowMultipleShapes = MultiShapeUtility.AllowMultipleShapes))) { topLevelContextInfo.Add(AllowMultipleShapes, null); } foreach (PresentationViewsSubject presentationViewsSubject in DomainRoleInfo.GetElementLinks <PresentationViewsSubject>(model, PresentationViewsSubject.SubjectDomainRoleId)) { ORMDiagram diagram; if ((diagram = presentationViewsSubject.Presentation as ORMDiagram) != null) { ObjectType subtype = subTypeFact.Subtype; // add a link shape for each object type shape on the diagram for the played role foreach (ObjectTypeShape shapeElement in MultiShapeUtility.FindAllShapesForElement <ObjectTypeShape>(diagram, subtype)) { diagram.FixUpLocalDiagram(subTypeFact); } FactType objectifiedFactType; if (null != (objectifiedFactType = subtype.NestedFactType)) { foreach (FactTypeShape shapeElement in MultiShapeUtility.FindAllShapesForElement <FactTypeShape>(diagram, objectifiedFactType)) { diagram.FixUpLocalDiagram(subTypeFact); } } } } if (!containedAllowMultipleShapes) { topLevelContextInfo.Remove(AllowMultipleShapes); } } }
/// <summary> /// Adds the specified machine level group to the model. /// </summary> /// <param name="store">Target store</param> /// <param name="groupXMLNode">The group to add to the model.</param> /// <param name="activeForm">The current form</param> /// <param name="notifyAdded">Used during deserialization fixup</param> private static void AddGroupToModel(Store store, XmlNode groupXMLNode, CustomPropertiesManager activeForm, INotifyElementAdded notifyAdded) { CustomPropertyGroup grp = new CustomPropertyGroup(store); grp.Name = groupXMLNode.Attributes["name"].Value; grp.Description = groupXMLNode.Attributes["description"].Value; if (notifyAdded != null) { notifyAdded.ElementAdded(grp, false); } TreeNode newGroupTreeNode = null; if (activeForm != null) { newGroupTreeNode = activeForm._modelNode.Nodes.Add(grp.Name); newGroupTreeNode.Tag = grp; activeForm.tvCustomProperties.SelectedNode = newGroupTreeNode; } XmlNodeList xmlDefinitions = groupXMLNode.SelectNodes("def:CustomPropertyDefinition", _namespaceManager); foreach (XmlNode xmlDef in xmlDefinitions) { CustomPropertyDefinition def = new CustomPropertyDefinition(store); XmlAttributeCollection attributes = xmlDef.Attributes; def.CustomPropertyGroup = grp; def.Name = attributes["name"].Value; def.Category = attributes["category"].Value; def.Description = attributes["description"].Value; def.DataType = (CustomPropertyDataType)Enum.Parse(typeof(CustomPropertyDataType), attributes["dataType"].Value, true); XmlAttribute defaultValueAttribute = attributes["defaultValue"]; if (defaultValueAttribute != null) { def.DefaultValue = defaultValueAttribute.Value; } XmlAttribute verbalizeDefaultAttribute = attributes["verbalizeDefaultValue"]; if (verbalizeDefaultAttribute != null) { string verbalizeDefaultText = verbalizeDefaultAttribute.Value.Trim(); def.VerbalizeDefaultValue = verbalizeDefaultText == "true" || verbalizeDefaultText == "1"; } XmlNodeList types = xmlDef.SelectNodes("def:ORMTypes/def:ORMType", _namespaceManager); foreach (XmlNode ormType in types) { def.ORMTypes = def.ORMTypes | (ORMTypes)Enum.Parse(typeof(ORMTypes), ormType.Attributes["name"].Value, true); } if (notifyAdded != null) { notifyAdded.ElementAdded(def, true); } if (newGroupTreeNode != null) { newGroupTreeNode.Nodes.Add(def.Name).Tag = def; } } }
/// <summary> /// Move settings from the machine file into the model if they are not there already /// </summary> protected override void ProcessElement(ORMModel element, Store store, INotifyElementAdded notifyAdded) { EnsureMachineDocument(); ApplyDefaultGroups(store, null, notifyAdded); }
/// <summary> /// Reverses the binarization process performed by <see cref="BinarizeUnary"/>. Typically used when /// <paramref name="binarizedUnaryFactRoleCollection"/> no longer qualifies as the roles for a /// binarized unary <see cref="FactType"/>. /// </summary> private static void DebinarizeUnary(LinkedElementCollection<RoleBase> binarizedUnaryFactRoleCollection, bool deleteImplicitBooleanRole, INotifyElementAdded notifyAdded) { // UNDONE: We need to make sure the debinarization happens BEFORE the implied Objectification rules run on the binarized unary FactType. // The default implied role is the second one, walk the collection backwards int roleCount = binarizedUnaryFactRoleCollection.Count; for (int i = roleCount - 1; i >= 0; --i) { Role implicitBooleanRole; ObjectType implicitBooleanValueType; if (null != (implicitBooleanRole = binarizedUnaryFactRoleCollection[i].Role) && null != (implicitBooleanValueType = implicitBooleanRole.RolePlayer) && implicitBooleanValueType.IsImplicitBooleanValue) { // Delete the implicit boolean value type (which will also remove any value constraints on it) // Note that changes to IsImplicitBooleanValue are intentionally blocked so that the // deleted implied ValueType can be identified as such by events as well as rules. // implicitBooleanValueType.IsImplicitBooleanValue = false; bool ruleDisabled = false; RuleManager ruleManager = null; try { if (notifyAdded == null) { ruleManager = implicitBooleanRole.Store.RuleManager; ruleManager.DisableRule(typeof(ObjectTypePlaysRoleDeletedRuleClass)); ruleDisabled = true; } if (deleteImplicitBooleanRole) { // We delete the role first so that rules do not // try to recreate and implied fact type for this rule // if it is part of an objectified FactType. implicitBooleanRole.Delete(); --roleCount; if (!implicitBooleanValueType.IsDeleted) { // The Objectification.RolePlayerDeletingRule rule will delet this automatically implicitBooleanValueType.Delete(); } } else { implicitBooleanValueType.Delete(); } } finally { if (ruleDisabled) { ruleManager.EnableRule(typeof(ObjectTypePlaysRoleDeletedRuleClass)); } } // Clear implied constraints for (int j = 0; j < roleCount; ++j) { Role role = binarizedUnaryFactRoleCollection[j] as Role; if (role != null) { if (role != implicitBooleanRole) { role.Name = ""; } UniquenessConstraint singleRoleAlethicUniquenessConstraint = role.SingleRoleAlethicUniquenessConstraint; if (singleRoleAlethicUniquenessConstraint != null) { // Delete the uniqueness constraint singleRoleAlethicUniquenessConstraint.Delete(); } // UNDONE: We are using open-world assumption now //MandatoryConstraint simpleMandatoryConstraint = role.SimpleMandatoryConstraint; //if (simpleMandatoryConstraint != null && simpleMandatoryConstraint.Modality == ConstraintModality.Alethic) //{ // // Delete the simple mandatory constraint (for closed-world assumption), if present // simpleMandatoryConstraint.Delete(); //} } } break; } } }
/// <summary> /// Goes through all of the machine level groups that are marked as default /// and adds them to the model if needed. /// </summary> /// <param name="store">The current store</param> /// <param name="activeForm">An active form</param> /// <param name="notifyAdded">Used during deserialization fixup</param> private static void ApplyDefaultGroups(Store store, CustomPropertiesManager activeForm, INotifyElementAdded notifyAdded) { XmlNodeList defaultGroups = _loadedDoc.SelectNodes("//def:CustomPropertyGroup[@isDefault='true']", _namespaceManager); Dictionary <CustomPropertyGroup, List <CustomPropertyDefinition> > groupsAndDefs = GetGroupsAndDefsFromStore(store); foreach (XmlNode xmlGroup in defaultGroups) { string groupName = xmlGroup.Attributes["name"].Value; if (!ListHasGroupName(groupsAndDefs, groupName)) { AddGroupToModel(store, xmlGroup, activeForm, notifyAdded); } } }
/// <summary> /// Update the shape size. /// </summary> protected sealed override void ProcessElement(ValueConstraintShape element, Store store, INotifyElementAdded notifyAdded) { if (!element.IsDeleted) { element.AutoResize(); } }
void IDeserializationFixupListener.ProcessElements(int phase, Store store, INotifyElementAdded notifyAdded) { ProcessElements(phase, store, notifyAdded); }
/// <summary> /// Process objectification elements /// </summary> protected sealed override void ProcessElement(ModelErrorDisplayFilter element, Store store, INotifyElementAdded notifyAdded) { if (!element.IsDeleted) { if (string.IsNullOrEmpty(element.myExcludedCategoriesList) && string.IsNullOrEmpty(element.myExcludedErrorsList) && string.IsNullOrEmpty(element.myIncludedErrorsList)) { element.Delete(); } } }
/// <summary> /// Empty implementation /// </summary> protected sealed override void ProcessElement(NameGenerator element, Store store, INotifyElementAdded notifyAdded) { // Everything happens in PhaseCompleted }
/// <summary> /// Compares number of roles in ReadingOrder ot the place holders in /// the reading and then creates or removes errors as needed. /// </summary> private void ValidateRoleCountError(INotifyElementAdded notifyAdded) { if (!IsDeleted) { bool removeTooFew = false; bool removeTooMany = false; TooFewReadingRolesError tooFewError; TooManyReadingRolesError tooManyError; ReadingOrder readingOrder = ReadingOrder; FactType factType = readingOrder.FactType; ORMModel theModel = factType.Model; Store store = Store; LinkedElementCollection<RoleBase> orderRoles = readingOrder.RoleCollection; int numRoles = orderRoles.Count; int deletingCount = 0; for (int i = 0; i < numRoles; ++i) { if (orderRoles[i].IsDeleting) { ++deletingCount; } } numRoles -= deletingCount; int numPlaces = Reading.PlaceholderCount(Text); if (numRoles == numPlaces) { removeTooFew = true; removeTooMany = true; } //too few roles else if (numRoles < numPlaces) { removeTooMany = true; if (null == (tooFewError = TooFewRolesError)) { tooFewError = new TooFewReadingRolesError(store); tooFewError.Reading = this; tooFewError.Model = theModel; tooFewError.GenerateErrorText(); if (notifyAdded != null) { notifyAdded.ElementAdded(tooFewError, true); } } else { tooFewError.GenerateErrorText(); } } //too many roles else { removeTooFew = true; if (factType.UnaryRole == null) { if (null == (tooManyError = TooManyRolesError)) { tooManyError = new TooManyReadingRolesError(store); tooManyError.Reading = this; tooManyError.Model = theModel; tooManyError.GenerateErrorText(); if (notifyAdded != null) { notifyAdded.ElementAdded(tooManyError, true); } } else { tooManyError.GenerateErrorText(); } } } if (removeTooFew && null != (tooFewError = TooFewRolesError)) { tooFewError.Delete(); } if (removeTooMany && null != (tooManyError = TooManyRolesError)) { tooManyError.Delete(); } } }