PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/GeneralPDP/Scenario/ScenarioViewer.fs

#
F# | 672 lines | 532 code | 69 blank | 71 comment | 52 complexity | 7436d147083b6d6da0bdf4b463806818 MD5 | raw file
Possible License(s): Apache-2.0, GPL-3.0, LGPL-3.0, BSD-3-Clause
  1. namespace Microsoft.Research.GeneralPDP.Scenario
  2. open Basics
  3. open Message
  4. open BasicEndPoint
  5. open EnforcementEndPoint
  6. open PolicyRepositoryEndPoint
  7. open XacmlEndPoint
  8. open DkalEndPoint
  9. open XacmlToDkalEndPoint
  10. open DkalToXacmlEndPoint
  11. open Microsoft.Research.DkalEngine.Ast
  12. open Microsoft.Research.DkalEngine.Util
  13. open Microsoft.Research.GeneralPDP.Utils.GUI
  14. open Microsoft.Research.GeneralPDP.XACML.Parsing
  15. open Microsoft.Research.GeneralPDP.DKAL.Engine.ParsingCtxFactory
  16. open Microsoft.Msagl.Drawing
  17. open Microsoft.Msagl.GraphViewerGdi
  18. open System
  19. open System.Drawing
  20. open System.Threading
  21. open System.IO
  22. open System.Collections.Generic
  23. open System.Windows.Forms
  24. module ScenarioViewer =
  25. type VoidDelegate = delegate of unit -> unit
  26. type ScenarioViewer() =
  27. // GUI elements
  28. let form: Form = new Form()
  29. let graphViewer: GViewer = new GViewer()
  30. let rstButton: Button = new Button()
  31. let bckButton: Button = new Button()
  32. let fwdButton: Button = new Button()
  33. let nowButton: Button = new Button()
  34. let stepLabel: System.Windows.Forms.Label = new System.Windows.Forms.Label()
  35. let statusLabel: ToolStripLabel = new ToolStripLabel()
  36. let msgHeaderLabel: Label = new Label()
  37. let descrLabel: TextBox = new TextBox()
  38. let contextMenu = new ContextMenu()
  39. // font for graph labels
  40. let graphFont = descrLabel.Font
  41. // graph and geometry graph
  42. let mutable graph: Graph = null
  43. let mutable geomGraph: Microsoft.Msagl.GeometryGraph = null
  44. // reference to scenario being displayed
  45. let mutable scenario: IScenario option = None
  46. // reference to object under mouse
  47. let mutable underMouse: IViewerObject = null
  48. // application thread that holds the window while active
  49. let mutable appThread: Thread option = None
  50. // edges in order to keep track of graph state over time
  51. let edges: ResizeArray<Edge> = ResizeArray<_>()
  52. let mutable highlightedEdge: Edge option = None
  53. let mutable currIndex = -1
  54. // nodes to keep track of extra attributes (such as label)
  55. let nodes: Dictionary<EndPointId, IEndPoint> = new Dictionary<_,_>()
  56. // Draw images in nodes
  57. (*let getNodeBoundary (image: Image) (node: Microsoft.Msagl.Drawing.Node) =
  58. let textSize = TextRenderer.MeasureText(node.LabelText, graphFont)
  59. let width = (float) (Math.Max(image.Width, textSize.Width + 25))
  60. let height = (float) (image.Height + textSize.Height)
  61. Microsoft.Msagl.Splines.CurveFactory.CreateBox(width, height, new Microsoft.Msagl.Point())*)
  62. let addSegmentToPath (seg: Microsoft.Msagl.Splines.ICurve) (p: System.Drawing.Drawing2D.GraphicsPath ref) =
  63. let pointF (p: Microsoft.Msagl.Point) =
  64. new PointF((float32) p.X, (float32) p.Y)
  65. let radiansToDegrees = (180.0 / Math.PI)
  66. if seg <> null then
  67. match seg with
  68. | :? Microsoft.Msagl.Splines.LineSegment as line ->
  69. p.Value.AddLine(pointF(line.Start), pointF(line.End))
  70. | :? Microsoft.Msagl.Splines.CubicBezierSegment as cb ->
  71. p.Value.AddBezier(pointF(cb.B(0)), pointF(cb.B(1)), pointF(cb.B(2)), pointF(cb.B(3)))
  72. | :? Microsoft.Msagl.Splines.Ellipse as ellipse ->
  73. p.Value.AddArc((float32)(ellipse.Center.X - ellipse.AxisA.Length), (float32)(ellipse.Center.Y - ellipse.AxisB.Length),
  74. (float32)(2.0 * ellipse.AxisA.Length), (float32)(2.0 * ellipse.AxisB.Length), (float32)(ellipse.ParStart * radiansToDegrees),
  75. (float32)((ellipse.ParEnd - ellipse.ParStart) * radiansToDegrees))
  76. | _ -> ()
  77. let fillTheGraphicsPath (iCurve: Microsoft.Msagl.Splines.ICurve) =
  78. match iCurve with
  79. | :? Microsoft.Msagl.Splines.Curve as curve ->
  80. let path = new System.Drawing.Drawing2D.GraphicsPath()
  81. for seg in curve.Segments do
  82. addSegmentToPath seg (ref path)
  83. path
  84. | _ -> failwith "Expecting curve"
  85. let drawNode (image: Image) (node: Microsoft.Msagl.Drawing.Node) (graphics: obj) =
  86. match graphics with
  87. | :? Graphics as g ->
  88. // flip the image around its center
  89. use m = g.Transform
  90. use saveM = m.Clone()
  91. use m2 = new System.Drawing.Drawing2D.Matrix(1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 2.0F * (float32) node.Attr.GeometryNode.Center.Y)
  92. m.Multiply(m2)
  93. g.Transform <- m
  94. let path: Drawing2D.GraphicsPath = fillTheGraphicsPath(node.Attr.GeometryNode.BoundaryCurve)
  95. g.SetClip(path)
  96. let slackWidth = node.Attr.GeometryNode.Width - (float) image.Width
  97. let topLeft = new PointF((float32) (slackWidth / (float) 2.0 + node.Attr.GeometryNode.Center.X - node.Attr.GeometryNode.Width / (float) 2.0),
  98. (float32) (node.Attr.GeometryNode.Center.Y - node.Attr.GeometryNode.Height / (float) 2.0))
  99. g.DrawImage(image, topLeft)
  100. let stringSize = g.MeasureString(node.LabelText, statusLabel.Font)
  101. let stringSlackWidth = node.Attr.GeometryNode.Width - (float) stringSize.Width
  102. let labelTopLeft = new PointF((float32) (stringSlackWidth / (float) 2.0 + node.Attr.GeometryNode.Center.X - node.Attr.GeometryNode.Width / (float) 2.0),
  103. (float32) (node.Attr.GeometryNode.Center.Y + node.Attr.GeometryNode.Height / (float) 2.0) - 16.0F)
  104. let labelRect = new RectangleF(labelTopLeft, new SizeF((float32) node.Attr.GeometryNode.Width, (float32) node.Attr.GeometryNode.Height))
  105. g.DrawString(node.LabelText, statusLabel.Font, new SolidBrush(Color.Black), labelRect)
  106. g.Transform <- saveM
  107. true // returning false would enable the default rendering
  108. | _ -> failwith "Expecting graphics"
  109. let applyNodeAttributes(ep: IEndPoint, graphNode: Node) =
  110. match graphNode with
  111. | null -> ()
  112. | graphNode ->
  113. ep.ApplyStyle graphNode
  114. match ep.Image with
  115. | None -> ()
  116. | Some img ->
  117. graphNode.Attr.Shape <- Shape.DrawFromGeometry
  118. graphNode.DrawNodeDelegate <- new DelegateToOverrideNodeRendering(drawNode img)
  119. //graphNode.NodeBoundaryDelegate <- new DelegateToSetNodeBoundary(getNodeBoundary img)
  120. let reDraw() =
  121. // save previouse zoom value in order to restore it
  122. let oldZoom = graphViewer.ZoomF
  123. // recreate geometry elements
  124. geomGraph <- new Microsoft.Msagl.GeometryGraph()
  125. let height = Resources.Main.ep_1.Height
  126. let width = Resources.Main.ep_1.Width
  127. geomGraph.LayerSeparation <- (float) (height / 4)
  128. geomGraph.NodeSeparation <- (float) (width / 4)
  129. // first nodes
  130. for node in graph.NodeMap.Values do
  131. match node with
  132. | :? Node as node ->
  133. let ep = nodes.[node.Id]
  134. match ep.Image with
  135. | Some image ->
  136. let textSize = TextRenderer.MeasureText(node.LabelText, graphFont)
  137. let width = (float) (Math.Max(image.Width, textSize.Width + 25))
  138. let height = (float) (image.Height + textSize.Height)
  139. let geomNode = new Microsoft.Msagl.Node(node.Id, Microsoft.Msagl.Splines.CurveFactory.CreateBox(width, height, new Microsoft.Msagl.Point()))
  140. geomGraph.AddNode(geomNode)
  141. | None -> failwith "expecting image on every node"
  142. | _ -> failwith "expecting drawing node"
  143. // then edges (and their labels)
  144. let mutable geomEdges = []
  145. for edge in edges do
  146. let geomEdge = new Microsoft.Msagl.Edge(geomGraph.FindNode(edge.Source), geomGraph.FindNode(edge.Target))
  147. geomEdge.ArrowheadLength <- (float) width / 10.0
  148. geomEdge.Label <- edge.Label.GeometryLabel
  149. let font = new Font(edge.Label.FontName, (float32) edge.Label.FontSize)
  150. let w, h = ref 0.0, ref 0.0
  151. StringMeasure.MeasureWithFont(edge.Label.Text, font, w, h)
  152. geomEdge.Label.Width <- w.Value
  153. geomEdge.Label.Height <- h.Value
  154. geomEdges <- geomEdges @ [geomEdge]
  155. geomGraph.AddEdge(geomEdge)
  156. // then calculate layout
  157. geomGraph.CalculateLayout()
  158. // bind geometry elements to drawing elements
  159. for drawingNode in graph.NodeMap.Values do
  160. match drawingNode with
  161. | :? Node as drawingNode -> drawingNode.Attr.GeometryNode <- geomGraph.FindNode(drawingNode.Id)
  162. | _ -> failwith "expecting drawing node"
  163. for index in [0 .. edges.Count-1] do
  164. edges.[index].Attr.GeometryEdge <- geomEdges.[index]
  165. graph.GeometryGraph <- geomGraph
  166. graphViewer.NeedToCalculateLayout <- false
  167. graphViewer.Graph <- graph
  168. graphViewer.ZoomF <- oldZoom
  169. let updateControls() =
  170. if currIndex >= 0 then
  171. rstButton.Enabled <- true
  172. bckButton.Enabled <- true
  173. else
  174. rstButton.Enabled <- false
  175. bckButton.Enabled <- false
  176. if currIndex + 1 < edges.Count then
  177. nowButton.Enabled <- true
  178. fwdButton.Enabled <- true
  179. else
  180. nowButton.Enabled <- false
  181. fwdButton.Enabled <- false
  182. stepLabel.Text <- "Step " + (currIndex + 1).ToString() + " of " + edges.Count.ToString()
  183. let updateStatus() =
  184. let rec printStatusFrom (obj: IViewerObject) =
  185. match obj with
  186. | :? DLabel as l -> printStatusFrom l.Parent
  187. | :? DEdge as d ->
  188. let e = d.Edge
  189. if edges.Contains e && edges.IndexOf e <= currIndex then
  190. statusLabel.Text <- e.Source + " --> " + e.Target + ": " + e.LabelText
  191. | :? DNode as n ->
  192. statusLabel.Text <- n.Node.LabelText
  193. | null
  194. | _ ->
  195. statusLabel.Text <- ""
  196. printStatusFrom underMouse
  197. let updateMessageLabels (i: int) (m: obj) =
  198. match m with
  199. | :? IMessage as m ->
  200. descrLabel.Text <- m.Content.ToString()
  201. msgHeaderLabel.Text <- "Message " + (i+1).ToString() + ": " + m.Sender + " ---> " + m.Receiver
  202. | _ -> ()
  203. let updateDescription() =
  204. let rec printDescrFrom (obj: IViewerObject) =
  205. match obj with
  206. | :? DLabel as l -> printDescrFrom l.Parent
  207. | :? DEdge as d ->
  208. let e = d.Edge
  209. if edges.Contains e && edges.IndexOf e <= currIndex then
  210. updateMessageLabels (edges.IndexOf e) e.UserData
  211. | null -> ()
  212. | _ -> ()
  213. printDescrFrom underMouse
  214. let pickReceiver () =
  215. pickFromOptions "Sending message..." "Select the destination:" (Seq.map (fun (n: KeyValuePair<_,_>) -> n.Key) (nodes))
  216. (*let handleLoadEndPoint () =
  217. try
  218. let id = textInput "Loading a new endpoint..." "Choose an ID for the new endpoint:"
  219. match id with
  220. | Some id ->
  221. let kind = pickFromOptions "Loading a new endpoint..." "Select the endpoint kind:" ["Basic"; "Enforcement"; "PolicyRepository"; "XACML"; "DKAL"; "XACML->DKAL"; "DKAL->XACML" ]
  222. let ep: IEndPoint option = match kind with
  223. | Some "Basic" -> Some (BasicEndPoint id :> IEndPoint)
  224. | Some "Enforcement" -> Some (EnforcementEndPoint id :> IEndPoint)
  225. | Some "PolicyRepository" -> Some (PolicyRepositoryEndPoint(id, [], []) :> IEndPoint)
  226. | Some "XACML" ->
  227. match pickFromOptions "Loading a new endpoint..." "Select the attribute repository:"
  228. (["<None>"] @ (List.map (fun (n: KeyValuePair<_,_>) -> n.Key) (nodes |> Seq.toList))) with
  229. | None -> None
  230. | Some "<None>" -> Some (XacmlEndPoint id :> IEndPoint)
  231. | Some attRepId -> Some (XacmlEndPoint(id, attRepId) :> IEndPoint)
  232. | Some "DKAL" ->
  233. let openFileDialog = new OpenFileDialog()
  234. openFileDialog.AutoUpgradeEnabled <- false
  235. openFileDialog.InitialDirectory <- "C:\\Users\\t-guide\\Desktop\\fse\\main\\DKAL\\GeneralPDP\\Samples" // TODO: change for Application.StartupPath
  236. openFileDialog.Filter <- "DKAL policy (*.dkal)|*.dkal|" +
  237. "All files (*.*)|*.*"
  238. openFileDialog.FilterIndex <- 0
  239. if openFileDialog.ShowDialog() = DialogResult.OK then
  240. let pctx, assertions = xacmlAwareParsingCtx(id)
  241. let assertions = assertions @ pctx.ParseFile(openFileDialog.FileName)
  242. Some (DkalEndPoint(id, assertions) :> IEndPoint)
  243. else
  244. None
  245. | Some "XACML->DKAL" ->
  246. let dkalId = pickFromOptions "Loading a new endpoint..." "Select the DKAL backend:" (Seq.map (fun (n: KeyValuePair<_,_>) -> n.Key) (nodes))
  247. match dkalId with
  248. | Some dkalId ->
  249. let pctx, _ = xacmlAwareParsingCtx id
  250. Some (XacmlToDkalEndPoint(id, dkalId, pctx) :> IEndPoint)
  251. | None -> None
  252. | Some "DKAL->XACML" ->
  253. let xacmlId = pickFromOptions "Loading a new endpoint..." "Select the XACML backend:" (Seq.map (fun (n: KeyValuePair<_,_>) -> n.Key) (nodes))
  254. match xacmlId with
  255. | Some xacmlId ->
  256. let dkalId = pickFromOptions "Loading a new endpoint..." "Select the DKAL backend:" (Seq.map (fun (n: KeyValuePair<_,_>) -> n.Key) (nodes))
  257. match dkalId with
  258. | Some dkalId ->
  259. let openFileDialog = new OpenFileDialog()
  260. openFileDialog.AutoUpgradeEnabled <- false
  261. openFileDialog.InitialDirectory <- "C:\\Users\\t-guide\\Desktop\\fse\\main\\DKAL\\GeneralPDP\\Samples" // TODO: change for Application.StartupPath
  262. openFileDialog.Filter <- "DKAL policy (*.dkal)|*.dkal|" +
  263. "All files (*.*)|*.*"
  264. openFileDialog.FilterIndex <- 0
  265. if openFileDialog.ShowDialog() = DialogResult.OK then
  266. let pctx, assertions = xacmlAwareParsingCtx(id)
  267. let assertions = assertions @ pctx.ParseFile(openFileDialog.FileName)
  268. Some (DkalToXacmlEndPoint(id, xacmlId, dkalId, pctx, assertions) :> IEndPoint)
  269. else
  270. None
  271. | None -> None
  272. | None -> None
  273. | _ -> None
  274. match ep with
  275. | Some ep ->
  276. scenario.Value.AddEndPoint(ep)
  277. ep.Start()
  278. | None -> ()
  279. | None -> ()
  280. with
  281. | SyntaxError(p,s) -> printfn "%O: %O" p s
  282. | e -> printfn "Error while reading file: %O" e*)
  283. let handleSendNewMessage (ep: IEndPoint) =
  284. let openFileDialog = new OpenFileDialog()
  285. openFileDialog.AutoUpgradeEnabled <- false
  286. openFileDialog.InitialDirectory <- "C:\\Users\\t-guide\\Desktop\\fse\\main\\DKAL\\GeneralPDP\\Samples" // TODO: change for Application.StartupPath
  287. openFileDialog.Filter <- "XACML request (*.req)|*.req|" +
  288. "XACML policy (*.pcy)|*.pcy|" +
  289. "XACML response (*.rsp)|*.rsp|" +
  290. "XACML policy request (*.prq)|*.prq|" +
  291. "DKAL infon (*.infon)|*.infon|" +
  292. "All files (*.*)|*.*"
  293. openFileDialog.FilterIndex <- 0
  294. if openFileDialog.ShowDialog() = DialogResult.OK then
  295. try
  296. let ext = Path.GetExtension(openFileDialog.FileName)
  297. let content = match ext with
  298. | ".req" ->
  299. let text = File.ReadAllText(openFileDialog.FileName)
  300. let req = parseRequest(text)
  301. Some (XacmlRequestContent req)
  302. | ".pcy" ->
  303. let text = File.ReadAllText(openFileDialog.FileName)
  304. let pcy = parsePolicy(text)
  305. Some (XacmlPolicyContent pcy)
  306. | ".rsp" ->
  307. let text = File.ReadAllText(openFileDialog.FileName)
  308. let rsp = parseResponse(text)
  309. Some (XacmlResponseContent rsp)
  310. | ".prq" ->
  311. let text = File.ReadAllText(openFileDialog.FileName)
  312. let prq = parsePolicyRequest(text)
  313. Some (XacmlPolicyRequestContent prq)
  314. | ".infon" ->
  315. let text = File.ReadAllText(openFileDialog.FileName)
  316. let pctx, _ = xacmlAwareParsingCtx(ep.Id)
  317. let infon = pctx.ParseInfon text
  318. Some (InfonContent infon)
  319. | _ -> MessageBox.Show("File extension not recognized: " + ext) |> ignore
  320. None
  321. match content with
  322. | None -> ()
  323. | Some c ->
  324. match pickReceiver() with
  325. | None -> ()
  326. | Some r ->
  327. // move simulation to most current state
  328. if nowButton.Enabled then
  329. nowButton.PerformClick()
  330. // do message sending
  331. ep.Send({sender= ep.Id;
  332. receiver= r;
  333. content= c})
  334. with
  335. | SyntaxError(p,s) -> printfn "%O: %O" p s
  336. | e -> printfn "Error while reading file: %O" e
  337. let makeInvisible (e: Edge) =
  338. e.Attr.Color <- graph.Attr.BackgroundColor
  339. e.Label.FontColor <- graph.Attr.BackgroundColor
  340. let makeVisible (e: Edge) =
  341. e.Attr.Color <- Microsoft.Msagl.Drawing.Color.Black
  342. e.Label.FontColor <- Microsoft.Msagl.Drawing.Color.Black
  343. let highlightEdge (edge: Edge option) =
  344. match highlightedEdge with
  345. | None -> ()
  346. | Some e ->
  347. if edges.IndexOf e <= currIndex then
  348. makeVisible e
  349. else
  350. makeInvisible e
  351. match edge with
  352. | None -> ()
  353. | Some e ->
  354. e.Label.FontColor <- Microsoft.Msagl.Drawing.Color.Red
  355. e.Attr.Color <- Microsoft.Msagl.Drawing.Color.Red
  356. highlightedEdge <- edge
  357. reDraw()
  358. let centerGraphOn (e: Edge) =
  359. if graphViewer.ZoomF > 1.5 then
  360. graphViewer.ShowGroup([| e.SourceNode :> DrawingObject; e :> DrawingObject; e.TargetNode :> DrawingObject |])
  361. let doReset _ =
  362. for i in [0..currIndex] do
  363. makeInvisible (edges.[i])
  364. currIndex <- -1
  365. highlightEdge None
  366. descrLabel.Text <- ""
  367. msgHeaderLabel.Text <- ""
  368. statusLabel.Text <- ""
  369. updateControls()
  370. let doBack _ =
  371. makeInvisible (edges.[currIndex])
  372. currIndex <- currIndex - 1
  373. if currIndex >= 0 then
  374. let edge = edges.[currIndex]
  375. highlightEdge (Some edge)
  376. updateMessageLabels currIndex edge.UserData
  377. statusLabel.Text <- edge.Source + " --> " + edge.Target + ": " + edge.LabelText
  378. updateControls()
  379. centerGraphOn edge
  380. else
  381. highlightEdge None
  382. descrLabel.Text <- ""
  383. msgHeaderLabel.Text <- ""
  384. statusLabel.Text <- ""
  385. updateControls()
  386. let doForward _ =
  387. currIndex <- currIndex + 1
  388. let edge = edges.[currIndex]
  389. makeVisible edge
  390. highlightEdge (Some edge)
  391. updateMessageLabels currIndex edge.UserData
  392. statusLabel.Text <- edge.Source + " --> " + edge.Target + ": " + edge.LabelText
  393. updateControls()
  394. centerGraphOn edge
  395. let doNow _ =
  396. for i in [currIndex + 1 .. edges.Count - 1] do
  397. makeVisible edges.[i]
  398. currIndex <- edges.Count - 1
  399. let edge = edges.[currIndex]
  400. highlightEdge (Some edge)
  401. updateMessageLabels currIndex edge.UserData
  402. statusLabel.Text <- edge.Source + " --> " + edge.Target + ": " + edge.LabelText
  403. updateControls()
  404. centerGraphOn edge
  405. let handleJumpToThisMessage (edge: Edge) =
  406. let index = edges.IndexOf edge
  407. for i in [index + 1 .. edges.Count - 1] do
  408. makeVisible edges.[i]
  409. currIndex <- index
  410. highlightEdge (Some edge)
  411. updateMessageLabels currIndex edge.UserData
  412. statusLabel.Text <- edge.Source + " --> " + edge.Target + ": " + edge.LabelText
  413. updateControls()
  414. centerGraphOn edge
  415. let handleGraphClick (args: EventArgs) =
  416. contextMenu.MenuItems.Clear()
  417. match args with
  418. | :? MouseEventArgs as args ->
  419. let rec findElement (obj: IViewerObject) =
  420. match obj with
  421. | :? DNode as n ->
  422. let ep = nodes.[n.DrawingNode.Id]
  423. let headerMI = new MenuItem(ep.Description)
  424. headerMI.Enabled <- false
  425. contextMenu.MenuItems.Add(headerMI) |> ignore
  426. contextMenu.MenuItems.Add("-") |> ignore
  427. let initMessageMI = new MenuItem("Send new message...", new EventHandler(fun _ _ -> handleSendNewMessage ep))
  428. contextMenu.MenuItems.Add(initMessageMI) |> ignore
  429. // endpoint specific
  430. match ep with
  431. | :? DkalEndPoint as dEp ->
  432. let showCommRulesMI = new MenuItem("Show installed communication rules...", new EventHandler(fun _ _ ->
  433. let assertionsText = String.concat "\n" (List.map (fun (a: Assertion) -> a.ToPrettyString()) (dEp.CommRules()))
  434. MessageBox.Show(assertionsText, ep.Id + " communication rules") |> ignore
  435. ))
  436. contextMenu.MenuItems.Add(showCommRulesMI) |> ignore
  437. let showKnowsMI = new MenuItem("Show principal infostrate...", new EventHandler(fun _ _ ->
  438. let assertionsText = String.concat "\n" (List.map (fun (a: Assertion) -> a.ToPrettyString()) (dEp.Knows()))
  439. MessageBox.Show(assertionsText, ep.Id + " infostrate") |> ignore
  440. ))
  441. contextMenu.MenuItems.Add(showKnowsMI) |> ignore
  442. | _ -> ()
  443. | :? DLabel as l -> findElement l.Parent
  444. | :? DEdge as e ->
  445. let headerMI = new MenuItem(e.Edge.LabelText)
  446. headerMI.Enabled <- false
  447. contextMenu.MenuItems.Add(headerMI) |> ignore
  448. contextMenu.MenuItems.Add("-") |> ignore
  449. let jumpToThisMessageMI = new MenuItem("Jump simulation to this message", new EventHandler(fun _ _ -> handleJumpToThisMessage e.Edge))
  450. contextMenu.MenuItems.Add(jumpToThisMessageMI) |> ignore
  451. | _ -> ()
  452. findElement underMouse
  453. | _ -> failwith "Expecting mouse event args in click handler"
  454. do
  455. // set the graph viewer
  456. //graphViewer.LayoutEditingEnabled <- false
  457. graphViewer.ToolBarIsVisible <- false
  458. graphViewer.ContextMenu <- contextMenu
  459. graphViewer.Graph <- graph
  460. // graph viewer events
  461. graphViewer.MouseWheel.Add(fun e ->
  462. if e.Delta > 0 then
  463. graphViewer.ZoomF <- graphViewer.ZoomF + 0.1
  464. else
  465. graphViewer.ZoomF <- graphViewer.ZoomF - 0.1)
  466. graphViewer.MouseDown.Add(handleGraphClick)
  467. graphViewer.MouseCaptureChanged.Add(fun _ -> underMouse <- null)
  468. graphViewer.SelectionChanged.Add(
  469. fun args ->
  470. underMouse <- graphViewer.ObjectUnderMouseCursor
  471. updateDescription()
  472. updateStatus())
  473. // form events
  474. form.KeyPreview <- true
  475. form.KeyDown.Add(fun args -> if args.KeyCode = Keys.Right && fwdButton.Enabled then
  476. fwdButton.PerformClick()
  477. elif args.KeyCode = Keys.Left && bckButton.Enabled then
  478. bckButton.PerformClick())
  479. // set toolbar
  480. let toolStripContainer = new ToolStripContainer()
  481. (*let toolStripToolbar = new ToolStrip()
  482. toolStripToolbar.Items.Add(new ToolStripMenuItem("Load a new endpoint...",
  483. Resources.Main.img_open,
  484. new EventHandler(fun _ _ -> handleLoadEndPoint()))) |> ignore*)
  485. let toolStripStatus = new StatusStrip()
  486. toolStripStatus.Items.Add(statusLabel) |> ignore
  487. //toolStripContainer.TopToolStripPanel.Controls.Add(toolStripToolbar)
  488. toolStripContainer.BottomToolStripPanel.Controls.Add(toolStripStatus)
  489. // set the form
  490. form.WindowState <- FormWindowState.Maximized
  491. form.Text <- "Scenario viewer"
  492. form.Icon <- Resources.Main.icon_general_pdp
  493. // left panel with message label
  494. let pLeft = new Panel()
  495. descrLabel.Dock <- DockStyle.Fill
  496. pLeft.Controls.Add(descrLabel)
  497. msgHeaderLabel.Font <- new Font(msgHeaderLabel.Font, FontStyle.Bold)
  498. msgHeaderLabel.Dock <- DockStyle.Top
  499. pLeft.Controls.Add(msgHeaderLabel)
  500. // right panel with graph viewer and buttons
  501. let pRight = new Panel()
  502. graphViewer.Dock <- DockStyle.Fill
  503. pRight.Controls.Add(graphViewer)
  504. // tooltips
  505. let tt = new ToolTip()
  506. tt.SetToolTip(nowButton, "Move simulation to most current state")
  507. tt.SetToolTip(fwdButton, "Perform one simulation step")
  508. tt.SetToolTip(bckButton, "Go back one simulation step")
  509. tt.SetToolTip(rstButton, "Reset simulation to its initial state")
  510. // set back/forward/etc.. buttons
  511. nowButton.Image <- Resources.Main.img_last
  512. nowButton.Dock <- DockStyle.Left
  513. nowButton.Click.Add(doNow)
  514. fwdButton.Image <- Resources.Main.img_next
  515. fwdButton.Dock <- DockStyle.Left
  516. fwdButton.Click.Add(doForward)
  517. bckButton.Image <- Resources.Main.img_prev
  518. bckButton.Dock <- DockStyle.Left
  519. bckButton.Click.Add(doBack)
  520. rstButton.Image <- Resources.Main.img_first
  521. rstButton.Dock <- DockStyle.Left
  522. rstButton.Click.Add(doReset)
  523. stepLabel.Dock <- DockStyle.Fill
  524. stepLabel.TextAlign <- ContentAlignment.MiddleCenter
  525. updateControls()
  526. // group back and forward buttons
  527. let pButtons = new Panel()
  528. pButtons.Controls.AddRange([| stepLabel; nowButton; fwdButton; bckButton; rstButton|])
  529. pButtons.Height <- 40
  530. pButtons.Dock <- DockStyle.Bottom
  531. pRight.Controls.Add(pButtons)
  532. // set description label
  533. descrLabel.ReadOnly <- true
  534. descrLabel.Multiline <- true
  535. descrLabel.ScrollBars <- ScrollBars.Vertical
  536. // add elements to main panel
  537. let pMain = new Panel()
  538. let split = new SplitContainer()
  539. pLeft.Dock <- DockStyle.Fill
  540. split.Panel1.Controls.Add(pLeft)
  541. pRight.Dock <- DockStyle.Fill
  542. split.Panel2.Controls.Add(pRight)
  543. split.Dock <- DockStyle.Fill
  544. pMain.Controls.Add(split)
  545. // add elements to form
  546. form.SuspendLayout()
  547. pMain.Dock <- DockStyle.Fill
  548. toolStripContainer.ContentPanel.Controls.Add(pMain)
  549. toolStripContainer.Dock <- DockStyle.Fill
  550. form.Controls.Add(toolStripContainer)
  551. form.ResumeLayout()
  552. split.SplitterDistance <- 50
  553. member this.Display() =
  554. let init = fun () ->
  555. try
  556. Application.Run(form)
  557. with
  558. | e -> printfn "%O" e
  559. appThread <- Some (Thread init)
  560. appThread.Value.Start()
  561. member this.WaitForWindow() =
  562. match appThread with
  563. | None -> ()
  564. | Some t -> t.Join()
  565. appThread <- None
  566. member private this.Reset() =
  567. graph <- new Graph("scenario")
  568. geomGraph <- new Microsoft.Msagl.GeometryGraph()
  569. graph.Attr.BackgroundColor <- new Microsoft.Msagl.Drawing.Color(byte(211), byte(211), byte(211))
  570. graphViewer.Graph <- graph
  571. underMouse <- null
  572. edges.Clear()
  573. nodes.Clear()
  574. highlightedEdge <- None
  575. currIndex <- -1
  576. updateControls()
  577. descrLabel.Text <- ""
  578. statusLabel.Text <- ""
  579. reDraw()
  580. interface IScenarioViewer with
  581. member this.AssignScenario (s: IScenario) =
  582. this.Reset()
  583. scenario <- Some s
  584. form.Text <- "Scenario viewer - " + s.Name
  585. member this.NotifyNewEndPoint (ep: IEndPoint) =
  586. nodes.[ep.Id] <- ep
  587. let n = graph.AddNode(ep.Id)
  588. applyNodeAttributes(ep, n)
  589. reDraw()
  590. member this.NotifyNewMessage (m: IMessage) =
  591. form.Invoke(new VoidDelegate(fun () ->
  592. let messageNumber = edges.Count + 1
  593. let label = "(" + messageNumber.ToString() + ") " + m.Content.Type()
  594. let edge = graph.AddEdge(m.Sender, label, m.Receiver)
  595. edge.UserData <- m
  596. edge.Label.FontSize <- 6
  597. edges.Add(edge)
  598. makeInvisible edge
  599. //currIndex <- currIndex + 1
  600. updateControls()
  601. //highlightEdge (Some edge)
  602. reDraw()
  603. )) |> ignore