-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathAbstractGraphView.hs
852 lines (785 loc) · 33.1 KB
/
AbstractGraphView.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
{-# LANGUAGE FlexibleInstances #-}
{- |
Module : $Header$
Description : Interface for graph viewing and abstraction
Copyright : (c) Till Mossakowski, Uni Bremen 2002-2007
License : GPLv2 or higher, see LICENSE.txt
Maintainer : raider@informatik.uni-bremen.de
Stability : provisional
Portability : non-portable (relies on Logic via DevGraph)
Interface for graph viewing and abstraction.
It is possible to hide sets of nodes and edges.
Using a composition table for edge types,
paths through hidden nodes can be displayed.
Graphs, nodes, and edges are handled via
descriptors (here: integers), while node and
edge types are handled by user-supplied strings.
-}
module GUI.AbstractGraphView
( OurGraph
, initgraphs
, Result(Result)
, makegraph
, makegraphExt
, redisplay
, getGraphid
, Descr
, GraphInfo
, RelationViewSpec(RelViewSpec)
, writeRelViewSpecs
, AbstractionGraph(theGraph, edges,
ontoGraph, nodeMap, nodes, relViewSpecs)
, NodeMapping
, writeNodeMap
, addnode
, addlink
, delnode
, dellink
, EdgeValue
, writeOntoGraph
, showIt
, CompTable
, hidenodes
, changeNodeType
, checkHasHiddenNodes
, hideSetOfNodeTypes
, hideSetOfEdgeTypes
-- * Direct manipulation of uDrawGraph
, layoutImproveAll
, showTemporaryMessage
, deactivateGraphWindow
, activateGraphWindow
) where
import GUI.UDGUtils
import qualified UDrawGraph.Types as DVT
import ATC.DevGraph()
import Static.DevGraph (DGLinkLab)
import Common.Taxonomy
import Common.Lib.Graph as Tree
import Data.IORef
import Data.List(nub)
import qualified Data.Map as Map
import Data.Graph.Inductive.Graph (LEdge)
import qualified Data.Graph.Inductive.Graph as Graph
import Control.Concurrent
-- | wait for this amount of microseconds to let uDrawGraph redraw
delayTime :: Int
delayTime = 300000
{- methods using fetchGraph return a quadruple containing the
modified graph, a descriptor of the last modification (e.g. a new
node), the descriptor that can be used for the next modification and a
possible error message -}
-- Which graph display tool to be used, perhaps make it more tool independent?
instance Eq (DaVinciNode (String,Int,Int)) where
(==) = eq1
instance Eq (DaVinciArc EdgeValue) where
(==) = eq1
graphtool :: OurGraph
graphtool = daVinciSort
type OurGraph =
Graph DaVinciGraph
DaVinciGraphParms
DaVinciNode
DaVinciNodeType
DaVinciNodeTypeParms
DaVinciArc
DaVinciArcType
DaVinciArcTypeParms
-- Main datastructure for carrying around the graph,
-- both internally (nodes as integers), and at the daVinci level
type CompTable = [(String,String,String)]
data AbstractionGraph = AbstractionGraph
{ theGraph :: OurGraph
, nodeTypes :: [(String,DaVinciNodeType (String,Int,Int))]
, edgeTypes :: [(String,DaVinciArcType EdgeValue)]
, nodes :: Map.Map Int (String, DaVinciNode (String,Int,Int))
, edges :: Map.Map Int (Int, Int, String, DaVinciArc EdgeValue)
{- probably, also the abstracted graph needs to be stored,
and a list of hide/abstract events with the hidden nodes/edges (for
each event), which is used to restore things when showIt is called -}
, edgeComp :: CompTable
, eventTable :: [(Int,Entry)]
, hiddenEdges :: [(Int,(Int, Int, String, DaVinciArc EdgeValue))]
, deletedNodes :: [Int]
, ontoGraph :: Tree.Gr (String,String,OntoObjectType) String
, relViewSpecs :: [RelationViewSpec]
, nodeMap :: NodeMapping
}
type NodeMapping = Map.Map Int Descr
type Descr = Int
type EdgeValue = (String,Int,Maybe (LEdge DGLinkLab))
type GraphInfo = IORef ([(Descr,AbstractionGraph)],Descr)
-- for each graph the descriptor and the graph,
-- plus a global counter for new descriptors
data Result = Result Descr -- graph, node or edge descriptor
(Maybe String) -- a possible error message
data Entry = Entry {newNodes :: [(Descr,(String,
DaVinciNode (String,Int,Int)))],
oldNodes :: [(Descr,(String,String))],
newEdges :: [(Int,(Int,Int,String,DaVinciArc EdgeValue))],
oldEdges :: [(Int,(Int,Int,String,EdgeValue))]
}
data RelationViewSpec = RelViewSpec String Bool Bool
{- creates a new entry of the eventTable and fills it with the data contained
in its parameters -}
createEntry :: [(Descr,(String,DaVinciNode (String,Int,Int)))]
-> [(Descr,(String,String))]
-> [(Descr,(Int,Int,String,DaVinciArc EdgeValue))]
-> [(Descr,(Int,Int,String,EdgeValue))] -> Descr -> (Int,Entry)
createEntry nn on ne oe cnt =
(cnt, Entry {newNodes = nn, oldNodes = on, newEdges = ne, oldEdges = oe})
{- zips two lists by pairing each element of the first with each element of
the second -}
specialzip :: [a] -> [b] -> [(a,b)]
specialzip xs ys = [ (x, y) | x <- xs, y <- ys ]
{- similar to lookup, but also returns the decriptor
should only be used, if lookup will be successful (otherwise an error is
thrown) -}
get :: Descr -> [(Descr, a)] -> (Descr,a)
get d list =
case lookup d list of
Just r -> (d, r)
Nothing -> error $ "get: descriptor unknown: " ++ show d
++ '\n' : show (map fst list)
getFromMap :: Descr -> Map.Map Descr a -> (Descr,a)
getFromMap d list =
case Map.lookup d list of
Just r -> (d, r)
Nothing -> error $ "get: descriptor unknown: " ++ show d
++ '\n' : show (Map.keys list)
remove :: Eq a => a -> [(a, b)] -> [(a, b)]
remove x = filter ((x /=) . fst)
{- lookup a graph descriptor and execute a command on the graph
the delete flag specifies if the graph should be removed from the graph
list afterwards -}
fetchGraph :: Descr -> GraphInfo -> Bool -> ((AbstractionGraph, Descr)
-> IO (AbstractionGraph, Descr, Descr, Maybe String)) -> IO Result
fetchGraph gid gv delete cmd = do
(gs,ev_cnt) <- readIORef gv
case lookup gid gs of
Just g -> do
(g',descr,ev_cnt',err) <- cmd (g,ev_cnt)
let gs'' = if delete then gs' else (gid,g'):gs'
writeIORef gv (gs'',ev_cnt')
return (Result descr err)
where gs' = remove gid gs
Nothing -> return (Result 0 (Just ("Graph id "++show gid++" not found")))
getGraphid :: Descr -> GraphInfo -> IO OurGraph
getGraphid gid gv = do
(gs,_) <- readIORef gv
case lookup gid gs of
Just g -> return $ theGraph g
Nothing -> error "get_graphid: graph does not exist"
-- These are the operations of the interface
initgraphs :: IO GraphInfo
initgraphs = newIORef ([],0)
makegraph :: String -- Title
-> Maybe (IO ()) -- FileOpen Menu
-> Maybe (IO ()) -- FileSave Menu
-> Maybe (IO ()) -- FileSaveAs Menu
-> [GlobalMenu]
-> [(String,DaVinciNodeTypeParms (String,Descr,Descr))]
-> [(String,DaVinciArcTypeParms EdgeValue)] -> CompTable
-> GraphInfo -> IO Result
makegraph title open save saveAs =
makegraphExt title open save saveAs (return True) Nothing
makegraphExt :: String -- Title
-> Maybe (IO ()) -- FileOpen Menu
-> Maybe (IO ()) -- FileSave Menu
-> Maybe (IO ()) -- FileSaveAs Menu
-> IO Bool -- FileClose Menu
-> Maybe (IO ()) -- FileExit Menu
-> [GlobalMenu]
-> [(String,DaVinciNodeTypeParms (String,Descr,Descr))]
-> [(String,DaVinciArcTypeParms EdgeValue)] -> CompTable
-> GraphInfo -> IO Result
makegraphExt title open save saveAs close exit menus nodetypeparams
edgetypeparams comptable gv = do
(gs,ev_cnt) <- readIORef gv
let
graphParms =
foldr ($$) (GraphTitle title $$
OptimiseLayout False $$
AllowClose close $$
FileMenuAct OpenMenuOption open $$
FileMenuAct SaveMenuOption save $$
FileMenuAct SaveAsMenuOption saveAs $$
FileMenuAct ExitMenuOption exit $$
emptyGraphParms)
menus
abstractNodetypeparams =
LocalMenu (
Button "Unhide abstracted nodes"
(\(_, descr, gid) -> do
oldGv <- readIORef gv
(Result _ error') <- showIt gid descr gv
case error' of
Just _ -> do
writeIORef gv oldGv
return ()
Nothing -> do
redisplay gid gv
return ()
)
) $$$
Rhombus $$$
ValueTitle ( \ (name,_,_) -> return name) $$$
emptyNodeTypeParms :: DaVinciNodeTypeParms (String,Int,Int)
(nodetypenames,nodetypeparams1) =
unzip (("ABSTRACT",abstractNodetypeparams):nodetypeparams)
(edgetypenames,edgetypeparams1) = unzip edgetypeparams
ontoGr = Graph.empty
relViewSpecList = []
graph <- newGraph graphtool graphParms
nodetypes <- mapM (newNodeType graph) nodetypeparams1
edgetypes <- mapM (newArcType graph) edgetypeparams1
let g = AbstractionGraph {
theGraph = graph,
nodeTypes = zip nodetypenames nodetypes,
edgeTypes = zip edgetypenames edgetypes,
nodes = Map.empty,
edges = Map.empty, -- [],
edgeComp = comptable,
eventTable = [],
deletedNodes = [],
hiddenEdges = [],
ontoGraph = ontoGr,
relViewSpecs = relViewSpecList,
nodeMap = Map.empty }
writeIORef gv ((ev_cnt,g):gs,ev_cnt+1)
return (Result ev_cnt Nothing)
addnode :: Descr -> String -> String -> GraphInfo -> IO Result
addnode gid nodetype name gv =
fetchGraph gid gv False (\ (g, ev_cnt) ->
------------------------------ why query nodetype first
case lookup nodetype (nodeTypes g) of
Nothing ->
return (g,0,ev_cnt,Just ("addnode: illegal node type: "++nodetype))
Just nt -> do
node <- newNode (theGraph g) nt (name,ev_cnt,gid)
return (g{nodes = Map.insert ev_cnt (nodetype,node) $ nodes g},
ev_cnt,ev_cnt+1,Nothing)
)
{- | change the node type of the given node in the given graph.
it firstly checks if the node exists in the graph and if
the given node type is valid, then does the setting.
-}
changeNodeType :: Descr -- ^ the graph id
-> Descr -- ^ the id of the to be set node
-> String -- ^ the new node type
-> GraphInfo -- ^ the enviroment
-> IO Result
changeNodeType gid node nodetype graph =
fetchGraph gid graph False (\(g, ev_cnt) ->
case Map.lookup node (nodes g) of
Nothing ->
return (g, 0, ev_cnt, Just ("changeNodeType: illegal node: "
++ show node))
Just n ->
case lookup nodetype (nodeTypes g) of
Nothing ->
return (g, 0, ev_cnt,
Just ("changeNodeType: illegal node type: " ++ nodetype))
Just nt -> do
setNodeType (theGraph g) (snd n) nt
let newnodes =
Map.mapWithKey
(\descr v@(_, davinciNode) -> if descr == node
then (nodetype, davinciNode) else v) $ nodes g
return (g{nodes = newnodes}, node, ev_cnt+1, Nothing)
)
writeOntoGraph :: Descr -> Tree.Gr (String,String,OntoObjectType) String
-> GraphInfo -> IO Result
writeOntoGraph gid graph gv =
fetchGraph gid gv False (\(g,ev_cnt) ->
return (g{ontoGraph = graph},0,ev_cnt+1,Nothing)
)
writeRelViewSpecs :: Descr -> [RelationViewSpec] -> GraphInfo -> IO Result
writeRelViewSpecs gid specs gv =
fetchGraph gid gv False (\(g,ev_cnt) ->
return (g{relViewSpecs = specs},0,ev_cnt+1,Nothing)
)
writeNodeMap :: Descr -> NodeMapping -> GraphInfo -> IO Result
writeNodeMap gid nMap gv =
fetchGraph gid gv False (\(g,ev_cnt) ->
return (g{nodeMap = nMap},0,ev_cnt+1,Nothing)
)
delnode :: Descr -> Descr -> GraphInfo -> IO Result
delnode gid node gv =
fetchGraph gid gv False (\(g,ev_cnt) ->
case Map.lookup node (nodes g) of
Just n -> do
deleteNode (theGraph g) (snd n)
return (g{nodes = Map.delete node (nodes g)
,deletedNodes = deletedNodes g},
0,ev_cnt+1,Nothing)
Nothing ->
return (g,0,ev_cnt,Just ("delnode: illegal node: "++show node))
)
addlink :: Descr -> String -> String -> Maybe (LEdge DGLinkLab) -> Descr
-> Descr -> GraphInfo -> IO Result
addlink gid edgetype name label src tar gv =
fetchGraph gid gv False (\(g,ev_cnt) ->
case (lookup edgetype (edgeTypes g),
Map.lookup src (nodes g),
Map.lookup tar (nodes g)) of
(Just et, Just src_node, Just tar_node) -> do
existingEdgesOfSameTypeAndPosition <-
sequence [getArcValue (theGraph g) davinciArc
|(srcId, tgtId, tp, davinciArc) <- Map.elems (edges g),
tp == edgetype && srcId == src && tgtId == tar]
case lookup name [(nm,descr)|(nm,descr,_) <-
existingEdgesOfSameTypeAndPosition] of
_ -> do
edge <- newArc (theGraph g) et (name,ev_cnt,label) (snd src_node)
(snd tar_node)
return (g{edges = Map.insert ev_cnt (src,tar,edgetype,edge)
$ edges g},
ev_cnt,ev_cnt+1,Nothing)
(Nothing,_,_) ->
return (g,0,ev_cnt,Just ("addlink: illegal edge type: "++edgetype))
(_,Nothing,_) ->
return (g,0,ev_cnt,
Just ("addlink: illegal source node id: "++show src))
(_,_,Nothing) ->
return (g,0,ev_cnt,
Just ("addlink: illegal target node id: "++show tar))
)
dellink :: Descr -> Descr -> GraphInfo -> IO Result
dellink gid edge gv =
fetchGraph gid gv False (\(g,ev_cnt) ->
case Map.lookup edge (edges g) of
Just (_,_,_,e) -> do
deleteArc (theGraph g) e
return (g{edges = Map.delete edge (edges g)},0,ev_cnt+1,Nothing)
Nothing ->
return (g,0,ev_cnt,Just ("dellink: illegal edge: "++show edge))
)
redisplay :: Descr -> GraphInfo -> IO Result
redisplay gid gv =
fetchGraph gid gv False (\(g,ev_cnt) -> do
redraw (theGraph g)
threadDelay delayTime
return (g,0,ev_cnt+1,Nothing)
)
{- determines from the types of two edges the type of the path replacing them
(using the edgeComp table of the graph) -}
determineedgetype :: AbstractionGraph -> (String,String) -> Maybe String
determineedgetype g (t1,t2) =
case [ t | (tp1, tp2, t) <- edgeComp g, tp1 == t1 && tp2 == t2 ] of
[] -> Nothing
x : _ -> Just x
{- returns a pair of lists: one list of all in- and one of all out-going edges
of the node -}
fetchEdgesOfNode :: AbstractionGraph -> Descr -> Maybe ([Descr],[Descr])
fetchEdgesOfNode g node =
-- ? this checking seems meaningless...
-- case sequence (map ((flip Map.lookup) (edges g)) (Map.keys $ edges g)) of
-- Just _ ->
Just ([descr|(descr,(_,t,_,_)) <- Map.toList $ edges g, t == node],
[descr|(descr,(s,_,_,_)) <- Map.toList $ edges g, s == node])
--Nothing -> Nothing
hideSetOfNodeTypes :: Descr -> [String] -> Bool -> GraphInfo -> IO Result
hideSetOfNodeTypes gid nodetypes showLast gv =
fetchGraph gid gv False (\ (g, ev_cnt) ->
case mapM (flip lookup (nodeTypes g)) nodetypes of
Just _ -> do
let nodelist = [descr | (descr, (tp, _)) <- Map.toList (nodes g),
elem tp nodetypes && (not showLast || any
(\ (descr', _, _, _) -> descr' == descr)
(Map.elems $ edges g))]
case nodelist of
[] ->
return (g,0,ev_cnt,Nothing)
_ -> do
(Result de error') <- hidenodes gid nodelist gv
info <- readIORef gv
return (snd (get gid (fst info)), de, (snd info), error')
Nothing ->
return (g,0,ev_cnt,Just ("hidenodetype: illegal node types "
++ "in list: " ++ showList nodetypes ","))
)
hidenodes :: Descr -> [Descr] -> GraphInfo -> IO Result
hidenodes gid node_list gv =
fetchGraph gid gv False (\ (g, ev_cnt) ->
case mapM (flip Map.lookup (nodes g)) node_list of
Just _ ->
-- try to determine the path to add and the edges to remove
case makepathsMain g node_list of
-- try to create the paths
Just (newEdges',delEdges) -> do
-- save the old edges...
let
oeDescr = nub $ concatMap fst delEdges ++ concatMap snd delEdges
oe = map (flip getFromMap (edges g)) oeDescr
oldEdges' <- saveOldEdges g oe
-- ... then try to remove them from the graph
(gs,_) <- readIORef gv
writeIORef gv (gs,ev_cnt+1)
(Result _ error1) <- hideedgesaux gid oeDescr gv
info1 <- readIORef gv
case error1 of
Nothing -> do
-- determine the _new_ edges...
let
existingEdges =
[(src,tgt,tp)|(src,tgt,tp,_) <-
Map.elems $ edges (snd (get gid (fst info1)))]
filteredNewEdges =
[path| path@(src,tgt,tp) <- newEdges',
notElem (src,tgt,tp) existingEdges]
-- ... and try to add them
(Result _ error2) <-
addpaths gid filteredNewEdges gv --info1
case error2 of
Nothing -> do
-- save the old nodes...
let on = map (flip getFromMap (nodes g)) node_list
oldNodes' <- saveOldNodes g on
-- ... then try to remove them from the graph
(Result _ error3) <-
hidenodesaux gid node_list gv --info2
info3 <- readIORef gv
case error3 of
Nothing -> do
-- save the changes in an entry
let
g' = snd (get gid (fst info3))
newEdges'' = [edge| edge <- Map.toList (edges g'),
Map.notMember (fst edge) (edges g)]
newEvent = createEntry [] oldNodes' newEdges''
oldEdges' ev_cnt
return (g'{eventTable = newEvent : eventTable g'}
, ev_cnt, snd info3 + 1, Nothing)
Just t ->
return (g,0,ev_cnt,
Just ("hidenodes: error hiding nodes: "++t))
Just text ->
return (g,0,ev_cnt,
Just ("hidenodes: error adding paths: "++text))
Just text ->
return (g,0,ev_cnt,
Just ("hidenodes: error deleting edges: "++text))
Nothing ->
return (g,0,ev_cnt,
Just ("hidenodes: error making paths\n(possible reasons: "
++"an error occured getting the edges of the nodes\n "
++"or a pathtype could not be determined (missing "
++"entry in edgeComp table))"))
Nothing -> return (g,0,ev_cnt,Just "hidenodes: unknown node(s)")
)
-- auxiliary function, which removes the nodes from the graph
hidenodesaux :: Descr -> [Descr] -> GraphInfo -> IO Result
hidenodesaux _ [] gv = do
(_,ev_cnt) <- readIORef gv
return (Result ev_cnt Nothing)
hidenodesaux gid (d:delNodes) gv = do
deletedNode@(Result _ error') <- delnode gid d gv
case error' of
Nothing -> hidenodesaux gid delNodes gv
Just _ -> return deletedNode
-- returns the paths to add and the edges to remove
makepathsMain :: AbstractionGraph -> [Descr]
-> Maybe ([(Descr,Descr,String)],[([Descr],[Descr])])
makepathsMain g node_list =
-- try to determine the in- and outgoing edges of the nodes
case mapM (fetchEdgesOfNode g) node_list of
-- try to make paths of these edges
Just edgelistPairs ->
case mapM (makepaths g node_list) edgelistPairs of
-- the paths to add (dangling ones are removed) and the edges to remove
Just paths ->
Just (removeDanglingEdges (nub (concat paths)) node_list,
edgelistPairs)
Nothing -> Nothing
Nothing -> Nothing
-- removes those edges whose source or target node will be hidden
removeDanglingEdges :: [(Descr,Descr,String)] -> [Descr]
-> [(Descr,Descr,String)]
removeDanglingEdges edges' nodes' =
[edge| edge@(src,tgt,_) <- edges', notElem src nodes' && notElem tgt nodes']
-- returns a list of paths (ie source, target and type) to be added
makepaths :: AbstractionGraph -> [Descr] -> ([Descr],[Descr])
-> Maybe [(Descr,Descr,String)]
makepaths g node_list (inEdges,outEdges) =
-- try to lookup the edges of the node
case (mapM (flip Map.lookup (edges g)) inEdges,
mapM (flip Map.lookup (edges g)) outEdges) of
(Just ie, Just oe) ->
-- try to make paths out of them
case mapM (makepathsaux g node_list []) (specialzip ie oe) of
-- return the paths
Just paths -> Just (concat paths)
Nothing -> Nothing
(Nothing,_) -> Nothing
(_,Nothing) -> Nothing
{- determines source, target and type of the path to be added and checks it
using method checkpath -}
makepathsaux :: AbstractionGraph -> [Descr] -> [Descr]
-> ((Descr,Descr,String,DaVinciArc EdgeValue),
(Descr,Descr,String,DaVinciArc EdgeValue))
-> Maybe [(Descr,Descr,String)]
makepathsaux g node_list alreadyPassedNodes ((s1,_,ty1,ed1),(_,t2,ty2,_)) =
-- try to determine the type of the path
case determineedgetype g (ty1,ty2) of
-- return the checked path
Just ty -> checkpath g node_list alreadyPassedNodes (s1,t2,ty,ed1)
-- ed1 is just a dummy value (Dummiewert)
Nothing -> Nothing
{- check, if the source or the target of an edge are element of the list of
nodes that are to be hidden
if so, find out the "next" sources/targets and check again
remember which nodes have been passed to avoid infinite loops -}
checkpath :: AbstractionGraph -> [Descr] -> [Descr]
-> (Descr,Descr,String,DaVinciArc EdgeValue)
-> Maybe [(Descr,Descr,String)]
checkpath g node_list alreadyPassedNodes path@(src,tgt,ty,_)
| elem src alreadyPassedNodes || elem tgt alreadyPassedNodes = Just []
| elem src node_list =
-- try to determine the in- and outgoing edges of the source node
case fetchEdgesOfNode g src of
-- try to lookup ingoing edges
Just (inEdges,_) ->
case mapM (flip Map.lookup (edges g)) inEdges of
{- try to make paths of these edges and the "tail" of the path (and
recursively check them) -}
Just el ->
case mapM (makepathsaux g node_list (src : alreadyPassedNodes))
(specialzip el [path]) of
Just p -> Just (concat p)
Nothing -> Nothing
Nothing -> Nothing
Nothing -> Nothing
| elem tgt node_list =
-- try to determine the in- and outgoing edges of the target node
case fetchEdgesOfNode g tgt of
-- try to lookup the outgoing edges
Just (_,outEdges) ->
case mapM (flip Map.lookup (edges g)) outEdges of
{- try to make paths of these edges and the "init" of the path (and
recursively check them) -}
Just el ->
case mapM (makepathsaux g node_list
(tgt : alreadyPassedNodes))
(specialzip [path] el) of
Just p -> Just (concat p)
Nothing -> Nothing
Nothing -> Nothing
Nothing -> Nothing
| otherwise =
-- nothing to be done
Just [(src,tgt,ty)]
-- adds the paths (given source, target and type)
addpaths :: Descr -> [(Descr,Descr,String)] -> GraphInfo -> IO Result
addpaths _ [] gv = do
(_,ev_cnt) <- readIORef gv
return (Result ev_cnt Nothing)
addpaths gid ((src,tgt,ty):newEdges') gv = do
edge@(Result _ error') <- addlink gid ty "" Nothing src tgt gv
case error' of
Nothing -> addpaths gid newEdges' gv
Just _ -> return edge
hideSetOfEdgeTypes :: Descr -> [String] -> GraphInfo -> IO Result
hideSetOfEdgeTypes gid edgetypes gv =
fetchGraph gid gv False (\(g,ev_cnt) ->
case sequence [lookup edgetype (edgeTypes g)|edgetype <- edgetypes] of
Just _ -> do
let edgelist = [descr| (descr, (_ ,_ , tp, _)) <- Map.toList (edges g),
elem tp edgetypes]
showlist = filter (\ (_, (_, _, tp, _)) -> notElem tp edgetypes)
$ hiddenEdges g
case edgelist of
[] -> return (g, 0, ev_cnt, Nothing)
_ -> do
(Result de err) <- hideedges gid edgelist gv
case err of
Nothing -> do
info <- readIORef gv
let gs = (snd $ get de $ fst info)
gs' = gs{hiddenEdges = filter (flip notElem showlist)
$ hiddenEdges gs}
sl' <- saveOldEdges gs showlist
writeIORef gv ((de + 1, gs') : fst info, de + 1)
(Result de' err') <- showedges (de + 1) sl' gv
case err' of
Nothing -> do
info' <- readIORef gv
return (snd $ get de' $ fst info', de', snd info', Nothing)
Just _ -> return (g, 0, ev_cnt, err')
Just _ -> return (g, 0, ev_cnt, err)
Nothing ->
return (g, 0, ev_cnt, Just ("hideedgestype: illegal edge types "
++ "in list: " ++ showList edgetypes ","))
)
hideedges :: Descr -> [Descr] -> GraphInfo -> IO Result
hideedges gid edge_list gv =
fetchGraph gid gv False (\(g,ev_cnt) ->
case mapM (\ e -> case Map.lookup e (edges g) of
Just x -> Just (e,x)
Nothing -> Nothing) edge_list of
Just edges' -> do
Result de err <- hideedgesaux gid edge_list gv
case err of
Nothing -> do
info <- readIORef gv
return ((snd $ get gid $ fst info){hiddenEdges = hiddenEdges g
++ edges'},
de, snd info + 1, Nothing)
Just _ -> return (g,0,ev_cnt,Just "hideedges: error deleting edges")
Nothing -> return (g,0,ev_cnt,Just "hideedges: unknown edge(s)")
)
-- an auxiliary function, which removes the edges from the graph
hideedgesaux :: Descr -> [Descr] -> GraphInfo -> IO Result
hideedgesaux _ [] gv = do
(_,ev_cnt) <- readIORef gv
return (Result ev_cnt Nothing)
hideedgesaux gid (d:delEdges) gv = do
dle@(Result _ error') <- dellink gid d gv
case error' of
Nothing -> hideedgesaux gid delEdges gv --info
Just _ -> return dle
-- | function to check whether the internal nodes are hidden or not
checkHasHiddenNodes :: Descr -> Descr -> GraphInfo -> IO Result
checkHasHiddenNodes gid hide_event gv =
fetchGraph gid gv False (\(g, ev_cnt) ->
case lookup hide_event (eventTable g) of
Just _ -> return (g, 0, ev_cnt, Nothing)
Nothing -> return (g, 0, ev_cnt,
Just "checkHasHiddenNodes: hide events not found")
)
-- function to undo hide-events
showIt :: Descr -> Descr -> GraphInfo -> IO Result
showIt gid hide_event gv =
fetchGraph gid gv False (\(g,ev_cnt) ->
-- try to lookup the hide-event
case lookup hide_event (eventTable g) of
Just entry -> do
-- try to remove the paths that had been added
(Result _ error1) <- hideedgesaux gid (map fst (newEdges entry)) gv
case error1 of
Nothing -> do
-- try to add the nodes that had been hidden
(Result _ error2) <- shownodes gid (oldNodes entry) gv
case error2 of
Nothing -> do
-- try to remove the nodes that had been added
(Result _ error3) <- hidenodesaux gid
(map fst (newNodes entry)) gv
case error3 of
Nothing -> do
-- try to add the edges that had been hidden
(Result _ error4) <- showedges gid (oldEdges entry) gv
info4 <- readIORef gv
case error4 of
Nothing -> do
-- remove the event from the eventTable
let g' = snd (get gid (fst info4))
return (g'{eventTable = remove hide_event
(eventTable g')},0,ev_cnt+1,Nothing)
Just t4 ->
return (g,0,ev_cnt,Just ("showIt: error restoring old "
++"edges:\n-> "++t4))
Just t3 ->
return (g,0,ev_cnt,
Just ("showIt: error removing nodes:\n-> "++t3))
Just t2 ->
return (g,0,ev_cnt,Just ("showIt: error restoring nodes:\n-> "
++t2))
Just t1 ->
return (g,0,ev_cnt,Just ("showIt: error removing edges:\n-> "++t1))
Nothing ->
return (g,0,ev_cnt,Just ("showIt: invalid event descriptor: "
++ show hide_event))
)
-- adds nodes that had been hidden
shownodes :: Descr -> [(Descr,(String,String))] -> GraphInfo -> IO Result
shownodes _ [] gv = do
(_,ev_cnt) <- readIORef gv
return (Result ev_cnt Nothing)
shownodes gid ((d,(tp,name)):list) gv = do
(gs,_) <- readIORef gv
-- try to add the first node
writeIORef gv (gs,d)
nd@(Result _ error') <- addnode gid tp name gv
case error' of
Nothing -> -- try to add the rest
shownodes gid list gv
Just _ -> return nd
-- adds edges that had been hidden
showedges :: Descr -> [(Int,(Int,Int,String,EdgeValue))] -> GraphInfo
-> IO Result
showedges _ [] gv = do
(_,ev_cnt) <- readIORef gv
return (Result ev_cnt Nothing)
showedges gid ((d,(src,tgt,tp,value)):list) gv = do
(gs,_) <- readIORef gv
-- try to add the first edge
writeIORef gv (gs,d)
let
name = getEdgeName value
label = getEdgeLabel value
ed@(Result _ err) <- addlink gid tp name label src tgt gv
case err of
Nothing -> -- try to add the rest
showedges gid list gv
Just _ -> return ed
{- | creates a list of the nodes that will be hidden (ie descriptor,type and
name) -}
saveOldNodes :: AbstractionGraph
-> [(Int,(String,DaVinciNode(String,Int,Int)))]
-> IO [(Int,(String,String))]
saveOldNodes _ [] = return []
saveOldNodes g ((de,(tp,davincinode)):list) = do
(name,_,_) <- getNodeValue (theGraph g) davincinode
restOfList <- saveOldNodes g list
return ((de,(tp,name)):restOfList)
{- | creates a list of the edges that will be hidden (ie descriptor,source,
target,type and name) -}
saveOldEdges :: AbstractionGraph
-> [(Int,(Int,Int,String,DaVinciArc EdgeValue))]
-> IO [(Int,(Int,Int,String,EdgeValue))]
saveOldEdges _ [] = return []
saveOldEdges g ((de,(src,tgt,tp,davinciarc)):list) = do
value <- getArcValue (theGraph g) davinciarc
restOfList <- saveOldEdges g list
return ((de,(src,tgt,tp,value)):restOfList)
getEdgeName :: EdgeValue -> String
getEdgeName (name,_,_) = name
getEdgeLabel :: EdgeValue -> Maybe (LEdge DGLinkLab)
getEdgeLabel (_,_,label) = label
-- | improve the layout of a graph like calling \"Layout->Improve All\"
layoutImproveAll :: Descr -> GraphInfo -> IO Result
layoutImproveAll gid gv =
fetchGraph gid gv False (\(g,ev_cnt) -> do
let contxt = case theGraph g of
Graph dg -> getDaVinciGraphContext dg
doInContext (DVT.Menu $ DVT.Layout DVT.ImproveAll) contxt
return (g,0,ev_cnt+1,Nothing))
-- | display a message in a uDrawGraph window controlled by AbstractGraphView
showTemporaryMessage :: Descr -> GraphInfo
-> String -- ^ message to be displayed
-> IO Result
showTemporaryMessage gid gv message =
fetchGraph gid gv False (\(g,ev_cnt) -> do
let contxt = case theGraph g of
Graph dg -> getDaVinciGraphContext dg
doInContext (DVT.Window $ DVT.ShowMessage message) contxt
return (g,0,ev_cnt+1,Nothing))
-- | deactivate the input of all uDrawGraph windows;
--
-- Warning: every deactivate event must be paired an activate event
deactivateGraphWindow :: Descr -> GraphInfo -> IO Result
deactivateGraphWindow gid gv =
fetchGraph gid gv False (\(g,ev_cnt) -> do
let contxt = case theGraph g of
Graph dg -> getDaVinciGraphContext dg
doInContext (DVT.Window DVT.Deactivate) contxt
return (g,0,ev_cnt+1,Nothing))
-- | activate the input of a uDrawGraph display
activateGraphWindow :: Descr -> GraphInfo -> IO Result
activateGraphWindow gid gv =
fetchGraph gid gv False (\(g,ev_cnt) -> do
let contxt = case theGraph g of
Graph dg -> getDaVinciGraphContext dg
doInContext (DVT.Window DVT.Activate) contxt
return (g,0,ev_cnt+1,Nothing))