private bool PasteShapes()
        {
            // Get prototypes from clipboard, if they exist
            IDataObject           dataObject            = Clipboard.GetDataObject();
            ElementGroupPrototype elementGroupPrototype = ElementOperations.GetElementGroupPrototype(ServiceProvider, dataObject);

            // if we're not pasting on the diagram (i.e., the ModelRoot), we're pasting the prototype
            if (TargetElement is ModelRoot &&
                CurrentModelingDocView is EFModelDocView efModelDocView &&
                efModelDocView.Diagram is EFModelDiagram currentDiagram &&
                currentDiagram?.Store != null &&
                elementGroupPrototype != null)
            {
                Store store = efModelDocView.Diagram.Store;

                // get matching elements from the store
                List <ModelElement> modelElements = elementGroupPrototype.ProtoElements
                                                    .Select(p => store.ElementDirectory.FindElement(p.ElementId))
                                                    .Where(e => e != null)
                                                    .ToList();

                if (modelElements.Any())
                {
                    List <ModelClass>   modelClasses   = modelElements.OfType <ModelClass>().ToList();
                    List <Comment>      comments       = modelElements.OfType <Comment>().ToList();
                    List <ModelElement> everythingElse = modelElements.Except(modelClasses).Except(comments).ToList();
                    List <ShapeElement> newShapes      = new List <ShapeElement>();

                    using (Transaction t = store.TransactionManager.BeginTransaction())
                    {
                        // paste classes and comments first to ensure that any possible connector end is present before the connectors arrive
                        newShapes.AddRange(modelClasses.Select(e => EFModelDiagram.AddExistingModelElement(currentDiagram, e)));
                        newShapes.AddRange(comments.Select(e => EFModelDiagram.AddExistingModelElement(currentDiagram, e)));
                        newShapes.AddRange(everythingElse.Select(e => EFModelDiagram.AddExistingModelElement(currentDiagram, e)));
                        newShapes = newShapes.Where(s => s != null).ToList();

                        // if nothing got pasted (because it's already there), we succeeded in our paste but didn't really change
                        // the display, so nothing further needs done
                        if (!newShapes.Any())
                        {
                            return(true);
                        }

                        t.Commit();
                    }

                    using (Transaction t = store.TransactionManager.BeginTransaction())
                    {
                        Commands.LayoutDiagram(currentDiagram, newShapes);
                        t.Commit();
                    }

                    currentDiagram.Invalidate();

                    return(true);
                }
            }

            return(false);
        }
Example #2
0
        public static ShapeElement AddExistingModelElement(EFModelDiagram diagram, ModelElement element)
        {
            if (diagram?.NestedChildShapes?.Any(s => s.ModelElement == element) != false)
            {
                return(null);
            }

            using (Transaction t = element.Store.TransactionManager.BeginTransaction("add existing model elements"))
            {
                diagram.ForceAddShape = true;
                FixUpAllDiagrams.FixUp(diagram, element);
                diagram.ForceAddShape = false;

                // find all element links that are attached to our element where the ends are in the diagram but the link isn't already in the diagram
                List <ElementLink> elementLinks = element.Store.GetAll <ElementLink>()
                                                  .Where(link => link.LinkedElements.Contains(element) &&
                                                         link.LinkedElements.All(linkedElement => diagram.DisplayedElements.Contains(linkedElement)) &&
                                                         !diagram.DisplayedElements.Contains(link))
                                                  .ToList();

                foreach (ElementLink elementLink in elementLinks)
                {
                    FixUpAllDiagrams.FixUp(diagram, elementLink);
                }

                t.Commit();

                return(diagram.NestedChildShapes.FirstOrDefault(s => s.ModelElement == element));
            }
        }
        /// <inheritdoc />
        public override void ElementDeleting(ElementDeletingEventArgs e)
        {
            base.ElementDeleting(e);

            ModelDiagramData element = (ModelDiagramData)e.ModelElement;
            Store            store   = element.Store;
            Transaction      current = store.TransactionManager.CurrentTransaction;

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

            if (BooleanQuestionDisplay.Show($"About to permanently delete diagram named {element.Name} - are you sure?") != true)
            {
                current.Rollback();

                return;
            }

            EFModelDiagram diagram = element.GetDiagram();

            ModelDiagramData.CloseDiagram?.Invoke(diagram);
            diagram.Delete();
        }
