/// <summary> /// AddRule: typeof(SetComparisonConstraintHasRoleSequence) /// Validate subtype external constraint patterns when a role sequence /// is added with preexisting roles /// </summary> private static void LimitSubtypeSetComparisonConstraintSequenceAddRule(ElementAddedEventArgs e) { SetComparisonConstraintHasRoleSequence link = e.ModelElement as SetComparisonConstraintHasRoleSequence; SetComparisonConstraintRoleSequence sequence = link.RoleSequence; LinkedElementCollection <Role> roles = sequence.RoleCollection; int roleCount = roles.Count; if (roleCount != 0) { SetComparisonConstraint constraint = link.ExternalConstraint; bool isExclusion = constraint is ExclusionConstraint; bool isSubset = !isExclusion && constraint is SubsetConstraint; bool addExclusionDelayValidate = false; bool addSubtypeDelayValidate = false; for (int i = 0; i < roleCount; ++i) { Role untypedRole = roles[i]; if (untypedRole is SubtypeMetaRole) { ThrowInvalidSubtypeMetaRoleConstraint(); } else if (isExclusion) { addExclusionDelayValidate = true; } else if (isSubset) { addSubtypeDelayValidate = true; } else if (untypedRole is SupertypeMetaRole) { ThrowInvalidSupertypeMetaRoleConstraint(); } } if (addExclusionDelayValidate) { FrameworkDomainModel.DelayValidateElement(constraint, DelayValidateSupertypeExclusionSingleColumnOnly); } else if (addSubtypeDelayValidate) { FrameworkDomainModel.DelayValidateElement(constraint, DelayValidateSupertypeSubsetPattern); } } }
/// <summary> /// Create a connection between an ExternalConstraintShape and a FactType. Roles /// used in the connection are stored with the currently active connect action. /// </summary> /// <param name="sourceShapeElement">The source of the requested connection</param> /// <param name="targetShapeElement">The target of the requested connection</param> /// <param name="paintFeedbackArgs">PaintFeedbackArgs</param> public override void CreateConnection(ShapeElement sourceShapeElement, ShapeElement targetShapeElement, PaintFeedbackArgs paintFeedbackArgs) { ExternalConstraintShape constraintShape; IConstraint constraint; ExternalConstraintConnectAction action; IList<Role> selectedRoles; int rolesCount; if ((null != (constraintShape = sourceShapeElement as ExternalConstraintShape)) && (null != (constraint = constraintShape.AssociatedConstraint)) && (null != (action = (sourceShapeElement.Diagram as ORMDiagram).ExternalConstraintConnectAction)) && (null != (selectedRoles = action.SelectedRoleCollection)) && (0 != (rolesCount = selectedRoles.Count))) { SetComparisonConstraint mcConstraint; SetConstraint scConstraint; ConstraintRoleSequence modifyRoleSequence = null; if (null != (mcConstraint = constraint as SetComparisonConstraint)) { ConstraintRoleSequence constraintRoleSequenceBeingEdited = action.ConstraintRoleSequenceToEdit; // Add a new role set if (null == constraintRoleSequenceBeingEdited) { LinkedElementCollection<SetComparisonConstraintRoleSequence> roleSequences = mcConstraint.RoleSequenceCollection; if (action.mySubtypeConnection) { // All editing is done as a single column, add role sequences to the constraint // instead of roles to the sequence Store store = mcConstraint.Store; for (int i = 0; i < rolesCount; ++i) { SetComparisonConstraintRoleSequence roleSequence = new SetComparisonConstraintRoleSequence(store); roleSequence.RoleCollection.Add(selectedRoles[i]); roleSequences.Add(roleSequence); } } else { SetComparisonConstraintRoleSequence roleSequence = new SetComparisonConstraintRoleSequence(mcConstraint.Store); LinkedElementCollection<Role> roles = roleSequence.RoleCollection; for (int i = 0; i < rolesCount; ++i) { roles.Add(selectedRoles[i]); } roleSequences.Add(roleSequence); } } else if (action.mySubtypeConnection) { LinkedElementCollection<SetComparisonConstraintRoleSequence> existingSequences = mcConstraint.RoleSequenceCollection; int existingSequenceCount = existingSequences.Count; // Pull out removed ones first for (int i = existingSequenceCount - 1; i >= 0; --i) { SetComparisonConstraintRoleSequence existingSequence = existingSequences[i]; LinkedElementCollection<Role> sequenceRoles = existingSequence.RoleCollection; if (sequenceRoles.Count != 1 || !selectedRoles.Contains(sequenceRoles[0])) { existingSequences.Remove(existingSequence); --existingSequenceCount; } } Store store = mcConstraint.Store; for (int i = 0; i < rolesCount; ++i) { Role selectedRole = selectedRoles[i]; int existingIndex = -1; for (int j = 0; j < existingSequenceCount; ++j) { if (existingSequences[j].RoleCollection[0] == selectedRole) { existingIndex = j; break; } } if (existingIndex == -1) { SetComparisonConstraintRoleSequence roleSequence = new SetComparisonConstraintRoleSequence(store); roleSequence.RoleCollection.Add(selectedRoles[i]); if (i < existingSequenceCount) { existingSequences.Insert(i, roleSequence); } else { existingSequences.Add(roleSequence); } ++existingSequenceCount; } else if (existingIndex != i) { existingSequences.Move(existingIndex, i); } } } // Edit the existing role set. else { modifyRoleSequence = constraintRoleSequenceBeingEdited; } } else if (null != (scConstraint = constraint as SetConstraint)) { // The single-column constraint is its own role set, just add the roles. modifyRoleSequence = scConstraint; switch (constraint.ConstraintType) { case ConstraintType.ExternalUniqueness: case ConstraintType.Frequency: // Translate selected unary roles back to the implied role bool duplicatedSelectedRoles = false; for (int i = 0; i < rolesCount; ++i) { Role testRole = selectedRoles[i]; Role oppositeRole; ObjectType oppositeRolePlayer; if (null != (oppositeRole = testRole.OppositeRole as Role) && null != (oppositeRolePlayer = oppositeRole.RolePlayer) && oppositeRolePlayer.IsImplicitBooleanValue) { if (!duplicatedSelectedRoles) { duplicatedSelectedRoles = true; Role[] dupRoles = new Role[rolesCount]; selectedRoles.CopyTo(dupRoles, 0); selectedRoles = dupRoles; } selectedRoles[i] = oppositeRole; } } break; } } if (modifyRoleSequence != null) { // Note that we don't just blow away the collection here, there are too // many side effects (such as removing the preferred identifier when a compatible // link is added) LinkedElementCollection<Role> roles = modifyRoleSequence.RoleCollection; int existingRolesCount = roles.Count; for (int i = existingRolesCount - 1; i >= 0; --i) { Role testRole = roles[i]; if (!selectedRoles.Contains(testRole)) { roles.Remove(testRole); --existingRolesCount; } } for (int i = 0; i < rolesCount; ++i) { Role selectedRole = selectedRoles[i]; int existingIndex = roles.IndexOf(selectedRole); if (existingIndex == -1) { if (i < existingRolesCount) { roles.Insert(i, selectedRole); } else if (!roles.Contains(selectedRole)) { roles.Add(selectedRole); } ++existingRolesCount; } else if (existingIndex != i) { roles.Move(existingIndex, i); } } } } }