]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/scl/Simantics/ReverseSynchronization.scl
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / scl / Simantics / ReverseSynchronization.scl
1 import "MSet" as MSet\r
2 import "Simantics/DB" (Resource)\r
3 import "Simantics/Variables" (Variable)\r
4 import "Simantics/DB" as DB\r
5 import "Simantics/Variables" as VAR\r
6 import "Simantics/Model" as MODEL\r
7 \r
8 // ----------------------------------------------------------------------------\r
9 \r
10 data Synchronizable = Synchronizable Variable Variable String String\r
11 \r
12 // ----------------------------------------------------------------------------\r
13 // Utility functions and imports\r
14 \r
15 @private\r
16 importJava "org.simantics.db.layer0.variable.Variables" where\r
17     @JavaName getRVI\r
18     rvi :: Variable -> <ReadGraph> String\r
19 \r
20 @private\r
21 importJava "org.simantics.databoard.util.URIStringUtils" where\r
22     @JavaName escape\r
23     escapeUri :: String -> String\r
24     @JavaName unescape\r
25     unescapeUri :: String -> String\r
26 \r
27 @private\r
28 partOfComposites :: MSet.T Resource -> Variable -> Variable -> <Proc,ReadGraph> Boolean\r
29 partOfComposites composites context v = let\r
30         recurseParent var = match (VAR.possibleParent var) with\r
31             Just p -> partOfComposites composites context p\r
32             Nothing -> False\r
33     in\r
34         if (context == v) then False\r
35         else match (VAR.possibleRepresents v) with\r
36             Nothing -> recurseParent v\r
37             Just r -> if (MSet.contains composites r) then True\r
38                       else recurseParent v\r
39 \r
40 @private\r
41 concatStrings :: [String] -> String\r
42 concatStrings strings = foldl (\s1 s2 -> s1 + s2) "" strings\r
43 \r
44 @private\r
45 glueFilteredStrings :: String -> (String -> String) -> [String] -> String\r
46 glueFilteredStrings glue f strings = foldl (\s1 s2 -> s1 + glue + (f s2)) "" strings\r
47 \r
48 @private\r
49 reverseSynchronizable :: (Variable -> <ReadGraph> Maybe Variable) -> Variable -> <ReadGraph> Maybe Synchronizable\r
50 reverseSynchronizable experimentPropertyMapper configProp = match (experimentPropertyMapper configProp) with \r
51     Nothing -> Nothing\r
52     Just activeProp -> let\r
53             configValue = (VAR.propertyValue configProp "HasDisplayValue") :: String\r
54             activeValue = (VAR.propertyValue activeProp "HasDisplayValue") :: String\r
55         in do\r
56             if (activeValue == configValue) then Nothing\r
57             else Just $ Synchronizable\r
58                 configProp\r
59                 activeProp\r
60                 configValue\r
61                 activeValue\r
62 \r
63 @private\r
64 resolveComposite :: String -> [String] -> <ReadGraph> Maybe Resource\r
65 resolveComposite pathContextUri path = DB.possibleResource (pathContextUri + (glueFilteredStrings "/" escapeUri path))\r
66 \r
67 @private\r
68 resolveComposites :: Resource -> [[String]] -> <Proc,ReadGraph> MSet.T Resource\r
69 resolveComposites pathContext paths = MSet.fromList (mapMaybe (resolveComposite (DB.uriOf pathContext)) paths)\r
70 \r
71 @private\r
72 reverseSynchronizableComponents :: (Resource -> <ReadGraph> [Variable]) -> [[String]] -> <Proc,ReadGraph> [Variable]\r
73 reverseSynchronizableComponents componentFinder folderPaths = let\r
74         m = DB.currentModel\r
75         configurationContext = MODEL.configurationOf m\r
76         composites = resolveComposites configurationContext folderPaths\r
77         components = componentFinder m\r
78     in\r
79         if (length folderPaths > 0) then filter (partOfComposites composites (VAR.resourceVariable configurationContext)) components\r
80         else components\r
81 \r
82 @private\r
83 reverseSynchronizableProperties :: (Variable -> <ReadGraph> Maybe Variable) -> Variable -> <ReadGraph> [Synchronizable]\r
84 reverseSynchronizableProperties experimentPropertyMapper componentVar = mapMaybe (reverseSynchronizable experimentPropertyMapper) (VAR.properties componentVar)\r
85 \r
86 @private\r
87 formatSynchronizable :: Synchronizable -> <ReadGraph> String\r
88 formatSynchronizable (Synchronizable config active configValue activeValue) = let\r
89         component = VAR.variableParent config\r
90         componentName = VAR.name component\r
91         propertyName = VAR.name config\r
92         path = unescapeUri (rvi (VAR.variableParent component))\r
93     in\r
94         path + "\t" + componentName + "\t" + propertyName + "\t" + configValue + "\t" + activeValue + "\n"\r
95 \r
96 @private\r
97 showSynchronizable :: Synchronizable -> <ReadGraph> String \r
98 showSynchronizable (Synchronizable config active configValue activeValue) = let\r
99         component = VAR.variableParent config\r
100         componentName = VAR.name component\r
101         propertyName = VAR.name config\r
102     in\r
103         componentName + " " + propertyName + " " + configValue + " -> " + activeValue\r
104 \r
105 """\r
106 Resolves all component properties that can be reverse synchronized from\r
107 the active model's currently active solver state into the active model's\r
108 configuration. The @Synchronizable@s resolved can then be passed on to other\r
109 functions in this module for printing and application.\r
110 \r
111 Reverse synchronizability of a component and its properties is left up to\r
112 argument functions. The `moduleFinder` function looks for all synchronizable components\r
113 within the model specified as argument and the `experimentPropertyFilter`\r
114 function filters the properties that are considered reverse-synchronizable.\r
115 \r
116 The @folderPaths@ argument can be used to tell the system which subfolders\r
117 of the model configuration to check for reverse-synchronizable properties.\r
118 For example, to specify that you want all modules contained by the root\r
119 folder @Folder@ to be examined, you should just specify @[["Folder"]]@.\r
120 On the other hand if you want to check only specific subfolders/drawings,\r
121 you can specify them like this: @[["Folder", "Subfolder","Drawing"], ["Folder", "Subfolder 2", "Another Drawing"]]@.\r
122 To examine all modules in the model configuration, the empty list @[]@\r
123 can be specified.\r
124 \r
125 Examples:\r
126 > findReverseSynchronizables []\r
127 > findReverseSynchronizables [["Folder"]]\r
128 > findReverseSynchronizables [["Folder", "Subfolder", "Drawing 1"], ["Folder", "Subfolder 2", "Another Drawing"]]\r
129 """\r
130 findReverseSynchronizables :: (Resource -> <ReadGraph> [Variable]) ->\r
131                           (Variable -> <ReadGraph> Maybe Variable) ->\r
132                           [[String]] -> <Proc,ReadGraph> [Synchronizable]\r
133 findReverseSynchronizables componentFinder experimentPropertyMapper folderPaths =\r
134     concatMap (reverseSynchronizableProperties experimentPropertyMapper)\r
135               (reverseSynchronizableComponents componentFinder folderPaths)\r
136 \r
137 """\r
138 Formats the specified list of synchronizables into a String where each\r
139 line of text represents a single synchronizable in the following\r
140 tab-separated format that can be directly copy-pasted into e.g. Excel:\r
141 \r
142 <path>\t<componentName>\t<propertyName>\t<configValue>\t<activeValue>\r
143 \r
144 Example:\r
145 > print (formatSynchronizables (findReverseSynchronizables []))\r
146 """\r
147 formatSynchronizables :: [Synchronizable] -> <ReadGraph> String \r
148 formatSynchronizables syncs = concatStrings $ map formatSynchronizable syncs\r
149 \r
150 @private\r
151 applyReverseSynchronization :: Synchronizable -> <Proc,WriteGraph> ()\r
152 applyReverseSynchronization s = do\r
153     print ("Reverse synchronizing " + (showSynchronizable s))\r
154     match s with\r
155         (Synchronizable configVar _ _ activeValue) -> VAR.setPropertyValue configVar "HasDisplayValue" activeValue\r
156 \r
157 """\r
158 Applies a list of reverse synchronization operations into the active model's configuration.\r
159 \r
160 Example:\r
161 > applyReverseSynchronizations (findReverseSynchronizables [])\r
162 """\r
163 applyReverseSynchronizations :: [Synchronizable] -> <Proc,WriteGraph> ()\r
164 applyReverseSynchronizations syncs = do\r
165     DB.disableDependencies ()\r
166     for syncs applyReverseSynchronization\r