Example #4
0
        internal static void LayoutDiagram(EFModelDiagram diagram, IEnumerable <ShapeElement> shapeElements)
        {
            using (Transaction tx = diagram.Store.TransactionManager.BeginTransaction("ModelAutoLayout"))
            {
                List <ShapeElement> shapeList = shapeElements.ToList();

                List <DotNode> vertices = shapeList
                                          .OfType <NodeShape>()
                                          .Select(node => new DotNode {
                    Shape = node
                })
                                          .ToList();

                List <DotEdge> edges = shapeList
                                       .OfType <BinaryLinkShape>()
                                       .Select(link => new DotEdge(vertices.Single(vertex => vertex.Shape.Id == link.FromShape.Id),
                                                                   vertices.Single(vertex => vertex.Shape.Id == link.ToShape.Id))
                {
                    Shape = link
                })
                                       .ToList();

                // use graphviz as the default if available
                if (File.Exists(EFModelPackage.Options.DotExePath))
                {
                    DoGraphvizLayout(vertices, edges, diagram);
                }
                else
                {
                    DoStandardLayout(edges.Select(edge => edge.Shape).ToList(), diagram);
                }

                tx.Commit();
            }
        }
Example #5
0
        internal static void LayoutDiagram(EFModelDiagram diagram)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                ModelRoot modelRoot = diagram.Store.ModelRoot();

                using (Transaction tx = diagram.Store.TransactionManager.BeginTransaction("ModelAutoLayout"))
                {
                    List <NodeShape>       nodeShapes = diagram.NestedChildShapes.Where(s => s.IsVisible).OfType <NodeShape>().ToList();
                    List <BinaryLinkShape> linkShapes = diagram.NestedChildShapes.Where(s => s.IsVisible).OfType <BinaryLinkShape>().ToList();

                    // The standard DSL layout method was selected. Just do the deed and be done with it.
                    // otherwise, we need to run an MSAGL layout
                    if (modelRoot.LayoutAlgorithm == LayoutAlgorithm.Default || modelRoot.LayoutAlgorithmSettings == null)
                    {
                        DoStandardLayout(linkShapes, diagram);
                    }
                    else
                    {
                        DoCustomLayout(nodeShapes, linkShapes, modelRoot);
                    }

                    tx.Commit();
                }
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }
        public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)
        {
            base.ElementPropertyChanged(e);

            ModelDiagramData element = (ModelDiagramData)e.ModelElement;

            if (element.IsDeleted)
            {
                return;
            }

            Store       store = element.Store;
            Transaction currentTransaction = store.TransactionManager.CurrentTransaction;

            if (currentTransaction.IsSerializing)
            {
                return;
            }

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

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

            switch (e.DomainProperty.Name)
            {
            case "Name":
                if (string.IsNullOrWhiteSpace(e.NewValue?.ToString()))
                {
                    errorMessages.Add("Diagram must have a name");
                    break;
                }

                if (store.ElementDirectory.AllElements.OfType <ModelDiagramData>().Where(d => d != element).Any(d => d.Name == e.NewValue.ToString()))
                {
                    errorMessages.Add("Diagram must have a unique name");
                    break;
                }

                EFModelDiagram diagram = element.GetDiagram();
                if (diagram != null)
                {
                    ModelDiagramData.CloseDiagram?.Invoke(diagram);
                    diagram.Name = element.Name = e.NewValue.ToString();
                }
                break;
            }

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

            if (errorMessages.Any())
            {
                currentTransaction.Rollback();
                ErrorDisplay.Show(string.Join("\n", errorMessages));
            }
        }
Example #7
0
        public static void LayoutDiagram(EFModelDiagram diagram)
        {
            using (WaitCursor _ = new WaitCursor())
            {
                IEnumerable <ShapeElement> shapeElements = diagram.NestedChildShapes.Where(s => s.IsVisible);

                LayoutDiagram(diagram, shapeElements);
            }
        }
