Skip to content
This repository has been archived by the owner on Jan 16, 2024. It is now read-only.

Commit

Permalink
Compiles
Browse files Browse the repository at this point in the history
  • Loading branch information
msawczyn committed Dec 28, 2021
1 parent f5a430b commit 2dca0b9
Show file tree
Hide file tree
Showing 36 changed files with 2,747 additions and 61 deletions.
66 changes: 49 additions & 17 deletions src/Dsl/CustomCode/Partials/ClassShape.cs
Expand Up @@ -142,7 +142,7 @@ protected override CompartmentMapping[] GetCompartmentMappings(Type melType)
/// <summary>
/// Maps names to images for class glyphs
/// </summary>
public static ReadOnlyDictionary<string, Image> ClassImages =
public static readonly ReadOnlyDictionary<string, Image> ClassImages =
new ReadOnlyDictionary<string, Image>(new Dictionary<string, Image>
{
{nameof(Resources.EntityGlyph), Resources.EntityGlyph}
Expand All @@ -151,12 +151,14 @@ protected override CompartmentMapping[] GetCompartmentMappings(Type melType)
, {nameof(Resources.SQLVisible), Resources.SQLVisible}
, {nameof(Resources.AbstractEntityGlyph), Resources.AbstractEntityGlyph}
, {nameof(Resources.AbstractEntityGlyphVisible), Resources.AbstractEntityGlyphVisible}
, { nameof(Resources.AssociationClassGlyph), Resources.AssociationClassGlyph }
, { nameof(Resources.AssociationClassGlyphVisible), Resources.AssociationClassGlyphVisible }
});

