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