Example #8
0
        private void OnMenuLayoutDiagram(object sender, EventArgs e)
        {
            EFModelDiagram diagram = CurrentSelection.Cast <EFModelDiagram>().SingleOrDefault();

            if (diagram == null)
            {
                return;
            }

            Commands.LayoutDiagram(diagram);
        }
Example #9
0
        private bool PasteShapes(List <ModelElement> modelElements)
        {
            if (TargetElement is ModelRoot &&
                CurrentModelingDocView is EFModelDocView efModelDocView &&
                efModelDocView.Diagram is EFModelDiagram currentDiagram &&
                currentDiagram.Store != null &&
                modelElements.Any())
            {
                Store store = efModelDocView.Diagram.Store;

                List <ModelClass>   modelClasses   = modelElements.OfType <ModelClass>().ToList();
                List <Comment>      comments       = modelElements.OfType <Comment>().ToList();
                List <ModelElement> everythingElse = modelElements.Except(modelClasses).Except(comments).ToList();
                List <ShapeElement> newShapes      = new List <ShapeElement>();

                using (Transaction t = store.TransactionManager.BeginTransaction())
                {
                    // paste classes and comments first to ensure that any possible connector end is present before the connectors arrive
                    newShapes.AddRange(modelClasses.Select(e => EFModelDiagram.AddExistingModelElement(currentDiagram, e)));
                    newShapes.AddRange(comments.Select(e => EFModelDiagram.AddExistingModelElement(currentDiagram, e)));
                    newShapes = newShapes.Where(s => s != null).ToList();

                    // select and show the new or existing shape. Search, in order, classes, comments, then everything else
                    ModelElement firstElement = modelClasses.FirstOrDefault() ?? comments.FirstOrDefault() ?? everythingElse.FirstOrDefault();

                    if (firstElement != null)
                    {
                        currentDiagram.ActiveDiagramView.SelectModelElement(firstElement, true);
                    }

                    // if nothing got pasted (because it's already there), we succeeded in our paste but didn't really change
                    // the display, so nothing further needs done
                    if (!newShapes.Any())
                    {
                        return(false);
                    }

                    t.Commit();
                }

                //using (Transaction t = store.TransactionManager.BeginTransaction())
                //{
                //   Commands.LayoutDiagram(currentDiagram, newShapes);
                //   t.Commit();
                //}
                currentDiagram.Invalidate();

                return(true);
            }

            return(false);
        }
Example #10
0
        private void OnPostLoadModelAndDiagram(
            SerializationResult serializationResult,
            Partition modelPartition,
            string modelFileName,
            Partition diagramPartition,
            string diagramFileName,
            ModelRoot modelRoot,
            EFModelDiagram diagram)
        {
            Debug.Assert(modelPartition != null);
            Debug.Assert(modelPartition.Store != null);

            // Tracking properties need to be set up according to whether the serialization matches the calculated values.
            ResetTrackingProperties(modelPartition.Store);
        }
Example #11
0
        private void OnMenuLayoutDiagram(object sender, EventArgs e)
        {
            EFModelDiagram diagram = CurrentSelection.Cast <EFModelDiagram>().FirstOrDefault();

            if (diagram != null)
            {
                using (Transaction tx = diagram.Store.TransactionManager.BeginTransaction("ModelAutoLayout"))
                {
                    diagram.AutoLayoutShapeElements(diagram.NestedChildShapes,
                                                    Microsoft.VisualStudio.Modeling.Diagrams.GraphObject.VGRoutingStyle.VGRouteStraight,
                                                    Microsoft.VisualStudio.Modeling.Diagrams.GraphObject.PlacementValueStyle.VGPlaceSN,
                                                    false);
                    tx.Commit();
                }
            }
        }
        /// <summary>
        /// public virtual method for the client to have his own user-defined delete rule class
        /// </summary>
        /// <param name="e"></param>
        public override void ElementDeleted(ElementDeletedEventArgs e)
        {
            base.ElementDeleted(e);
            ModelDiagramData element = (ModelDiagramData)e.ModelElement;
            Store            store   = element.Store;
            Transaction      current = store.TransactionManager.CurrentTransaction;

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

            EFModelDiagram diagram = element.GetDiagram();

            ModelDiagramData.CloseDiagram?.Invoke(diagram);
            diagram.Delete();
        }