/// <summary>
/// Maps names to images for property glyphs
/// </summary>
public static ReadOnlyDictionary<string, Image> PropertyImages =
public static readonly ReadOnlyDictionary<string, Image> PropertyImages =
new ReadOnlyDictionary<string, Image>(new Dictionary<string, Image>
{
{nameof(Resources.Warning), Resources.Warning}
Expand Down Expand Up @@ -235,27 +237,47 @@ public static Image GetPropertyImage(ModelElement element)
/// </remarks>
protected override void OnBeforePaint()
{
if (ModelElement is ModelClass element && (element.IsAbstract || element.IsDependentType))
if (ModelElement is ModelClass element && (element.IsAbstract || element.IsDependentType || element.IsAssociationClass))
{
PenSettings penSettings = StyleSet.GetOverriddenPenSettings(DiagramPens.ConnectionLine) ?? new PenSettings();

if (element.IsAbstract)
{
PenSettings penSettings = StyleSet.GetOverriddenPenSettings(DiagramPens.ShapeOutline) ?? new PenSettings();
penSettings.Color = Color.OrangeRed;
penSettings.Width = 0.03f;
penSettings.DashStyle = DashStyle.Dot;
StyleSet.OverridePen(DiagramPens.ShapeOutline, penSettings);
}
else if (element.IsDependentType)
{
PenSettings penSettings = StyleSet.GetOverriddenPenSettings(DiagramPens.ShapeOutline) ?? new PenSettings();
penSettings.Color = Color.ForestGreen;
penSettings.Width = 0.03f;
penSettings.DashStyle = DashStyle.Dot;
StyleSet.OverridePen(DiagramPens.ShapeOutline, penSettings);
}
else if (element.IsAssociationClass)
{
PenSettings penSettings = StyleSet.GetOverriddenPenSettings(DiagramPens.ShapeOutline) ?? new PenSettings();
penSettings.Color = Color.DarkGoldenrod;
penSettings.Width = 0.03f;
penSettings.DashStyle = DashStyle.Dot;
StyleSet.OverridePen(DiagramPens.ShapeOutline, penSettings);

StyleSet.OverridePen(DiagramPens.ShapeOutline, penSettings);
BrushSettings backgroundBrush = StyleSet.GetOverriddenBrushSettings(DiagramBrushes.ShapeBackground) ?? new BrushSettings();
backgroundBrush.Color = Color.Goldenrod;
StyleSet.OverrideBrush(DiagramBrushes.ShapeBackground, backgroundBrush);

FontSettings titleFont = StyleSet.GetOverriddenFontSettings(DiagramFonts.ShapeTitle) ?? new FontSettings();
titleFont.Italic = true;
StyleSet.OverrideFont(DiagramFonts.ShapeTitle, titleFont);
}
}
else
{
StyleSet.ClearPenOverride(DiagramPens.ShapeOutline);
StyleSet.ClearBrushOverride(DiagramBrushes.ShapeBackground);
StyleSet.ClearFontOverride(DiagramFonts.ShapeTitle);
}

}

Expand Down Expand Up @@ -291,6 +313,8 @@ public static string GetExplorerNodeImageName(ModelElement element)
return $"[{attribute.Persistent}][{attribute.SetterVisibility}]";

case ModelClass modelClass:
if (modelClass.IsAssociationClass)
return modelClass.IsVisible() ? nameof(Resources.AssociationClassGlyphVisible) : nameof(Resources.AssociationClassGlyph);
if (modelClass.IsQueryType)
return modelClass.IsVisible() ? nameof(Resources.SQLVisible) : nameof(Resources.SQL);
if (modelClass.IsAbstract)
Expand All @@ -305,14 +329,14 @@ public static string GetExplorerNodeImageName(ModelElement element)
#region Drag/drop model attributes

/// <summary>
/// Model element that is being dragged.
/// Model attribute that is being dragged, if any
/// </summary>
private static ModelAttribute dragStartElement;
private static ModelAttribute dragStartModelAttribute;

/// <summary>
/// Absolute bounds of the compartment, used to set the cursor.
/// Absolute bounds of the item being dragged, used to set the cursor.
/// </summary>
private static RectangleD compartmentBounds;
private static RectangleD dragItemBounds;

/// <summary>
/// Remember which item the mouse was dragged from.
Expand All @@ -324,8 +348,8 @@ public static string GetExplorerNodeImageName(ModelElement element)
/// <param name="e"></param>
private void Compartment_MouseDown(object sender, DiagramMouseEventArgs e)
{
dragStartElement = e.HitDiagramItem.RepresentedElements.OfType<ModelAttribute>().FirstOrDefault();
compartmentBounds = e.HitDiagramItem.Shape.AbsoluteBoundingBox;
dragStartModelAttribute = e.HitDiagramItem.RepresentedElements.OfType<ModelAttribute>().FirstOrDefault();
dragItemBounds = e.HitDiagramItem.Shape.AbsoluteBoundingBox;
}

/// <summary>
Expand All @@ -337,10 +361,10 @@ private void Compartment_MouseDown(object sender, DiagramMouseEventArgs e)
/// <param name="e"></param>
private void Compartment_MouseMove(object sender, DiagramMouseEventArgs e)
{
if (dragStartElement != null && dragStartElement != e.HitDiagramItem.RepresentedElements.OfType<ModelAttribute>().FirstOrDefault())
if (dragStartModelAttribute != null && dragStartModelAttribute != e.HitDiagramItem.RepresentedElements.OfType<ModelAttribute>().FirstOrDefault())
{
e.DiagramClientView.ActiveMouseAction = new CompartmentDragMouseAction<ClassShape>(dragStartElement, this, compartmentBounds);
dragStartElement = null;
e.DiagramClientView.ActiveMouseAction = new CompartmentDragMouseAction<ClassShape>(dragStartModelAttribute, this, dragItemBounds);
dragStartModelAttribute = null;
}
}

Expand All @@ -349,7 +373,10 @@ private void Compartment_MouseMove(object sender, DiagramMouseEventArgs e)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Compartment_MouseUp(object sender, DiagramMouseEventArgs e) => dragStartElement = null;
private void Compartment_MouseUp(object sender, DiagramMouseEventArgs e)
{
dragStartModelAttribute = null;
}

/// <summary>
/// Called by the Action when the user releases the mouse.
Expand Down Expand Up @@ -446,7 +473,7 @@ private ElementLink GetEmbeddingLink(ModelAttribute child) => child.GetDomainCla
public override void OnMouseUp(DiagramMouseEventArgs e)
{
base.OnMouseUp(e);
dragStartElement = null;
dragStartModelAttribute = null;
}

#endregion
Expand All @@ -461,6 +488,11 @@ public override void OnMouseUp(DiagramMouseEventArgs e)
/// </summary>
public static Action ExecCodeGeneration;

/// <summary>
/// Set when DocData is loaded. If non-null, calling this action will set the linked ModelClass to be an association class for the linked BidirectionalAssociation
/// </summary>
public static Action<BidirectionalConnector, ClassShape> AddAssociationClass;

/// <summary>Called by the control's OnDoubleClick()</summary>
/// <param name="e">A DiagramPointEventArgs that contains event data.</param>
public override void OnDoubleClick(DiagramPointEventArgs e)
Expand Down
35 changes: 32 additions & 3 deletions src/Dsl/CustomCode/Partials/ModelClass.cs
Expand Up @@ -20,21 +20,18 @@ public partial class ModelClass : IModelElementWithCompartments, IDisplaysWarnin
/// <summary>
/// True if this is a normal entity type (not aggregated and not keyless), false otherwise
/// </summary>
/// <returns></returns>
[Browsable(false)]
public bool IsEntity() => !IsDependentType && !IsKeylessType();

/// <summary>
/// True if this is a dependent (aggregated) entity type, false otherwise
/// </summary>
/// <returns></returns>
[Browsable(false)]
public bool IsDependent() => IsDependentType;

/// <summary>
/// True if this is a keyless entity type (backed by a query or a view), false otherwise
/// </summary>
/// <returns></returns>
[Browsable(false)]
public bool IsKeyless() => IsKeylessType();

Expand Down Expand Up @@ -128,6 +125,24 @@ public string GetDefaultTableName(bool shouldPluralize)
: Name;
}

/// <summary>
/// All custom interfaces in the class, including those inherited from base classes
/// </summary>
public IEnumerable<string> AllCustomInterfaces
{
get
{
List<string> interfaces = new List<string>();
ModelClass modelClass = this;
while (modelClass != null)
{
interfaces.AddRange(modelClass.CustomInterfaces.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
modelClass = modelClass.Superclass;
}

return interfaces.Distinct();
}
}

/// <summary>
/// All attributes in the class, including those inherited from base classes
Expand Down Expand Up @@ -318,6 +333,9 @@ protected string GetGlyphTypeValue()
if (ModelRoot.ShowWarningsInDesigner && GetHasWarningValue())
return "WarningGlyph";

if (IsAssociationClass)
return "AssociationClassGlyph";

if (IsQueryType)
return "SQLGlyph";

Expand Down Expand Up @@ -501,6 +519,17 @@ internal void MoveAttribute(ModelAttribute attribute, ModelClass destination)
destination.MergeRelate(attribute, null);
}

internal bool CanBecomeAssociationClass()
{
return !AllNavigationProperties().Any()
&& !IsAssociationClass
&& !IsAbstract
&& !IsDependentType
&& !IsQueryType
&& !IsDatabaseView
&& string.IsNullOrEmpty(ViewName);
}

#region Validations

[ValidationMethod(ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu)]
Expand Down
7 changes: 6 additions & 1 deletion src/Dsl/CustomCode/Partials/ModelRoot.cs
Expand Up @@ -62,7 +62,12 @@ static ModelRoot()
/// <summary>
/// True if the model is EFCore and the Entity Framework version is >= 5
/// </summary>
public bool IsEFCore5Plus => EntityFrameworkVersion == EFVersion.EFCore && (EntityFrameworkPackageVersion == "Latest" || GetEntityFrameworkPackageVersionNum() >= 5);
public bool IsEFCore5Plus => EntityFrameworkVersion == EFVersion.EFCore && GetEntityFrameworkPackageVersionNum() >= 5;

/// <summary>
/// True if the model is EFCore and the Entity Framework version is >= 6
/// </summary>
public bool IsEFCore6Plus => EntityFrameworkVersion == EFVersion.EFCore && (EntityFrameworkPackageVersion == "Latest" || GetEntityFrameworkPackageVersionNum() >= 6);

/// <summary>
/// Finds all diagrams associated to this model
Expand Down
79 changes: 79 additions & 0 deletions src/Dsl/CustomCode/Rules/ClassShapeChangeRules.cs
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.VisualStudio.Modeling;

namespace Sawczyn.EFDesigner.EFModel
{
[RuleOn(typeof(ClassShape), FireTime = TimeToFire.TopLevelCommit)]
internal class ClassShapeChangeRules : ChangeRule
{
/// <inheritdoc />
public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)
{
base.ElementPropertyChanged(e);

ClassShape element = (ClassShape)e.ModelElement;

if (element.IsDeleted)
return;

ModelClass modelClass = (ModelClass)element.ModelElement;
Store store = element.Store;
Transaction current = store.TransactionManager.CurrentTransaction;

if (current.IsSerializing || ModelRoot.BatchUpdating)
return;

if (Equals(e.NewValue, e.OldValue))
return;

List<string> errorMessages = new List<string>();

switch (e.DomainProperty.Name)
{
case "AbsoluteBounds":
{
List<Guid> linkedConnectionObjectIds = modelClass.Store.ElementDirectory.AllElements
.OfType<ModelClass>()
.Where(x => x.IsAssociationClass)
.Select(x => x.DescribedAssociationElementId)
.ToList();

List<BidirectionalConnector> candidates = store.ElementDirectory.AllElements
.OfType<BidirectionalConnector>()
.Where(c => ((BidirectionalAssociation)c.ModelElement).SourceMultiplicity == Multiplicity.ZeroMany
&& ((BidirectionalAssociation)c.ModelElement).TargetMultiplicity == Multiplicity.ZeroMany
&& !linkedConnectionObjectIds.Contains(((BidirectionalAssociation)c.ModelElement).Id)
&& c.AbsoluteBoundingBox.IntersectsWith(element.AbsoluteBoundingBox))
.ToList();

if (modelClass.CanBecomeAssociationClass() && candidates.Any())
{
foreach (BidirectionalConnector candidate in candidates)
{
BidirectionalAssociation association = ((BidirectionalAssociation)candidate.ModelElement);

if (BooleanQuestionDisplay.Show(store, $"Make {modelClass.Name} an association class for {association.GetDisplayText()}?") == true)
{
ClassShape.AddAssociationClass(candidate, element);
break;
}
}
}
}

break;
}

errorMessages = errorMessages.Where(m => m != null).ToList();

if (errorMessages.Any())
{
current.Rollback();
ErrorDisplay.Show(store, string.Join("\n", errorMessages));
}
}
}
}

0 comments on commit 2dca0b9

Please sign in to comment.