/// <summary> /// Implements <see cref="IModelingEventSubscriber.ManageModelingEventHandlers"/>. /// </summary> protected void ManageModelingEventHandlers(ModelingEventManager eventManager, EventSubscriberReasons reasons, EventHandlerAction action) { // UNDONE: If we delay attach user interface events (possible in the future for // external model scenarios), then we need to check ModelStateEvents here and // be more precise in which events are attached that affect model state such as // calculated shape size. Currently, this is only called without 'UserInterfaceEvents' // for unit-testing. if ((EventSubscriberReasons.DocumentLoaded | EventSubscriberReasons.UserInterfaceEvents) == (reasons & (EventSubscriberReasons.DocumentLoaded | EventSubscriberReasons.UserInterfaceEvents))) { Store store = Store; ORMDiagram.ManageEventHandlers(store, eventManager, action); ORMBaseShape.ManageEventHandlers(store, eventManager, action); ReadingShape.ManageEventHandlers(store, eventManager, action); ExternalConstraintShape.ManageEventHandlers(store, eventManager, action); RolePlayerLink.ManageEventHandlers(store, eventManager, action); ObjectTypeShape.ManageEventHandlers(store, eventManager, action); ORMBaseBinaryLinkShape.ManageEventHandlers(store, eventManager, action); FactTypeShape.ManageEventHandlers(store, eventManager, action); SubtypeLink.ManageEventHandlers(store, eventManager, action); } if (0 != (reasons & EventSubscriberReasons.DocumentLoaded)) { IORMToolServices services; IORMExtendableElementService extendableElementService; if (null != (services = Store as IORMToolServices) && null != (extendableElementService = services.ExtendableElementService)) { extendableElementService.RegisterExtensionRoles(new Guid[] { ORMDiagramHasExtensionElement.ExtensionDomainRoleId, ORMBaseShapeHasExtensionElement.ExtensionDomainRoleId }); } } }
/// <summary> /// Initialize paint settings. This is initialized after the base shape /// has been painted. /// </summary> public PaintHelper(DiagramPaintEventArgs e, ExternalConstraintShape constraintShape) { StyleSet styleSet = constraintShape.StyleSet; StyleSetResourceId penId = constraintShape.OutlinePenId; Pen pen = styleSet.GetPen(penId); Brush brush = styleSet.GetBrush(ExternalConstraintBrush); SolidBrush coloredBrush = brush as SolidBrush; // Keep the pen color in sync with the color being used for highlighting Color startColor = constraintShape.UpdateDynamicColor(constraintShape.OutlinePenId, pen); if (startColor.IsEmpty) { startColor = constraintShape.UpdateGeometryLuminosity(e.View, pen); } else { constraintShape.UpdateGeometryLuminosity(e.View, pen); } myPenStartColor = startColor; Color newColor = pen.Color; if (coloredBrush != null) { myBrushStartColor = coloredBrush.Color; coloredBrush.Color = newColor; } else { myBrushStartColor = Color.Empty; } myBrush = brush; myPen = pen; }
private static void DelayValidateExternalConstraintShapeFullyConnected(ModelElement element) { if (!element.IsDeleted) { ExternalConstraintShape shape = (ExternalConstraintShape)element; int linkCount = 0; foreach (LinkConnectsToNode link in LinkConnectsToNode.GetLinksToLink(shape)) { if (link.Link is ExternalConstraintLink) { ++linkCount; } } bool keepShape = false; IConstraint constraint = shape.AssociatedConstraint; switch (constraint.ConstraintStorageStyle) { case ConstraintStorageStyle.SetConstraint: keepShape = ((SetConstraint)constraint).FactTypeCollection.Count == linkCount; break; case ConstraintStorageStyle.SetComparisonConstraint: keepShape = ((SetComparisonConstraint)constraint).FactTypeCollection.Count == linkCount; break; } if (!keepShape) { shape.Delete(); } } }
/// <summary> /// DeleteRule: typeof(ORMSolutions.ORMArchitect.Core.ObjectModel.ExclusiveOrConstraintCoupler), FireTime=TopLevelCommit, Priority=DiagramFixupConstants.AddShapeRulePriority; /// Split a single shape into two shapes when a exclusion constraint /// is decoupled from a mandatory constraint /// </summary> private static void ExclusiveOrCouplerDeletedRule(ElementDeletedEventArgs e) { ExclusiveOrConstraintCoupler link = e.ModelElement as ExclusiveOrConstraintCoupler; MandatoryConstraint mandatory = link.MandatoryConstraint; ExclusionConstraint exclusion = link.ExclusionConstraint; if (!mandatory.IsDeleted && !exclusion.IsDeleted) { LinkedElementCollection <PresentationElement> pels = PresentationViewsSubject.GetPresentation(mandatory); int pelCount = pels.Count; for (int i = 0; i < pelCount; ++i) { ExternalConstraintShape shape = pels[i] as ExternalConstraintShape; if (shape != null) { ORMDiagram diagram = (ORMDiagram)shape.Diagram; RectangleD bounds = shape.AbsoluteBounds; double width = bounds.Width; bounds.Offset(-width / 2, 0); bounds = diagram.BoundsRules.GetCompliantBounds(shape, bounds); shape.AbsoluteBounds = bounds; bounds.Offset(width, 0); diagram.PlaceORMElementOnDiagram(null, exclusion, bounds.Location, ORMPlacementOption.None, null, null); } } } }
/// <summary> /// Helper function for preferred identifier validation /// </summary> private static void InvalidateForPreferredIdentifier(UniquenessConstraint constraint) { if (!constraint.IsInternal && !constraint.IsDeleted) { foreach (PresentationElement pel in PresentationViewsSubject.GetPresentation(constraint)) { ExternalConstraintShape constraintShape = pel as ExternalConstraintShape; if (constraintShape != null) { constraintShape.Invalidate(true); } } } }
/// <summary> /// AddRule: typeof(ORMSolutions.ORMArchitect.Core.ObjectModel.ExclusiveOrConstraintCoupler), FireTime=TopLevelCommit, Priority=DiagramFixupConstants.AddShapeRulePriority; /// Remove shapes associated with the exclusion constraint /// when exclusion and mandatory constraints are coupled. /// </summary> private static void ExclusiveOrCouplerAddedRule(ElementAddedEventArgs e) { ExclusiveOrConstraintCoupler link = e.ModelElement as ExclusiveOrConstraintCoupler; MandatoryConstraint mandatory = link.MandatoryConstraint; ExclusionConstraint exclusion = link.ExclusionConstraint; LinkedElementCollection <PresentationElement> pels = PresentationViewsSubject.GetPresentation(exclusion); for (int i = pels.Count - 1; i >= 0; --i) { ExternalConstraintShape shape = pels[i] as ExternalConstraintShape; if (shape != null) { shape.Delete(); } } InvalidateAssociatedDisplay(mandatory); }
private static void UpdateShapeSize(FrequencyConstraint constraint) { // Resize the frequency constraint wherever it is displayed, and make sure // the object type is made visible in the same location. foreach (PresentationElement pel in PresentationViewsSubject.GetPresentation(constraint)) { ExternalConstraintShape externalConstraintShape = pel as ExternalConstraintShape; if (externalConstraintShape != null) { SizeD oldSize = externalConstraintShape.Size; externalConstraintShape.AutoResize(); if (oldSize == externalConstraintShape.Size) { ((IInvalidateDisplay)externalConstraintShape).InvalidateRequired(true); } } } }
/// <summary> /// DeletingRule: typeof(Microsoft.VisualStudio.Modeling.Diagrams.LinkConnectsToNode) /// External constraint shapes can only be drawn if they show all of their /// links, so automatically remove them if a connecting shape is removed. /// </summary> private static void VerifyConnectedShapeShapeDeletingRule(ElementDeletingEventArgs e) { LinkConnectsToNode connectLink = (LinkConnectsToNode)e.ModelElement; ExternalConstraintLink link; ModelElement linkMel; ModelElement shapeMel; if (null != (link = connectLink.Link as ExternalConstraintLink) && null != (linkMel = link.ModelElement) && !linkMel.IsDeleting) { NodeShape linkNode = connectLink.Nodes; ExternalConstraintShape constraintShape = linkNode as ExternalConstraintShape; NodeShape oppositeShape = null; // The ToShape (as opposed to FromShape) here needs to be in // sync with the code in ConfiguringAsChildOf if (constraintShape == null) { constraintShape = link.ToShape as ExternalConstraintShape; oppositeShape = linkNode; } else { oppositeShape = link.FromShape; } if (oppositeShape != null && constraintShape != null && null != (shapeMel = constraintShape.ModelElement) && !shapeMel.IsDeleting) { if (!constraintShape.IsDeleting) { FrameworkDomainModel.DelayValidateElement(constraintShape, DelayValidateExternalConstraintShapeFullyConnected); } // Delay, fact type shape size will not be accurate until deletion is completed. FactTypeShape factTypeShape = MultiShapeUtility.ResolvePrimaryShape(oppositeShape) as FactTypeShape; if (factTypeShape != null && !factTypeShape.IsDeleting) { FrameworkDomainModel.DelayValidateElement(factTypeShape, DelayValidateFactTypeShapeSize); } } } }
/// <summary> /// Implements <see cref="IModelingEventSubscriber.ManageModelingEventHandlers"/>. /// </summary> protected void ManageModelingEventHandlers(ModelingEventManager eventManager, EventSubscriberReasons reasons, EventHandlerAction action) { // UNDONE: If we delay attach user interface events (possible in the future for // external model scenarios), then we need to check ModelStateEvents here and // be more precise in which events are attached that affect model state such as // calculated shape size. Currently, this is only called without 'UserInterfaceEvents' // for unit-testing. if ((EventSubscriberReasons.DocumentLoaded | EventSubscriberReasons.UserInterfaceEvents) == (reasons & (EventSubscriberReasons.DocumentLoaded | EventSubscriberReasons.UserInterfaceEvents))) { Store store = Store; ORMBaseShape.ManageEventHandlers(store, eventManager, action); ReadingShape.ManageEventHandlers(store, eventManager, action); ExternalConstraintShape.ManageEventHandlers(store, eventManager, action); RolePlayerLink.ManageEventHandlers(store, eventManager, action); ObjectTypeShape.ManageEventHandlers(store, eventManager, action); ORMBaseBinaryLinkShape.ManageEventHandlers(store, eventManager, action); FactTypeShape.ManageEventHandlers(store, eventManager, action); SubtypeLink.ManageEventHandlers(store, eventManager, action); } }
/// <summary> /// Initialize paint settings. This is initialized after the base shape /// has been painted. /// </summary> public PaintHelper(DiagramPaintEventArgs e, ExternalConstraintShape constraintShape) { StyleSet styleSet = constraintShape.StyleSet; StyleSetResourceId penId = constraintShape.OutlinePenId; Pen pen = styleSet.GetPen(penId); Brush brush = styleSet.GetBrush(ExternalConstraintBrush); SolidBrush coloredBrush = brush as SolidBrush; // Keep the pen color in sync with the color being used for highlighting Color startColor = constraintShape.UpdateDynamicColor(constraintShape.OutlinePenId, pen); if (startColor.IsEmpty) { startColor = constraintShape.UpdateGeometryLuminosity(e.View, pen); } else { constraintShape.UpdateGeometryLuminosity(e.View, pen); } myPenStartColor = startColor; Color newColor = pen.Color; if (coloredBrush != null) { myBrushStartColor = coloredBrush.Color; coloredBrush.Color = newColor; } else { myBrushStartColor = Color.Empty; } myBrush = brush; myPen = pen; }
/// <summary> /// An IMS event to track the shape element added to the associated /// diagram during this connect action. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ExternalConstraintShapeAddedEvent(object sender, ElementAddedEventArgs e) { if (myAddedConstraintShape == null) { ExternalConstraintShape candidate = e.ModelElement as ExternalConstraintShape; // Make sure the shape was added to the diagram associated with this // connect action if (candidate != null && candidate.Diagram == Diagram) { myAddedConstraintShape = candidate; } } }
/// <summary> /// Central function to return member variables to a clean state. /// Called by the constructor and the deactivation sequence. /// </summary> private void Reset() { myAddedConstraintShape = null; }
/// <summary> /// Set this mouse action as the active action on the /// diagram of the given shape, and activate its drag line /// centered on the shape. /// </summary> /// <param name="attachToShape">The shape for the constraint /// being connected.</param> /// <param name="clientView">The active DiagramClientView</param> public void ChainMouseAction(ExternalConstraintShape attachToShape, DiagramClientView clientView) { DiagramView activeView = Diagram.ActiveDiagramView; if (activeView != null) { // Move on to the selection action clientView.ActiveMouseAction = this; // Now emulate a mouse click in the middle of the added constraint. The click // actions provide a starting point for the connect action, so a mouse move // provides a drag line. Point emulateClickPoint = clientView.WorldToDevice(attachToShape.AbsoluteCenter); DiagramMouseEventArgs mouseEventArgs = new DiagramMouseEventArgs(new MouseEventArgs(MouseButtons.Left, 1, emulateClickPoint.X, emulateClickPoint.Y, 0), clientView); MouseDown(mouseEventArgs); Click(new DiagramPointEventArgs(emulateClickPoint.X, emulateClickPoint.Y, PointRelativeTo.Client, clientView)); MouseUp(mouseEventArgs); // An extra move lets us chain when the mouse is not on the design surface, // such as when we are being activated via the task list. MouseMove(mouseEventArgs); ORMDiagram.SelectToolboxItem(activeView, ResourceStrings.ToolboxExternalConstraintConnectorItemId); } }
private void Reset() { myConstraintRoleSequence = null; myInitialSelectedRoles = null; mySelectedRoles = null; mySourceShape = null; myActiveConstraint = null; myPendingOnClickedAction = OnClickedAction.Normal; mySubtypeConnection = false; myAllowSubtypeConnection = false; FactTypeShape.ActiveExternalConstraintConnectAction = null; }
/// <summary> /// Add a source shape or commit/cancel the action by forwarding the /// click to the base class, or modify the current role sequence by handling /// the click locally. /// </summary> /// <param name="e">MouseActionEventArgs</param> protected override void OnClicked(MouseActionEventArgs e) { switch (myPendingOnClickedAction) { case OnClickedAction.Commit: myPendingOnClickedAction = OnClickedAction.Normal; // Letting the click through to the base ConnectAction // at this point (a constraint is selected and a role has been // double-clicked) will force the connect action to finish. base.OnClicked(e); return; case OnClickedAction.CheckForCommit: myPendingOnClickedAction = OnClickedAction.Normal; break; } DiagramMouseEventArgs args = CurrentDiagramArgs as DiagramMouseEventArgs; if (args != null) { DiagramItem item = args.DiagramHitTestInfo.HitDiagramItem; ModelElement currentElement = null; bool isSupertypeRole = false; ORMDiagram ormDiagram; foreach (ModelElement elem in item.RepresentedElements) { currentElement = elem; SubtypeLink subtypeLink = currentElement as SubtypeLink; if (subtypeLink != null) { isSupertypeRole = true; currentElement = subtypeLink.AssociatedSubtypeFact.SupertypeRole; } break; } ExternalConstraintShape constraintShape; Role role; if (null != (constraintShape = currentElement as ExternalConstraintShape)) { if (mySourceShape == null) { // Let the click through to the base to officially begin the drag action base.OnClicked(e); mySourceShape = constraintShape; IConstraint activeConstraint = constraintShape.AssociatedConstraint; myActiveConstraint = activeConstraint; switch (activeConstraint.ConstraintType) { case ConstraintType.DisjunctiveMandatory: // This setting is refined later myAllowSubtypeConnection = true; break; case ConstraintType.Exclusion: ExclusionConstraint exclusion = (ExclusionConstraint)activeConstraint; // If the exclusion constraint is currently attached to any fact types // that are not subtype facts, then we cannot allow a subtype connection. LinkedElementCollection<FactType> exclusionFactTypes = exclusion.FactTypeCollection; myAllowSubtypeConnection = (exclusionFactTypes.Count == 0) ? true : exclusionFactTypes[0] is SubtypeFact; break; default: myAllowSubtypeConnection = false; break; } if (null != (ormDiagram = mySourceShape.Diagram as ORMDiagram)) { ormDiagram.StickyObject = constraintShape; } } } else if (null != (role = currentElement as Role)) { // Add or remove the role IList<Role> roles = SelectedRoleCollection; int roleIndex = roles.IndexOf(role); bool forceRedraw = false; int redrawIndexBound = -1; ExternalConstraintShape sourceShape = mySourceShape; if (roleIndex >= 0) { // Only remove a role when the control key is down. Otherwise, // there is no way to double-click on a previously selected // role without turning it off, and this is a natural gesture. // Add shift key as well for discoverability. if (0 != (0xff00 & GetKeyState(Keys.ControlKey)) || 0 != (0xff00 & GetKeyState(Keys.ShiftKey))) { forceRedraw = true; roles.RemoveAt(roleIndex); redrawIndexBound = roles.Count; if (roles.Count == 0 && mySubtypeConnection && InitialRoles.Count == 0) { mySubtypeConnection = false; } } } else { bool allowAdd = false; if (mySubtypeConnection) { allowAdd = isSupertypeRole; } else if (isSupertypeRole) { if (roles.Count == 0 && InitialRoles.Count == 0 && myAllowSubtypeConnection) { mySubtypeConnection = true; allowAdd = true; } } else { allowAdd = true; } if (allowAdd) { forceRedraw = true; roles.Add(role); } else { sourceShape = null; } } if (sourceShape != null) { myPendingOnClickedAction = OnClickedAction.CheckForCommit; } if (forceRedraw) { // Force the shape types to redraw RedrawOwningFactType(role); // Force anything with a later index to redraw as well. // These roles may be on different fact types than the // original. for (int i = roleIndex; i < redrawIndexBound; ++i) { RedrawOwningFactType(roles[i]); } } } else if (mySourceShape != null && null != (ormDiagram = currentElement as ORMDiagram)) { #if VISUALSTUDIO_10_0 if (IsActive) { Cancel(e.DiagramClientView); } #else base.OnClicked(e); // Let through to allow a cancel #endif } } }