Example #13
0
        private void ObjectModelBrowser_OnNodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node is ExplorerTreeNode elementNode && elementNode.RepresentedElement != null)
            {
                ModelElement element = elementNode.RepresentedElement;

                if (ModelingDocData is EFModelDocData docData)
                {
                    Diagram diagram = docData.CurrentDocView?.CurrentDiagram;

                    if (diagram != null && diagram is EFModelDiagram efModelDiagram && !element.LocateInActiveDiagram(true))
                    {
                        EFModelDiagram.AddExistingModelElement(efModelDiagram, element);
                    }
                }
            }
        }
Example #14
0
        private static void DoStandardLayout(List <BinaryLinkShape> linkShapes, EFModelDiagram diagram)
        {
            // first we need to mark all the connectors as dirty so they'll route. Easiest way is to flip their 'ManuallyRouted' flag
            foreach (BinaryLinkShape linkShape in linkShapes)
            {
                linkShape.ManuallyRouted = !linkShape.ManuallyRouted;
            }

            // now let the layout mechanism route the connectors by setting 'ManuallyRouted' to false, regardless of what it was before
            foreach (BinaryLinkShape linkShape in linkShapes)
            {
                linkShape.ManuallyRouted = false;
            }

            diagram.AutoLayoutShapeElements(diagram.NestedChildShapes.Where(s => s.IsVisible).ToList(),
                                            VGRoutingStyle.VGRouteStraight,
                                            PlacementValueStyle.VGPlaceSN,
                                            true);
        }
Example #15
0
 public void SetDiagram(EFModelDiagram d)
 {
     diagram = d;
 }
        public virtual ModelRoot LoadModelAndDiagrams(DslModeling::SerializationResult serializationResult, DslModeling::Partition modelPartition, string modelFileName, DslModeling::Partition diagramsPartition, string diagramsFileName, DslModeling::ISchemaResolver schemaResolver, DslValidation::ValidationController validationController, DslModeling::ISerializerLocator serializerLocator)
        {
            #region Check Parameters
            if (serializationResult == null)
            {
                throw new global::System.ArgumentNullException("serializationResult");
            }
            if (modelPartition == null)
            {
                throw new global::System.ArgumentNullException("modelPartition");
            }
            if (diagramsPartition == null)
            {
                throw new global::System.ArgumentNullException("diagramsPartition");
            }
            if (string.IsNullOrEmpty(diagramsFileName))
            {
                throw new global::System.ArgumentNullException("diagramsFileName");
            }
            #endregion

            ModelRoot modelRoot;

            // Ensure there is an outer transaction spanning both model and diagram load, so moniker resolution works properly.
            if (!diagramsPartition.Store.TransactionActive)
            {
                throw new global::System.InvalidOperationException(EFModelDomainModel.SingletonResourceManager.GetString("MissingTransaction"));
            }

            modelRoot = this.LoadModel(serializationResult, modelPartition, modelFileName, schemaResolver, validationController, serializerLocator);
            ModelDiagramData data = null;

            if (serializationResult.Failed)
            {
                // don't try to deserialize diagram data if model load failed.
                return(modelRoot);
            }

            if (IsValid(diagramsFileName))
            {
                using (var pkgOutputDoc = global::System.IO.Packaging.Package.Open(diagramsFileName, global::System.IO.FileMode.Open, global::System.IO.FileAccess.Read))
                {
                    foreach (var packagePart in pkgOutputDoc.GetParts())
                    {
                        EFModelDiagram diagram = this.LoadDiagram(serializationResult
                                                                  , modelPartition
                                                                  , modelFileName
                                                                  , diagramsFileName
                                                                  , modelRoot
                                                                  , diagramsPartition
                                                                  , packagePart.GetStream(global::System.IO.FileMode.Open, global::System.IO.FileAccess.Read)
                                                                  , schemaResolver
                                                                  , validationController
                                                                  , serializerLocator) as EFModelDiagram;

                        if (diagram != null)
                        {
                            data = FixupDiagramData(diagram);
                        }

                        if (diagram.Name == Path.GetFileNameWithoutExtension(diagramsFileName).Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries).First())
                        {
                            data.SetLocks(Locks.All);
                        }
                    }
                }
            }
            else
            {
                // missing diagram file indicates we should create a new diagram.
                EFModelDiagram diagram = this.LoadDiagram(serializationResult
                                                          , modelPartition
                                                          , modelFileName
                                                          , diagramsFileName
                                                          , modelRoot
                                                          , diagramsPartition
                                                          , global::System.IO.Stream.Null
                                                          , schemaResolver
                                                          , validationController
                                                          , serializerLocator) as EFModelDiagram;
                if (diagram != null)
                {
                    data = FixupDiagramData(diagram);
                }

                if (diagram.Name == Path.GetFileNameWithoutExtension(diagramsFileName))
                {
                    data.SetLocks(Locks.All);
                }
            }

            modelRoot.Store
            .GetAll <ModelDiagramData>()
            .Where(d => d.GetDiagram() == null)
            .ToList()
            .ForEach(d => modelRoot.Diagrams.Remove(d));

            return(modelRoot);

            ModelDiagramData FixupDiagramData(EFModelDiagram diagram)
            {
                ModelDiagramData diagramData = modelRoot.Store
                                               .GetAll <ModelDiagramData>()
                                               .FirstOrDefault(d => d.Name == diagram.Name);

                if (diagramData == null)
                {
                    modelRoot.Diagrams.Add(diagramData = new ModelDiagramData(modelRoot.Store.DefaultPartition
                                                                              , new DslModeling.PropertyAssignment(ModelDiagramData.NameDomainPropertyId, diagram.Name)));
                }

                diagramData.SetDiagram(diagram);
                return(diagramData);
            }
        }
