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
8 // ----------------------------------------------------------------------------
\r
10 data Synchronizable = Synchronizable Variable Variable String String
\r
12 // ----------------------------------------------------------------------------
\r
13 // Utility functions and imports
\r
16 importJava "org.simantics.db.layer0.variable.Variables" where
\r
18 rvi :: Variable -> <ReadGraph> String
\r
21 importJava "org.simantics.databoard.util.URIStringUtils" where
\r
23 escapeUri :: String -> String
\r
25 unescapeUri :: String -> String
\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
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
41 concatStrings :: [String] -> String
\r
42 concatStrings strings = foldl (\s1 s2 -> s1 + s2) "" strings
\r
45 glueFilteredStrings :: String -> (String -> String) -> [String] -> String
\r
46 glueFilteredStrings glue f strings = foldl (\s1 s2 -> s1 + glue + (f s2)) "" strings
\r
49 reverseSynchronizable :: (Variable -> <ReadGraph> Maybe Variable) -> Variable -> <ReadGraph> Maybe Synchronizable
\r
50 reverseSynchronizable experimentPropertyMapper configProp = match (experimentPropertyMapper configProp) with
\r
52 Just activeProp -> let
\r
53 configValue = (VAR.propertyValue configProp "HasDisplayValue") :: String
\r
54 activeValue = (VAR.propertyValue activeProp "HasDisplayValue") :: String
\r
56 if (activeValue == configValue) then Nothing
\r
57 else Just $ Synchronizable
\r
64 resolveComposite :: String -> [String] -> <ReadGraph> Maybe Resource
\r
65 resolveComposite pathContextUri path = DB.possibleResource (pathContextUri + (glueFilteredStrings "/" escapeUri path))
\r
68 resolveComposites :: Resource -> [[String]] -> <Proc,ReadGraph> MSet.T Resource
\r
69 resolveComposites pathContext paths = MSet.fromList (mapMaybe (resolveComposite (DB.uriOf pathContext)) paths)
\r
72 reverseSynchronizableComponents :: (Resource -> <ReadGraph> [Variable]) -> [[String]] -> <Proc,ReadGraph> [Variable]
\r
73 reverseSynchronizableComponents componentFinder folderPaths = let
\r
75 configurationContext = MODEL.configurationOf m
\r
76 composites = resolveComposites configurationContext folderPaths
\r
77 components = componentFinder m
\r
79 if (length folderPaths > 0) then filter (partOfComposites composites (VAR.resourceVariable configurationContext)) components
\r
83 reverseSynchronizableProperties :: (Variable -> <ReadGraph> Maybe Variable) -> Variable -> <ReadGraph> [Synchronizable]
\r
84 reverseSynchronizableProperties experimentPropertyMapper componentVar = mapMaybe (reverseSynchronizable experimentPropertyMapper) (VAR.properties componentVar)
\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
94 path + "\t" + componentName + "\t" + propertyName + "\t" + configValue + "\t" + activeValue + "\n"
\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
103 componentName + " " + propertyName + " " + configValue + " -> " + activeValue
\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
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
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
126 > findReverseSynchronizables []
\r
127 > findReverseSynchronizables [["Folder"]]
\r
128 > findReverseSynchronizables [["Folder", "Subfolder", "Drawing 1"], ["Folder", "Subfolder 2", "Another Drawing"]]
\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
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
142 <path>\t<componentName>\t<propertyName>\t<configValue>\t<activeValue>
\r
145 > print (formatSynchronizables (findReverseSynchronizables []))
\r
147 formatSynchronizables :: [Synchronizable] -> <ReadGraph> String
\r
148 formatSynchronizables syncs = concatStrings $ map formatSynchronizable syncs
\r
151 applyReverseSynchronization :: Synchronizable -> <Proc,WriteGraph> ()
\r
152 applyReverseSynchronization s = do
\r
153 print ("Reverse synchronizing " + (showSynchronizable s))
\r
155 (Synchronizable configVar _ _ activeValue) -> VAR.setPropertyValue configVar "HasDisplayValue" activeValue
\r
158 Applies a list of reverse synchronization operations into the active model's configuration.
\r
161 > applyReverseSynchronizations (findReverseSynchronizables [])
\r
163 applyReverseSynchronizations :: [Synchronizable] -> <Proc,WriteGraph> ()
\r
164 applyReverseSynchronizations syncs = do
\r
165 DB.disableDependencies ()
\r
166 for syncs applyReverseSynchronization
\r