reset a3, kut Charlie ;)
[tt2015.git] / a3 / code / Gast / iDataGraphvizForm.icl
diff --git a/a3/code/Gast/iDataGraphvizForm.icl b/a3/code/Gast/iDataGraphvizForm.icl
new file mode 100644 (file)
index 0000000..eb7080c
--- /dev/null
@@ -0,0 +1,208 @@
+implementation module iDataGraphvizForm\r
+\r
+import StdEnv\r
+import StdiData, iDataHandler\r
+import Graphviz\r
+import launch\r
+import Directory\r
+\r
+derive gUpd   [], Maybe, NodeState, //Digraph, \r
+                                               Arrow, ArrowShape, ArrowType, ClusterMode, Color, CompassPoint, DirType, DotPoint, \r
+                                               EdgeAttribute, EdgeStyle, GraphAttribute, LayerId, LayerList, LayerRange, Margin, \r
+                                               NodeAttribute, NodeDef, NodeShape, NodeStyle, OutputMode, Pad, PageDir, Pointf, \r
+                                               RankDir, RankType, Ratio, Rect, SelectedItem, Side, Sizef, StartStyle, StartType, ViewPort\r
+derive gPrint Maybe, Digraph, NodeState,\r
+                                               Arrow, ArrowShape, ArrowType, ClusterMode, Color, CompassPoint, DirType, DotPoint, \r
+                                               EdgeAttribute, EdgeStyle, GraphAttribute, LayerId, LayerList, LayerRange, Margin, \r
+                                               NodeAttribute, NodeDef, NodeShape, NodeStyle, OutputMode, Pad, PageDir, Pointf, \r
+                                               RankDir, RankType, Ratio, Rect, SelectedItem, Side, Sizef, StartStyle, StartType, ViewPort\r
+derive gParse Maybe, Digraph, NodeState,\r
+                                               Arrow, ArrowShape, ArrowType, ClusterMode, Color, CompassPoint, DirType, DotPoint, \r
+                                               EdgeAttribute, EdgeStyle, GraphAttribute, LayerId, LayerList, LayerRange, Margin, \r
+                                               NodeAttribute, NodeDef, NodeShape, NodeStyle, OutputMode, Pad, PageDir, Pointf, \r
+                                               RankDir, RankType, Ratio, Rect, SelectedItem, Side, Sizef, StartStyle, StartType, ViewPort\r
+derive gerda  Digraph, NodeState, \r
+                                               Arrow, ArrowShape, ArrowType, ClusterMode, Color, CompassPoint, DirType, DotPoint, \r
+                                               EdgeAttribute, EdgeStyle, GraphAttribute, LayerId, LayerList, LayerRange, Margin, \r
+                                               NodeAttribute, NodeDef, NodeShape, NodeStyle, OutputMode, Pad, PageDir, Pointf, \r
+                                               RankDir, RankType, Ratio, Rect, SelectedItem, Side, Sizef, StartStyle, StartType, ViewPort\r
+derive read   Maybe, Digraph, NodeState, \r
+                                               Arrow, ArrowShape, ArrowType, ClusterMode, Color, CompassPoint, DirType, DotPoint, \r
+                                               EdgeAttribute, EdgeStyle, GraphAttribute, LayerId, LayerList, LayerRange, Margin, \r
+                                               NodeAttribute, NodeDef, NodeShape, NodeStyle, OutputMode, Pad, PageDir, Pointf, \r
+                                               RankDir, RankType, Ratio, Rect, SelectedItem, Side, Sizef, StartStyle, StartType, ViewPort\r
+derive write  Maybe, Digraph, NodeState, \r
+                                               Arrow, ArrowShape, ArrowType, ClusterMode, Color, CompassPoint, DirType, DotPoint, \r
+                                               EdgeAttribute, EdgeStyle, GraphAttribute, LayerId, LayerList, LayerRange, Margin, \r
+                                               NodeAttribute, NodeDef, NodeShape, NodeStyle, OutputMode, Pad, PageDir, Pointf, \r
+                                               RankDir, RankType, Ratio, Rect, SelectedItem, Side, Sizef, StartStyle, StartType, ViewPort\r
+\r
+//     Specialization of iData for Digraph values:\r
+gUpd {|Digraph|} (UpdSearch (UpdC node) 0) (Digraph name graphAtts nodeDefs _)\r
+                                               = (UpdDone, Digraph name graphAtts nodeDefs nodeNr)\r
+where\r
+       nodeNr                          = case [nr \\ NodeDef nr _ nodeAtts _ <- nodeDefs | not (isEmpty (filter (isNAtt_label node) nodeAtts))] of\r
+                                                       [nr:_]  = Just (Node nr)\r
+                                                       _               = Nothing\r
+       isNAtt_label l (NAtt_label l`)\r
+                                               = l==l`\r
+       isNAtt_label _ _        = False\r
+gUpd {|Digraph|} (UpdSearch other cnt) g\r
+                                               = (UpdSearch other (cnt-1),g)\r
+gUpd {|Digraph|} (UpdCreate l) _\r
+                                               = (UpdCreate l,Digraph "" [] [] Nothing)\r
+gUpd {|Digraph|} mode g        = (mode,g)\r
+\r
+gForm {|Digraph|} (init,formid) hst\r
+       # (value,hst)           = accWorldHSt (obtainValueFromConfig dot_exe_path_name) hst\r
+       | isNothing value       = (result [ Txt ("Could not obtain "+++dot_exe_path_name+++" from "+++config_file_name+++".") ],hst)\r
+       # exe                           = fromJust value\r
+       # hst                           = appWorldHSt (ensureDirectory (target "")) hst         // PA++\r
+       # (ok,hst)                      = accWorldHSt (writefile (target (dotext name)) (printDigraph (enhanceDigraphWithLinks digraph))) hst\r
+       | not ok                        = (result [ Txt ("Could not write Digraph to "+++target (dotext name)+++".") ],hst)\r
+       # ((ok,exit),hst)       = accWorldHSt (collect3 (launch exe (toGIF (target name)))) hst\r
+       | not ok                        = (result [ Txt ("Creation of "+++gifext (target name)+++" failed. Exit code = "+++toString exit+++".") ],hst)\r
+       # ((ok,exit),hst)       = accWorldHSt (collect3 (launch exe (toMAP (target name) name))) hst\r
+       | not ok                        = (result [ Txt ("Creation of "+++mapext (target name)+++" failed. Exit code = "+++toString exit+++".") ],hst)\r
+       # ((ok,lines),hst)      = accWorldHSt (collect3 (readfile (mapext map_source_name))) hst\r
+       | not ok                        = (result [ Txt ("Reading of "+++mapext (target name)+++" failed.") ],hst)\r
+       # (cntr,hst)            = CntrHSt hst\r
+       # lines                         = map (enhanceMAPlineWithOnClickEvent cntr) lines\r
+       | otherwise                     = (result [ \r
+                                                          Img [ Img_Src    (gifext img_source_name)\r
+                                                               , Img_Usemap ("#"+++name)\r
+//                                                             , Img_Width  (Percent 100)\r
+                                                               , Img_Height (Percent 60)\r
+                                                               ]\r
+                                                         : map InlineCode lines\r
+                                                         ],incrHSt 1 hst)\r
+where\r
+       digraph                         = formid.ival\r
+       name                            = formid.id\r
+       clean_name                      = clean_up name\r
+       result html                     = {changed=False,value=digraph,form=html}\r
+       img_source_name         = ThisExe+++"/"+++name\r
+       map_source_name         = ThisExe+++"/"+++name\r
+\r
+       \r
+       clean_up :: !String -> String\r
+//     clean_up name           = name\r
+       clean_up name           = {clean_char c \\ c<-: name}\r
+       clean_char '.'          = 'x'\r
+       clean_char '+'          = 'p'\r
+       clean_char '-'          = 'm'\r
+       clean_char c            = c\r
+\r
+       enhanceMAPlineWithOnClickEvent :: !Int !String -> String\r
+       enhanceMAPlineWithOnClickEvent cntr line\r
+               | line%(0,5) == "<area "\r
+                       | size line <= 6 || isNothing href_bounds //|| isNothing title_bounds\r
+                                               = line\r
+                       | otherwise     = line%(0,fst href-1)                                       +++ \r
+                                                 "onclick=\"toClean(this,'" +++ encodeTriplet(name,cntr,UpdC titletext) +++ "',true,false,false);\" " +++ \r
+                                                 "id=\""+++ encodeInputId(name,cntr,UpdC titletext) +++ "\"" +++\r
+                                                 line%(snd href+1,size line-1)\r
+               | line%(0,4) == "<map "\r
+                                               = "<map id=\"" +++ name +++ "\" name=\"" +++ name +++ "\">\n"\r
+               | otherwise\r
+                                               = line\r
+       where\r
+               href_bounds             = boundsOfKeyValue "href="  line\r
+               title_bounds    = boundsOfKeyValue "title=" line\r
+               href                    = fromJust href_bounds\r
+               title                   = fromJust title_bounds\r
+               titletext               = line%(fst title+7,snd title-1)\r
+\r
+boundsOfKeyValue :: !String !String -> Maybe (!Int,!Int)\r
+boundsOfKeyValue key str\r
+       = case [i \\ i<-[0..size str-size key] | str%(i,i+size key-1) == key] of\r
+               [i : _]                 = case [j \\ j<-[i..size str-1] | str.[j]=='\"'] of\r
+                                                       [_,close:_] = Just (i,close)\r
+                                                       otherwise       = Nothing\r
+               otherwise               = Nothing\r
+\r
+enhanceDigraphWithLinks :: !Digraph -> Digraph\r
+enhanceDigraphWithLinks (Digraph name graphAtts nodeDefs selected)\r
+       = Digraph name graphAtts \r
+               [  NodeDef nr st [ NAtt_URL ("http://localhost/"+++ThisExe) : nodeAtts ] edges \r
+               \\ NodeDef nr st nodeAtts edges <- nodeDefs\r
+               ] selected\r
+\r
+obtainValueFromConfig :: !String !*env -> (!Maybe String,!*env) | FileSystem env\r
+obtainValueFromConfig name env\r
+       # (ok,file,env)         = fopen config_file_name FReadText env\r
+       | not ok                        = (Nothing,env)\r
+       # (value,file)          = obtainValueFromFile name file\r
+       # (ok,env)                      = fclose file env\r
+       | not ok                        = (Nothing,env)\r
+       | otherwise                     = (value,  env)\r
+where\r
+       obtainValueFromFile :: !String !*File -> (!Maybe String,!*File)\r
+       obtainValueFromFile name file\r
+               # (lines,file)  = readlines file\r
+               # value                 = case [ skipSpace (line%(name_length,size line-2)) \\ line<-lines\r
+                                                                                                    | line.[0] <> commentsymbol \r
+                                                                                                   && size line > name_length\r
+                                                                                                   && line%(0,name_length-1) == name\r
+                                                      ] of [v:_]       = Just v\r
+                                                           _           = Nothing\r
+               = (value,file)\r
+       where\r
+               name_length             = size name\r
+\r
+config_file_name               :== "iDataGraphvizForm.config"\r
+commentsymbol                  :== '%'\r
+dot_exe_path_name              :== "DOT_PATH"\r
+target file                            = MyAbsDir +++ ThisExe +++ "\\" +++ file\r
+toGIF file                             = "-Tgif -o "   +++ "\"" +++ gifext file +++ "\" \"" +++ dotext file +++ "\""\r
+//toMAP file                           = "-Tcmapx -o " +++ "\"" +++ mapext file +++ "\" \"" +++ dotext file +++ "\""\r
+toMAP file name                        = "-Tcmapx" +++ " -Glabel=" +++ name +++ " -o " +++ "\"" +++ mapext file +++ "\" \"" +++ dotext file +++ "\""\r
+gifext file                            = file +++ ".gif"\r
+mapext file                            = file +++ ".map"\r
+dotext file                            = file +++ ".dot"\r
+\r
+//     Utility functions:\r
+/*     ensureDirectory path env\r
+               checks whether the directory at path exists. If so, no further actions are taken.\r
+               If not, the directory is created.\r
+*/\r
+import StdDebug\r
+\r
+ensureDirectory :: !String !*env -> *env | FileSystem env      // PA++\r
+ensureDirectory pathname env\r
+       # ((ok,path), env)      = pd_StringToPath pathname env\r
+       | not ok                        = env\r
+       # ((err,info),env)      = getFileInfo path env\r
+       | err<>NoDirError       = snd (createDirectory path env)\r
+       | otherwise                     = env\r
+\r
+writefile :: !String ![String] !*env -> (!Bool,!*env) | FileSystem env\r
+writefile fileName content env\r
+       # (ok,file,env)         = fopen fileName FWriteText env\r
+       | not ok                        = (False,env)\r
+       # file                          = foldl (<<<) file content\r
+       = fclose file env\r
+\r
+readfile  :: !String !*env -> (!Bool,![String],!*env) | FileSystem env\r
+readfile fileName env\r
+       # (ok,file,env)         = fopen fileName FReadText env\r
+       | not ok                        = (False,[],env)\r
+       # (content,file)        = readlines file\r
+       # (ok,env)                      = fclose file env\r
+       = (ok,content,env)\r
+\r
+readlines :: !*File -> (![String],!*File)\r
+readlines file\r
+       # (end,file)            = fend file\r
+       | end                           = ([],file)\r
+       # (line, file)          = freadline file\r
+       # (lines,file)          = readlines file\r
+       = ([line:lines],file)\r
+\r
+collect3 :: (.s -> (.a,.b,.s)) .s -> (.(.a,.b),.s)\r
+collect3 f st\r
+       # (a,b,st)                      = f st\r
+       = ((a,b),st)\r
+\r
+skipSpace :: !String -> String\r
+skipSpace str                  = toString (dropWhile isSpace (fromString str))\r