Example #17
0
        // ReSharper disable once UnusedParameter.Local
        private static void DoGraphvizLayout(List <DotNode> vertices, List <DotEdge> edges, EFModelDiagram diagram)
        {
            // set up to be a bidirectional graph with the edges we found
            BidirectionalGraph <DotNode, DotEdge> graph = edges.ToBidirectionalGraph <DotNode, DotEdge>();

            // add all the vertices that aren't connected by edges
            graph.AddVertexRange(vertices.Except(edges.Select(e => e.Source).Union(edges.Select(e => e.Target))));

            // we'll process as Graphviz
            GraphvizAlgorithm <DotNode, DotEdge> graphviz = new GraphvizAlgorithm <DotNode, DotEdge>(graph);

            graphviz.GraphFormat.NodeSeparation = 1.0;
            graphviz.GraphFormat.Splines        = GraphvizSplineType.Ortho;
            graphviz.CommonVertexFormat.Shape   = GraphvizVertexShape.Record;

            // labels will be the Id of the underlying Shape
            graphviz.FormatVertex += (sender, args) =>
            {
                args.VertexFormat.Label = args.Vertex.Shape.ModelElement is ModelClass modelClass
                                                                     ? modelClass.Name
                                                                     : args.Vertex.Shape.ModelElement is ModelEnum modelEnum
                                                                        ? modelEnum.Name
                                                                        : args.Vertex.Shape.ModelElement.Id.ToString();
                args.VertexFormat.FixedSize = true;
                args.VertexFormat.Size      = new GraphvizSizeF((float)args.Vertex.Shape.Size.Width,
                                                                (float)args.Vertex.Shape.Size.Height);

                args.VertexFormat.Label = args.Vertex.Shape.Id.ToString();
            };

            graphviz.FormatEdge += (sender, args) =>
            {
                args.EdgeFormat.Label.Value = args.Edge.Shape.Id.ToString();
            };
            // generate the commands
            string dotCommands = graphviz.Generate(new DotEngine(), Path.Combine(Path.GetTempPath(), Path.GetTempFileName()));

            Debug.WriteLine(dotCommands);

            ProcessStartInfo dotStartInfo = new ProcessStartInfo(EFModelPackage.Options.DotExePath, "-T plain")
            {
                RedirectStandardInput  = true,
                RedirectStandardOutput = true,
                UseShellExecute        = false,
                CreateNoWindow         = true
            };
            string graphOutput;

            using (Process dotProcess = Process.Start(dotStartInfo))
            {
                // stdin is redirected to our stream, so pump the commands in through that
                dotProcess.StandardInput.WriteLine(dotCommands);
                // closing the stream starts the process
                dotProcess.StandardInput.Close();
                // stdout is redirected too, so capture the output
                graphOutput = dotProcess.StandardOutput.ReadToEnd();
                dotProcess.WaitForExit();
            }
            Debug.WriteLine(graphOutput);

            // break it up into lines of text for processing
            string[] outputLines = graphOutput.Split(new [] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            SizeD    graphSize   = SizeD.Empty;

            // ReSharper disable once LoopCanBePartlyConvertedToQuery
            foreach (string outputLine in outputLines)
            {
                // spaces aren't valid in any of the data, so we can treat them as delimiters
                string[] parts = outputLine.Split(' ');
                string   id;
                double   x, y;

                // graphviz coordinates have 0,0 at the bottom left, positive means moving up
                // our coordinates have 0,0 at the top left, positive means moving down
                // so we need to transform them
                switch (parts[0])
                {
                case "graph":
                    // 0     1 2      3
                    // graph 1 109.38 92.681
                    graphSize = new SizeD(double.Parse(parts[2]), double.Parse(parts[3]));
                    break;

                case "node":
                    // 0    1  2      3      4   5      6                                      7
                    // node 71 78.514 93.639 1.5 3.3056 "0f651fe7-da0f-453f-a08a-ec1d31ec0e71" solid record black lightgrey
                    id = parts[6].Trim('"');
                    DotNode dotNode = vertices.Single(v => v.Shape.Id.ToString() == id); // label

                    x = double.Parse(parts[2]);
                    y = graphSize.Height - double.Parse(parts[3]);

                    dotNode.Shape.Bounds = new RectangleD(x, y, dotNode.Shape.Size.Width, dotNode.Shape.Size.Height);

                    break;

                case "edge":
                    // 0    1 2  3 4      5      6      7      8      9     10     11    12
                    // edge 6 18 4 34.926 77.518 34.926 77.518 34.926 75.88 34.926 75.88 "567b5db7-7591-4aa7-845c-76635bf56f28" 36.083 77.16 solid black
                    id = parts[4 + int.Parse(parts[3]) * 2].Trim('"');
                    DotEdge edge = edges.Single(e => e.Shape.Id.ToString() == id);

                    // need to mark the connector as dirty. this is the easiest way to do this
                    BinaryLinkShape linkShape = edge.Shape;
                    linkShape.ManuallyRouted = !linkShape.ManuallyRouted;
                    linkShape.FixedFrom      = VGFixedCode.NotFixed;
                    linkShape.FixedTo        = VGFixedCode.NotFixed;

                    // make the labels follow the lines
                    foreach (LineLabelShape lineLabelShape in linkShape.RelativeChildShapes.OfType <LineLabelShape>())
                    {
                        lineLabelShape.ManuallySized  = false;
                        lineLabelShape.ManuallyPlaced = false;
                    }

                    linkShape.EdgePoints.Clear();

                    int pointCount = int.Parse(parts[3]);

                    for (int index = 4; index < 4 + pointCount * 2; index += 2)
                    {
                        x = double.Parse(parts[index]);
                        y = graphSize.Height - double.Parse(parts[index + 1]);
                        linkShape.EdgePoints.Add(new EdgePoint(x, y, VGPointType.Normal));
                    }

                    // since we're not changing the nodes this edge connects, this really doesn't do much.
                    // what it DOES do, however, is call ConnectEdgeToNodes, which is an internal method we'd otherwise
                    // be unable to access
                    linkShape.Connect(linkShape.FromShape, linkShape.ToShape);
                    linkShape.ManuallyRouted = false;

                    break;
                }
            }
        }