]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling/scl/Simantics/Diagram.scl
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / scl / Simantics / Diagram.scl
diff --git a/bundles/org.simantics.modeling/scl/Simantics/Diagram.scl b/bundles/org.simantics.modeling/scl/Simantics/Diagram.scl
new file mode 100644 (file)
index 0000000..93a60f3
--- /dev/null
@@ -0,0 +1,831 @@
+include "Simantics/Model"\r
+include "Simantics/WorkbenchSelection"\r
+include "Simantics/Library"\r
+include "File"\r
+import "Simantics/GUID" as GUID\r
+\r
+import "http://www.simantics.org/Layer0-1.1" as L0\r
+import "http://www.simantics.org/Diagram-2.2" as DIA\r
+import "http://www.simantics.org/G2D-1.1" as G2D\r
+import "http://www.simantics.org/Modeling-1.2" as MOD\r
+import "http://www.simantics.org/Simulation-1.1" as SIMU\r
+import "http://www.simantics.org/Structural-1.2" as STR\r
+\r
+// --- Entity types -------------------------------------------------\r
+\r
+type Diagram = Resource\r
+type DiagramFolder  = Resource\r
+type Component = Resource\r
+type Element = Resource\r
+type ComponentType = Resource\r
+type Terminal = Resource\r
+type Connection = Resource\r
+type ConnectionType = Resource\r
+\r
+// --- Position -----------------------------------------------------\r
+\r
+data Position = Position Double Double Double Double Double Double\r
+\r
+deriving instance Show Position\r
+\r
+location :: Double -> Double -> Position\r
+location x y = Position 1 0 0 1 x y\r
+\r
+move :: (Double,Double) -> Position -> Position\r
+move (dx,dy) (Position xx xy yx yy x y) = Position xx xy yx yy (x+dx) (y+dy)\r
+\r
+rotate :: Integer -> Position -> Position\r
+rotate angle (Position xx xy yx yy x y) =\r
+    Position (c*xx + s*xy) (c*xy - s*xx)\r
+             (c*yx + s*yy) (c*yy - s*yx)\r
+             x y\r
+  where\r
+    a = if angle < 0 \r
+        then (angle `mod` 4) + 4\r
+        else angle `mod` 4\r
+    s = match a with 1 -> 1.0 ; 3 -> -1.0 ; _ -> 0.0\r
+    c = match a with 0 -> 1.0 ; 2 -> -1.0 ; _ -> 0.0\r
+\r
+scale :: Double -> Position -> Position\r
+scale s (Position xx xy yx yy x y) = Position (s*xx) (s*xy) (s*yx) (s*yy) x y\r
+\r
+flipX :: Position -> Position\r
+flipX (Position xx xy yx yy x y) = Position (-xx) xy (-yx) yy x y \r
+\r
+flipY :: Position -> Position\r
+flipY (Position xx xy yx yy x y) = Position xx (-xy) yx (-yy) x y\r
+\r
+positionToDoubleArray (Position a b c d e f) = toDoubleArray [a,b,c,d,e,f]\r
+\r
+// --- Diagram element data types -----------------------------------\r
+\r
+data Property res = Property res Dynamic\r
+instance (Show res) => Show (Property res) where\r
+    show (Property r _) = "Property " + show r \r
+\r
+data Edge = Edge Integer Integer\r
+deriving instance Show Edge\r
+data ConnectionNode res = Terminal String res\r
+                        | RouteLine\r
+                              Boolean   // is horizontal \r
+                              Double    // position\r
+deriving instance (Show res) => Show (ConnectionNode res)\r
+\r
+data Font = Font String Integer Integer\r
+deriving instance Show Font\r
+\r
+data Alignment =\r
+    Baseline\r
+  | Center\r
+  | Leading\r
+  | Trailing\r
+deriving instance Show Alignment\r
+\r
+resourceToAlignment res = match (possibleNameOf res) with\r
+    Just "Baseline" -> Baseline\r
+    Just "Center" -> Center\r
+    Just "Leading" -> Leading\r
+    Just "Trailing" -> Trailing\r
+    _ -> fail ("Couldn't convert " + show res + " to Alignment.")\r
+\r
+alignmentToResource Baseline = G2D.Alignment.Baseline\r
+alignmentToResource Center = G2D.Alignment.Center\r
+alignmentToResource Leading = G2D.Alignment.Leading\r
+alignmentToResource Trailing = G2D.Alignment.Trailing\r
+\r
+data MonitorReference = MonitorReference String String\r
+deriving instance Show MonitorReference\r
+\r
+data MonitorVisuals = MonitorVisuals (Maybe Font) Double Alignment Alignment\r
+deriving instance Show MonitorVisuals\r
+\r
+data TextVisuals = TextVisuals (Maybe Font) Alignment Alignment\r
+deriving instance Show TextVisuals\r
+\r
+data DiagramElement res = \r
+    Component\r
+        res            // component type\r
+        String         // name\r
+        Position       // position\r
+        [Property res] // properties\r
+  | SimpleConnection String res String res (Maybe String)\r
+  | Connection [ConnectionNode res] [Edge] (Maybe String)\r
+  | Flag \r
+        res \r
+        String         // name \r
+        String         // label\r
+        Boolean        // output\r
+        Boolean        // external\r
+        (Maybe String)         // IOTableBinding\r
+        (Maybe Integer)        // IOTableRowIndex\r
+        Position       // position  \r
+        [Dynamic]      // references to the joins\r
+  | SVG String Position\r
+  | Monitor String (Maybe MonitorReference) MonitorVisuals Position\r
+  | Text\r
+        Resource       // element type\r
+        String         // Text shown by the element\r
+        TextVisuals    // text element visual attributes\r
+        Position       // position on diagram\r
+deriving instance (Show res) => Show (DiagramElement res)\r
+\r
+// --- Functions ----------------------------------------------------\r
+\r
+"""Creates a random GUID L0.identifier property for the specified entity resource.""" \r
+@private\r
+hasRandomIdentifier :: Resource -> <ReadGraph,WriteGraph> ()\r
+hasRandomIdentifier entity = runProc (claimRelatedValue_ entity L0.identifier GUID.randomGUID GUID.guidBinding)\r
+\r
+"""Returns all diagrams of the given model."""\r
+diagramsOf :: Model -> <ReadGraph> [Diagram]\r
+diagramsOf model = recurse\r
+                   DIA.Diagram \r
+                   (toResource (configurationOf model))\r
+  where\r
+    recurse t r = do\r
+        cs = resourceChildrenOf r \r
+        dias = map fromResource $ filter isDiagramComposite cs\r
+        folders = filter (not . isDiagramComposite) cs\r
+        dias + concatMap (recurse t) folders\r
+    isDiagramComposite r = existsStatement r MOD.CompositeToDiagram\r
+\r
+"""Returns a model relative path of the given diagram."""\r
+pathOf :: Diagram -> <ReadGraph> [String]\r
+pathOf diagram = map nameOf $ unfoldl aux $ toResource diagram\r
+  where\r
+    aux r = if existsStatement r SIMU.IsConfigurationOf\r
+            then Nothing\r
+            else do\r
+                parents  = r # L0.PartOf\r
+                if length parents == 1\r
+                then Just (r, parents!0)\r
+                else Nothing\r
+    nameOf r = relatedValue r $ L0.HasName\r
+\r
+pathNameOf :: Diagram -> <ReadGraph> String\r
+pathNameOf diagram = do\r
+    path = pathOf diagram\r
+    foldl1 (\s s1 -> s + " / " + s1) path\r
+\r
+// @Private?\r
+diagramResourceOf :: Diagram -> <ReadGraph> Resource\r
+diagramResourceOf d = singleObject (toResource d) MOD.CompositeToDiagram\r
+\r
+import "Extras/HashMap" as Map\r
+\r
+"""Constructs a transformation for a diagram element."""\r
+mapDiagramElement :: (a -> <e> b) -> (a -> <e> b) -> (a -> <e> Maybe b) -> (a -> <e> b) -> DiagramElement a -> <e> DiagramElement b\r
+mapDiagramElement mapComponentType mapTerminal mapAttribute mapFlagType diagramElement =\r
+    (match diagramElement with\r
+        Component componentType name position properties -> do\r
+            Component (mapComponentType componentType) name position\r
+                (filterJust (map mapProperty properties))\r
+        SimpleConnection e1 r1 e2 r2 possibleName ->\r
+            SimpleConnection e1 (mapTerminal r1) e2 (mapTerminal r2) possibleName\r
+        Connection nodes edges possibleName ->\r
+            Connection\r
+                (map mapConnectionNode nodes)\r
+                edges possibleName\r
+        Flag t e e2 e3 e4 e5 p p2 joins -> Flag (mapFlagType t) e e2 e3 e4 e5 p p2 joins\r
+        SVG d p -> SVG d p\r
+        Monitor label ref visuals position -> Monitor label ref visuals position\r
+        Text elementType text visuals position -> Text elementType text visuals position\r
+) where\r
+    mapProperty (Property p v) = \r
+      match (mapAttribute p) with\r
+        Just mp -> Just (Property mp v)\r
+        Nothing -> Nothing\r
+    mapConnectionNode (Terminal e r) = Terminal e (mapTerminal r)\r
+    mapConnectionNode (RouteLine iv p) = RouteLine iv p\r
+\r
+importJava "org.simantics.structural2.utils.StructuralUtils" where\r
+    @JavaName newComponent\r
+    createComposite_ :: Resource -> String -> Resource -> <WriteGraph> Resource   \r
+\r
+data DiagramSpec = NewDiagram \r
+                       Model    // root \r
+                       [String] // path to the diagram\r
+                       Resource // folder type \r
+                       Resource // composite type\r
+                 | ExistingDiagram Diagram\r
+\r
+compositeToDiagram' c = singleObject c MOD.CompositeToDiagram\r
+\r
+"""Creates or modifies an existing diagram to contain the given diagram elements."""        \r
+createDiagramR :: DiagramSpec -> (Dynamic -> <WriteGraph> Resource) -> [DiagramElement Resource] -> <WriteGraph> (Diagram, [Resource])\r
+createDiagramR (ExistingDiagram diagram') joinMap elementSpecs = runProc do\r
+    configuration = toResource diagram'\r
+    diagram = compositeToDiagram' configuration\r
+    hasName = L0.HasName\r
+    componentMap = Map.fromList [ (c `relatedValue` hasName :: String, c)\r
+                                | c <- resourceChildrenOf configuration\r
+                                ]\r
+    denyByPredicate diagram L0.ConsistsOf\r
+    elements = setElements (DiagramInfo diagram configuration componentMap) joinMap elementSpecs\r
+    claimRelatedValue diagram DIA.HasModCount \r
+        (fromInteger (length elements) :: Long)\r
+    (diagram', elements)\r
+\r
+createDiagramR (NewDiagram model path folderType compositeType) joinMap elementSpecs = (runProc do\r
+    configuration = createConfiguration ()    \r
+    diagram = compositeToDiagram' configuration\r
+    elements = setElements (DiagramInfo diagram configuration (Map.create ())) joinMap elementSpecs\r
+    claimRelatedValue diagram DIA.HasModCount \r
+        (fromInteger (length elements) :: Long)\r
+    (fromResource configuration, elements)\r
+) where\r
+    createConfiguration () = do\r
+        lastId = length path - 1\r
+        parentFolder = foldl (\p id -> getOrCreateFolder p (path!id)) \r
+            (toResource (configurationOf model)) \r
+            [0..lastId-1]        \r
+        createComposite_ parentFolder (path!lastId) compositeType\r
+    getOrCreateFolder parentFolder name =\r
+        match possibleResourceChild parentFolder name with\r
+            Just child -> child\r
+            Nothing ->\r
+                createComposite_ parentFolder name folderType\r
+\r
+claimFolder :: Model -> [String] -> Resource -> <Proc,WriteGraph> Resource\r
+claimFolder model path folderType = do\r
+    lastId = length path\r
+    foldl (\p id -> getOrCreateFolder p folderType (path!id)) \r
+        (toResource (configurationOf model)) \r
+        [0..lastId-1]\r
+\r
+claimModelFolder :: Model -> [String] -> Resource -> <Proc,WriteGraph> Resource\r
+claimModelFolder model path folderType = do\r
+    lastId = length path\r
+    foldl (\p id -> getOrCreateFolder p folderType (path!id)) \r
+        (toResource model) \r
+        [0..lastId-1]        \r
+\r
+getOrCreateFolder :: Resource -> Resource -> String -> <Proc,WriteGraph> Resource\r
+getOrCreateFolder parentFolder folderType name = do\r
+    match possibleResourceChild parentFolder name with\r
+        Just child -> child\r
+        Nothing ->\r
+            createComposite_ parentFolder name folderType\r
+\r
+relatedValueWithDefault :: Serializable a => a -> Resource -> Resource -> <ReadGraph> a\r
+relatedValueWithDefault def r p =\r
+    if existsStatement r p\r
+    then relatedValue r p\r
+    else def\r
+\r
+applyConnectionType :: Resource -> <Proc,WriteGraph,ReadGraph> ()\r
+applyConnectionType res = do\r
+    t = determineConnectionType res\r
+    match t with\r
+      Just t -> claim res STR.HasConnectionType t\r
+      Nothing -> print ("No connection type " + (show res))\r
+    () \r
+\r
+importJava "org.simantics.modeling.utils.JoinMap" where\r
+    @JavaName "<init>"\r
+    createJoinMap :: () -> <Proc> (Dynamic -> <WriteGraph> Resource)\r
+    \r
+/*\r
+createJoin :: (Dynamic -> <WriteGraph> Resource) -> Dynamic -> <Proc,WriteGraph> Resource\r
+createJoin joinMap key = if Map.contains joinMap key\r
+                         then Map.unsafeGet joinMap key\r
+                         else do\r
+                             j = newEntity [\r
+                                 hasType STR.ConnectionJoin\r
+                               ]\r
+                             Map.put joinMap key j \r
+                             j\r
+*/\r
+data DiagramInfo = DiagramInfo\r
+                       Resource                // diagram\r
+                       Resource                // configuration\r
+                       (Map.T String Resource) // existing components\r
+\r
+"""\r
+Sets the elements of the diagram. Diagram is assumed to be empty,\r
+but the configuration may contain existing components that can be found\r
+from the given existing components map.\r
+"""\r
+setElements :: DiagramInfo -> (Dynamic -> <WriteGraph> Resource) -> [DiagramElement Resource] -> <Proc,WriteGraph> [Resource]\r
+setElements (DiagramInfo diagram configuration componentMap) joinMap elementSpecs = (do\r
+    /*elements = map createElement (filter (not . isConnection) elementSpecs)\r
+             + map createElement (filter isConnection elementSpecs)*/\r
+    elements = mapMaybe createElement elementSpecs\r
+    for elements \r
+        (claim diagram L0.ConsistsOf)\r
+    setOrderedSet diagram elements\r
+    iter applyConnectionType (filter isConnectionResource elements)\r
+    syncActivateOnce diagram\r
+    for (zip elementSpecs elements) setConnectionName\r
+    elements\r
+) where\r
+    elementMap = Map.create ()\r
+    idRef = ref (0 :: Integer)\r
+\r
+    isConnectionResource r = isInstanceOf r DIA.Connection\r
+    isConnection (Connection _ _ _) = True\r
+    isConnection (SimpleConnection _ _ _ _ _) = True\r
+    isConnection _ = False\r
+\r
+    freshElementName () = do\r
+        id = getRef idRef\r
+        idRef := id + 1\r
+        show id\r
+    createElement (Component componentType name position properties) = do\r
+        component = if Map.contains componentMap name \r
+                    then Map.unsafeGet componentMap name \r
+                    else newEntity [\r
+                        hasName name,\r
+                        hasParent configuration,\r
+                        hasRandomIdentifier\r
+                    ]\r
+        for properties (\(Property prop value) ->\r
+            untypedClaimRelatedValue component prop value\r
+        )\r
+        element = newOrMappedElement name \r
+        element = updateEntity element [\r
+            hasName (freshElementName ()),\r
+            hasType componentType,\r
+            hasTypedProperty \r
+                DIA.HasTransform\r
+                (positionToDoubleArray position)\r
+                G2D.Transform,\r
+            hasStatement \r
+                MOD.ElementToComponent\r
+                component\r
+        ]\r
+        Map.put elementMap name element\r
+        Just element\r
+    newOrMappedElement eName = do\r
+        element = match Map.get elementMap eName with\r
+            Just element -> element\r
+            Nothing -> newEntity []\r
+        Map.put elementMap eName element\r
+        element\r
+    createElement (SimpleConnection aName ar bName br _) = do\r
+        connection = newEntity [\r
+            hasName (freshElementName ()),\r
+            hasType DIA.RouteGraphConnection\r
+        ]\r
+        a = newOrMappedElement aName\r
+        b = newOrMappedElement bName\r
+        ca = createConnector connection a ar\r
+        cb = createConnector connection b br\r
+        connectNodes ca cb\r
+        Just connection\r
+    createElement (Flag t name label output external tableBinding tableRow position joins) = do\r
+        flag = newOrMappedElement name \r
+        flag = updateEntity flag [\r
+            hasName (freshElementName ()),\r
+            hasLabel label,\r
+            hasType t,\r
+            hasTypedProperty \r
+                DIA.HasTransform\r
+                (positionToDoubleArray position)\r
+                G2D.Transform,\r
+            hasPossibleProperty \r
+                DIA.Flag.HasIOTableBinding\r
+                tableBinding,\r
+            hasPossibleProperty \r
+                DIA.Flag.HasIOTableRowIndex\r
+                tableRow\r
+        ]\r
+        iter (\jRef -> claim\r
+                       (joinMap jRef)\r
+                       DIA.JoinsFlag\r
+                       flag\r
+             ) \r
+            joins\r
+        if output \r
+          then do\r
+            claim flag DIA.HasFlagType DIA.FlagType.OutputFlag\r
+          else ()\r
+        if external \r
+          then do\r
+            claim flag DIA.ExternalFlag flag\r
+          else ()\r
+        Map.put elementMap name flag\r
+        Just flag\r
+    createElement (Connection nodeSpecs edges _) = do\r
+        connection = newEntity [\r
+            hasName (freshElementName ()),\r
+            hasType DIA.RouteGraphConnection\r
+        ]\r
+        \r
+        nodes = map (createNode connection) nodeSpecs\r
+        for edges (\(Edge a b) -> connectNodes (nodes!a) (nodes!b))\r
+        Just connection\r
+    createNode connection (Terminal elementName terminal) = do\r
+        element = newOrMappedElement elementName\r
+        createConnector connection element terminal        \r
+    createNode connection (RouteLine isHorizontal position) = do\r
+        newEntity [\r
+            hasName (freshElementName ()),\r
+            hasType DIA.RouteLine,\r
+            hasProperty DIA.HasPosition\r
+                        position,\r
+            hasProperty DIA.IsHorizontal\r
+                        isHorizontal,\r
+            hasStatement DIA.HasInteriorRouteNode.Inverse\r
+                        connection\r
+        ]\r
+    createConnector connection component terminal = do\r
+        connector = newResource ()\r
+        claim connector\r
+              L0.InstanceOf\r
+              DIA.Connector\r
+        claim component terminal connector\r
+        claim connection \r
+              DIA.HasPlainConnector \r
+              connector\r
+        connector\r
+    connectNodes a b = \r
+        claim a DIA.AreConnected b\r
+    createElement (SVG document position) =\r
+        Just $ newEntity [\r
+            hasName (freshElementName ()),\r
+            hasType DIA.SVGElement,\r
+            hasProperty \r
+                G2D.HasSVGDocument\r
+                document,\r
+            hasTypedProperty \r
+                DIA.HasTransform\r
+                (positionToDoubleArray position)\r
+                G2D.Transform\r
+        ]\r
+    createRealizedFont (Font family size style) = do\r
+        font = newResource ()\r
+        claim font\r
+              L0.InstanceOf\r
+              DIA.RealizedFont\r
+        claimRelatedValue font DIA.RealizedFont.HasFamily family\r
+        claimRelatedValue font DIA.RealizedFont.HasSize size\r
+        claimRelatedValue font DIA.RealizedFont.HasStyle style\r
+        font\r
+    hasFont (Just font) = hasStatement DIA.HasFont (createRealizedFont font)\r
+    hasFont Nothing = const ()\r
+    createElement (Monitor label Nothing (MonitorVisuals font strokeWidth hAlign vAlign) position) = do\r
+        Just $ newEntity [\r
+            hasName (freshElementName ()),\r
+            hasType DIA.Monitor,\r
+            hasProperty \r
+                L0.HasLabel\r
+                label,\r
+            hasTypedProperty \r
+                DIA.HasTransform\r
+                (positionToDoubleArray position)\r
+                G2D.Transform,\r
+            hasTypedProperty \r
+                G2D.HasStrokeWidth\r
+                strokeWidth\r
+                L0.Double,\r
+            hasStatement \r
+                G2D.HasHorizontalAlignment\r
+                (alignmentToResource hAlign),\r
+            hasStatement \r
+                G2D.HasVerticalAlignment\r
+                (alignmentToResource vAlign),\r
+            hasFont font\r
+        ]\r
+    createElement (Monitor label (Just (MonitorReference componentName suffix)) (MonitorVisuals font strokeWidth hAlign vAlign) position) = do\r
+        match (Map.get elementMap componentName) with\r
+          Nothing -> Nothing // Monitored component is not on the same diagram as the monitor. Not supported by this routine.\r
+          Just element -> do\r
+            component = singleObject element MOD.ElementToComponent\r
+            Just $ newEntity [\r
+            hasName (freshElementName ()),\r
+            hasType DIA.Monitor,\r
+            hasProperty \r
+                L0.HasLabel\r
+                label,\r
+            hasProperty \r
+                DIA.HasMonitorSuffix\r
+                suffix,\r
+            hasStatement DIA.HasMonitorComponent component,\r
+            hasTypedProperty \r
+                DIA.HasTransform\r
+                (positionToDoubleArray position)\r
+                G2D.Transform,\r
+            hasTypedProperty \r
+                G2D.HasStrokeWidth\r
+                strokeWidth\r
+                L0.Double,\r
+            hasStatement \r
+                G2D.HasHorizontalAlignment\r
+                (alignmentToResource hAlign),\r
+            hasStatement \r
+                G2D.HasVerticalAlignment\r
+                (alignmentToResource vAlign),\r
+            hasFont font\r
+          ]\r
+    createElement (Text elementType text (TextVisuals font hAlign vAlign) position) =\r
+        Just $ newEntity [\r
+            hasName (freshElementName ()),\r
+            hasType elementType,\r
+            hasProperty \r
+                DIA.HasText\r
+                text,\r
+            hasTypedProperty \r
+                DIA.HasTransform\r
+                (positionToDoubleArray position)\r
+                G2D.Transform,\r
+            hasStatement \r
+                G2D.HasHorizontalAlignment\r
+                (alignmentToResource hAlign),\r
+            hasStatement \r
+                G2D.HasVerticalAlignment\r
+                (alignmentToResource vAlign),\r
+            hasFont font\r
+        ]\r
+    setConnectionName (Connection _ _ (Just name), element) = \r
+        match possibleObject element MOD.ElementToComponent with\r
+            Just c -> claimRelatedValue c L0.HasName name\r
+            Nothing -> print ("Failed to set the name of the connection '" + name + "'.")\r
+    setConnectionName (SimpleConnection _ _ _ _ (Just name), element) = \r
+        match possibleObject element MOD.ElementToComponent with\r
+            Just c -> claimRelatedValue c L0.HasName name\r
+            Nothing -> print ("Failed to set the name of the connection '" + name + "'.")\r
+    setConnectionName (Flag _ name _ _ _ _ _ _ _, element) =\r
+        match possibleObject element MOD.ElementToComponent with\r
+            Just c -> claimRelatedValue c L0.HasName name\r
+            Nothing -> () // This is a typical case\r
+    setConnectionName _ = ()\r
+\r
+"""Returns a diagram in the given model with the given model relative path.""" \r
+diagram :: Model -> [String] -> <ReadGraph> Diagram\r
+diagram model path = \r
+    fromResource $ foldl \r
+        (\r name -> match possibleResourceChild r name with\r
+            Just c -> c\r
+            Nothing -> fail ("Didn't find " + name + ".") \r
+        ) \r
+        (toResource (configurationOf model)) path\r
+\r
+possibleDiagram :: Model -> [String] -> <ReadGraph> (Maybe Diagram)\r
+possibleDiagram model path = \r
+    map fromResource (foldl\r
+        (\r name -> match r with\r
+            Just p -> possibleResourceChild p name\r
+            Nothing -> Nothing \r
+        ) \r
+        (Just $ toResource (configurationOf model)) path)\r
+\r
+/*\r
+"""FIXME: doesn't work anymore with the elementsOfR spec\r
+elementsOf :: Diagram -> <ReadGraph> [DiagramElement String]\r
+elementsOf diagram = map (mapDiagramElement nameOf mapTerminal possibleNameOf nameOf)\r
+                   $ elementsOfR diagram\r
+  where\r
+    nameOf r = relatedValue r L0.HasName\r
+    mapTerminal r = do\r
+        name = nameOf r\r
+        if name == "ConnectionPoint" &&\r
+           r == DIA.Flag.ConnectionPoint\r
+        then "FlagTerminal"\r
+        else name\r
+*/\r
+\r
+"""Returns the elements of the given diagram.""" \r
+elementsOfR :: Diagram -> <ReadGraph> [(DiagramElement Resource, Resource)]\r
+elementsOfR diagram = filterJust $ map readElement' \r
+              (diagramResourceOf diagram # L0.ConsistsOf)\r
+  where\r
+    readElement' element = match readElement element with\r
+        Just el -> Just (el, element)\r
+        Nothing -> Nothing\r
+    readElement element =\r
+        if element `isInstanceOf` DIA.Flag\r
+        then readFlag element\r
+        else if element `isInstanceOf` DIA.SVGElement\r
+        then readSVG element\r
+        else if element `isInstanceOf` DIA.Monitor\r
+        then readMonitor element\r
+        else if element `isInstanceOf` DIA.RouteGraphConnection\r
+        then readConnection element\r
+        else if element `isInstanceOf` DIA.TextElement\r
+        then readText element\r
+        else if element `isInstanceOf` DIA.Element\r
+        then readComponent element\r
+        else Nothing\r
+    readFlag flag = Just $ Flag\r
+        (singleTypeOf \r
+                flag \r
+                DIA.Flag)\r
+        (idOf flag) \r
+        (labelOf flag)\r
+        (existsStatement3 flag DIA.HasFlagType DIA.FlagType.OutputFlag)\r
+        (existsStatement flag DIA.ExternalFlag)\r
+        ((possibleRelatedString flag DIA.Flag.HasIOTableBinding) :: (Maybe String))\r
+        ((possibleRelatedInteger flag DIA.Flag.HasIOTableRowIndex) :: (Maybe Integer))\r
+        (transformOf flag)\r
+        (map toDynamic $ flag # DIA.FlagIsJoinedBy)\r
+    readComponent element = do\r
+        component = singleObject \r
+            element \r
+            MOD.ElementToComponent\r
+        Just (Component \r
+            (singleTypeOf \r
+                element \r
+                DIA.Element)\r
+            (nameOf component) \r
+            (transformOf element)\r
+            (readAttributes component))\r
+    readSVG element = do\r
+        Just (SVG \r
+            (relatedValue element G2D.HasSVGDocument) \r
+            (transformOf element)\r
+            )\r
+    readMonitor element = do\r
+        font = readFont element (singleObject element DIA.HasFont)\r
+        hAlign = resourceToAlignment (singleObject element G2D.HasHorizontalAlignment)\r
+        vAlign = resourceToAlignment (singleObject element G2D.HasVerticalAlignment)\r
+        label = (relatedValue2 element L0.HasLabel)\r
+        strokeWidth = relatedValueWithDefault (-1.0) element G2D.HasStrokeWidth \r
+        transform = (transformOf element)  \r
+        match (existsStatement element DIA.HasMonitorSuffix) with\r
+          True -> do\r
+            suffix = (relatedValue element DIA.HasMonitorSuffix)\r
+            monitorComponent = (singleObject element DIA.HasMonitorComponent)\r
+            componentName = relatedValue monitorComponent L0.HasName\r
+            Just (Monitor label (Just (MonitorReference componentName suffix)) (MonitorVisuals font strokeWidth hAlign vAlign) transform) \r
+          False -> Just (Monitor label Nothing (MonitorVisuals font strokeWidth hAlign vAlign) transform)\r
+    readText element = do\r
+        elementType = singleTypeOf element DIA.Element\r
+        font = readPossibleFont element \r
+        hAlign = resourceToAlignment (singleObject element G2D.HasHorizontalAlignment)\r
+        vAlign = resourceToAlignment (singleObject element G2D.HasVerticalAlignment)\r
+        text = relatedValueWithDefault "" element DIA.HasText \r
+        transform = (transformOf element)\r
+        Just (Text elementType text (TextVisuals font hAlign vAlign) transform)\r
+    readPossibleFont element =\r
+        match possibleObject element DIA.HasFont with\r
+            Just f -> readFont element f\r
+            Nothing -> Nothing\r
+    readFont element font = do\r
+        if font `isInstanceOf` DIA.RealizedFont\r
+        then do\r
+            family = (relatedValue font DIA.RealizedFont.HasFamily)\r
+            size = (relatedValue font DIA.RealizedFont.HasSize)\r
+            style = (relatedValue font DIA.RealizedFont.HasStyle)\r
+            Just (Font family size style)\r
+        else Nothing\r
+    readAttributes component = let\r
+        allPredicates = map objectOf (statements (singleTypeOf component L0.Entity) L0.DomainOf)\r
+        is p = isSubrelationOf p L0.HasProperty\r
+        hasPropertyPredicates = filter is allPredicates\r
+        propertyStatements = map (singleStatement component) hasPropertyPredicates\r
+        p stm = match (untypedPossibleValueOf (objectOf stm)) with\r
+            Just v -> Just (Property (predicateOf stm) v)\r
+            _      -> Nothing\r
+      in mapMaybe p propertyStatements\r
+            \r
+    readConnection element = do\r
+        connectors = element # DIA.HasConnector\r
+        routeLines = element # DIA.HasInteriorRouteNode\r
+        nodes = map (readConnector element) connectors\r
+              + map readRouteLine routeLines\r
+        \r
+        nodeResources = connectors + routeLines\r
+        nodeResourceWithIds = zip nodeResources [0..length nodeResources-1]\r
+        edges = runProc do\r
+            rMap = Map.fromList nodeResourceWithIds\r
+            edgesOf (node,i) = \r
+                [ Edge i j\r
+                | r <- node # DIA.AreConnected\r
+                , j = Map.unsafeGet rMap r\r
+                , j > i ]\r
+            concatMap edgesOf nodeResourceWithIds\r
+        \r
+        Just $ Connection nodes edges (readConnectionName element)\r
+    readConnectionName element = \r
+        match possibleObject element MOD.ElementToComponent with\r
+            Just c -> possibleNameOf c\r
+            Nothing -> Nothing\r
+    readConnector connection r = Terminal\r
+        (idOf $ objectOf stat)\r
+        (inverseOf $ predicateOf stat)\r
+      where\r
+        stat = [ stat\r
+            | stat <- statements r STR.Connects\r
+            , objectOf stat != connection \r
+            ]!0\r
+    readRouteLine r = RouteLine\r
+        (relatedValue r DIA.IsHorizontal) \r
+        (relatedValue r DIA.HasPosition)\r
+    transformOf element = do \r
+        da = fromDoubleArray $\r
+            relatedValue element DIA.HasTransform\r
+        Position (da!0) (da!1) (da!2) (da!3) (da!4) (da!5)\r
+    nameOf r = relatedValue r L0.HasName\r
+    labelOf r = relatedValue2 r L0.HasLabel\r
+    idOf r = match possibleObject r MOD.ElementToComponent with\r
+        Just c -> nameOf c\r
+        Nothing -> if r `isInstanceOf` DIA.Flag\r
+                   then "FLAG_" + nameOf r\r
+                   else fail ("Element " + show r + " was not mapped to a component.")\r
+\r
+importJava "org.simantics.diagram.synchronization.graph.DiagramGraphUtil" where\r
+    """Takes one connection element and returns possible diagram type.""" \r
+    determineConnectionType :: Resource -> <ReadGraph> Maybe Resource\r
+    \r
+    rotateConnection :: Resource -> Double -> Double -> Boolean -> <WriteGraph> ()\r
+    flipConnection :: Resource -> Boolean -> Double -> <WriteGraph> ()   \r
+\r
+applyDiagramMapping :: Resource -> <Proc,WriteGraph> ()\r
+applyDiagramMapping diagram = do\r
+  syncActivateOnce diagram\r
+  ()\r
+\r
+"""Returns the diagram flag type resource used for all generic diagram flags."""\r
+genericFlagType :: () -> <ReadGraph> Resource\r
+genericFlagType _ = DIA.Flag\r
+\r
+/* Use functions in Simantics/PageSettings\r
+importJava "org.simantics.diagram.synchronization.graph.DiagramGraphUtil" where\r
+    @JavaName setPageBordersVisible\r
+    setPageBordersVisible :: Diagram -> Boolean -> <WriteGraph> ()\r
+    \r
+    @JavaName setMarginsVisible\r
+    setMarginsVisible :: Diagram -> Boolean -> <WriteGraph> ()\r
+*/\r
+importJava "org.simantics.modeling.typicals.TypicalUtil" where\r
+    @JavaName newMasterTypical\r
+    newTypicalDiagram :: Library -> Diagram\r
+\r
+    @JavaName syncTypicalInstance\r
+    syncTypicalInstance :: Resource -> <WriteGraph> ()\r
+    \r
+syncActivateDiagram :: Diagram -> <WriteGraph, Proc> Boolean\r
+syncActivateDiagram composite = do\r
+    diagram = compositeToDiagram' $ toResource composite\r
+    syncActivateOnce diagram\r
+    True\r
+\r
+// --- Diagrams ---------------------------------------------------\r
+\r
+importJava "org.simantics.structural2.utils.StructuralUtils" where\r
+    @JavaName newComponent\r
+    createComposite__ :: Configuration -> String -> Resource -> <WriteGraph> Diagram\r
+\r
+compositeToDiagram :: Resource -> <ReadGraph> Diagram\r
+compositeToDiagram c = fromResource (singleObject c MOD.CompositeToDiagram) \r
+\r
+createComposite :: Configuration -> String -> Resource -> <WriteGraph> Diagram\r
+createComposite diagramFolder name compositeType = do\r
+     newName = findFreshName name (toResource diagramFolder)\r
+     createComposite__ diagramFolder newName compositeType\r
+\r
+elementToComponent :: Element -> <ReadGraph> Component\r
+elementToComponent element = do\r
+    component = singleObject (toResource element) MOD.ElementToComponent\r
+    fromResource component\r
+    \r
+componentToElement :: Component -> <ReadGraph> Element\r
+componentToElement component = do\r
+    element = singleObject (toResource component) MOD.ComponentToElement\r
+    fromResource element\r
+\r
+getConnections :: Diagram -> <ReadGraph> [Resource]\r
+getConnections diagram = [object | object <- (toResource $ compositeToDiagram $ toResource diagram) # L0.ConsistsOf, isInstanceOf object DIA.RouteGraphConnection]\r
+\r
+getConnection :: Diagram -> String -> <ReadGraph> [Resource]\r
+getConnection diagram name = do\r
+    connections = getConnections diagram\r
+    filter (\x -> relatedValue2 x L0.HasName == name) connections\r
+\r
+setTransform :: Resource -> DoubleArray -> <WriteGraph> ()\r
+setTransform element transform = claimRelatedValueWithType element DIA.HasTransform G2D.Transform transform \r
+    \r
+importJava "org.simantics.modeling.svg.CreateSVGElement" where\r
+    createSVGElement :: Resource -> String -> ByteArray -> Double -> Double -> <WriteGraph> ()\r
+    \r
+    importSVGElement :: Resource -> File -> Double -> Double -> <WriteGraph> ()\r
+    \r
+importJava "org.simantics.diagram.synchronization.graph.RemoveElement" where\r
+    removeElement :: Resource -> Resource -> <WriteGraph> ()\r
+\r
+setStraightConnectionLines :: Resource -> Boolean -> <WriteGraph> ()\r
+setStraightConnectionLines element v =\r
+    for (element # STR.IsConnectedTo) $ \connector ->\r
+        claimRelatedValue connector DIA.Connector.straight v\r
+\r
+showProfileMonitors :: Resource -> Boolean -> <WriteGraph> ()\r
+showProfileMonitors element v = claimRelatedValue element DIA.Element.hideProfileMonitors (not v)\r
+\r
+setProfileMonitorsDirectionUp :: Resource -> Boolean -> <WriteGraph> ()\r
+setProfileMonitorsDirectionUp element v = claimRelatedValue element DIA.Element.upProfileMonitors v\r
+\r
+importJava "org.simantics.diagram.flag.Joiner" where\r
+    joinFlagsLocal :: [Resource] -> <WriteGraph> ()\r
+\r
+importJava "org.simantics.diagram.flag.RouteGraphConnectionSplitter" where\r
+    splitConnection :: Resource -> Double -> Double -> <WriteGraph> ()\r
+\r
+importJava "org.simantics.diagram.handler.CopyPasteUtil" where\r
+    moveConnection :: Resource -> Double -> Double -> <WriteGraph> ()\r
+\r
+importJava "org.simantics.diagram.content.ConnectionUtil" where\r
+    translateRouteNodes :: Resource -> Double -> Double -> <WriteGraph> ()\r
+    \r
+importJava "org.simantics.diagram.synchronization.graph.DiagramGraphUtil" where\r
+    defaultSymbolDropHandler :: [WorkbenchSelectionElement] -> <WriteGraph> ()    
\ No newline at end of file