1 /* Title: Tools/jEdit/src/graphview_dockable.scala |
1 /* Title: Tools/jEdit/src/graphview_dockable.scala |
2 Author: Markus Kaiser, TU Muenchen |
|
3 Author: Makarius |
2 Author: Makarius |
4 |
3 |
5 Dockable window for graphview. |
4 Stateless dockable window for graphview. |
6 */ |
5 */ |
7 |
6 |
8 package isabelle.jedit |
7 package isabelle.jedit |
9 |
8 |
10 |
9 |
11 import isabelle._ |
10 import isabelle._ |
12 |
11 |
13 import java.awt.BorderLayout |
12 import javax.swing.JComponent |
14 import javax.swing.{JPanel, JComponent} |
13 import java.awt.event.{WindowFocusListener, WindowEvent} |
15 |
|
16 import scala.actors.Actor._ |
|
17 |
14 |
18 import org.gjt.sp.jedit.View |
15 import org.gjt.sp.jedit.View |
|
16 |
|
17 import scala.swing.TextArea |
|
18 |
|
19 |
|
20 object Graphview_Dockable |
|
21 { |
|
22 /* implicit arguments -- owned by Swing thread */ |
|
23 |
|
24 private var implicit_snapshot = Document.State.init.snapshot() |
|
25 |
|
26 private val no_graph: Exn.Result[graphview.Model.Graph] = Exn.Exn(ERROR("No graph")) |
|
27 private var implicit_graph = no_graph |
|
28 |
|
29 private def set_implicit(snapshot: Document.Snapshot, graph: Exn.Result[graphview.Model.Graph]) |
|
30 { |
|
31 Swing_Thread.require() |
|
32 |
|
33 implicit_snapshot = snapshot |
|
34 implicit_graph = graph |
|
35 } |
|
36 |
|
37 private def reset_implicit(): Unit = |
|
38 set_implicit(Document.State.init.snapshot(), no_graph) |
|
39 |
|
40 def apply(view: View, snapshot: Document.Snapshot, graph: Exn.Result[graphview.Model.Graph]) |
|
41 { |
|
42 set_implicit(snapshot, graph) |
|
43 view.getDockableWindowManager.floatDockableWindow("isabelle-graphview") |
|
44 } |
|
45 } |
19 |
46 |
20 |
47 |
21 class Graphview_Dockable(view: View, position: String) extends Dockable(view, position) |
48 class Graphview_Dockable(view: View, position: String) extends Dockable(view, position) |
22 { |
49 { |
23 Swing_Thread.require() |
50 Swing_Thread.require() |
24 |
51 |
|
52 private val snapshot = Graphview_Dockable.implicit_snapshot |
|
53 private val graph = Graphview_Dockable.implicit_graph |
25 |
54 |
26 /* component state -- owned by Swing thread */ |
55 private val window_focus_listener = |
|
56 new WindowFocusListener { |
|
57 def windowGainedFocus(e: WindowEvent) { Graphview_Dockable.set_implicit(snapshot, graph) } |
|
58 def windowLostFocus(e: WindowEvent) { Graphview_Dockable.reset_implicit() } |
|
59 } |
27 |
60 |
28 private val do_update = true // FIXME |
61 val graphview = |
29 |
62 graph match { |
30 private var current_snapshot = Document.State.init.snapshot() |
63 case Exn.Res(proper_graph) => |
31 private var current_state = Command.empty.init_state |
64 new isabelle.graphview.Main_Panel(proper_graph) { |
32 private var current_graph: XML.Body = Nil |
65 override def make_tooltip(parent: JComponent, x: Int, y: Int, body: XML.Body): String = |
33 |
66 { |
34 |
67 val rendering = Rendering(snapshot, PIDE.options.value) |
35 /* GUI components */ |
68 new Pretty_Tooltip(view, parent, rendering, x, y, body) |
36 |
69 null |
37 private val graphview = new JPanel |
70 } |
38 |
|
39 // FIXME mutable GUI content |
|
40 private def set_graphview(snapshot: Document.Snapshot, graph_xml: XML.Body) |
|
41 { |
|
42 val graph = isabelle.graphview.Model.decode_graph(graph_xml).transitive_reduction_acyclic |
|
43 |
|
44 graphview.removeAll() |
|
45 graphview.setLayout(new BorderLayout) |
|
46 val panel = |
|
47 new isabelle.graphview.Main_Panel(graph) { |
|
48 override def make_tooltip(parent: JComponent, x: Int, y: Int, body: XML.Body): String = |
|
49 { |
|
50 val rendering = Rendering(snapshot, PIDE.options.value) |
|
51 new Pretty_Tooltip(view, parent, rendering, x, y, body) |
|
52 null |
|
53 } |
71 } |
54 } |
72 case Exn.Exn(exn) => new TextArea(Exn.message(exn)) |
55 graphview.add(panel.peer, BorderLayout.CENTER) |
73 } |
56 graphview.revalidate() |
|
57 } |
|
58 |
|
59 set_graphview(current_snapshot, current_graph) |
|
60 set_content(graphview) |
74 set_content(graphview) |
61 |
|
62 |
|
63 private def handle_update(follow: Boolean, restriction: Option[Set[Command]]) |
|
64 { |
|
65 Swing_Thread.require() |
|
66 |
|
67 val (new_snapshot, new_state) = |
|
68 Document_View(view.getTextArea) match { |
|
69 case Some(doc_view) => |
|
70 val snapshot = doc_view.model.snapshot() |
|
71 if (follow && !snapshot.is_outdated) { |
|
72 snapshot.node.command_at(doc_view.text_area.getCaretPosition).map(_._1) match { |
|
73 case Some(cmd) => |
|
74 (snapshot, snapshot.state.command_state(snapshot.version, cmd)) |
|
75 case None => |
|
76 (Document.State.init.snapshot(), Command.empty.init_state) |
|
77 } |
|
78 } |
|
79 else (current_snapshot, current_state) |
|
80 case None => (current_snapshot, current_state) |
|
81 } |
|
82 |
|
83 val new_graph = |
|
84 if (!restriction.isDefined || restriction.get.contains(new_state.command)) { |
|
85 new_state.markup.cumulate[Option[XML.Body]]( |
|
86 new_state.command.range, None, Some(Set(Markup.GRAPHVIEW)), |
|
87 { |
|
88 case (_, Text.Info(_, XML.Elem(Markup(Markup.GRAPHVIEW, _), graph))) => |
|
89 Some(graph) |
|
90 }).filter(_.info.isDefined) match { |
|
91 case Text.Info(_, Some(graph)) #:: _ => graph |
|
92 case _ => Nil |
|
93 } |
|
94 } |
|
95 else current_graph |
|
96 |
|
97 if (new_graph != current_graph) set_graphview(new_snapshot, new_graph) |
|
98 |
|
99 current_snapshot = new_snapshot |
|
100 current_state = new_state |
|
101 current_graph = new_graph |
|
102 } |
|
103 |
|
104 |
|
105 /* main actor */ |
|
106 |
|
107 private val main_actor = actor { |
|
108 loop { |
|
109 react { |
|
110 case _: Session.Global_Options => // FIXME |
|
111 |
|
112 case changed: Session.Commands_Changed => |
|
113 Swing_Thread.later { handle_update(do_update, Some(changed.commands)) } |
|
114 |
|
115 case Session.Caret_Focus => |
|
116 Swing_Thread.later { handle_update(do_update, None) } |
|
117 |
|
118 case bad => |
|
119 java.lang.System.err.println("Graphview_Dockable: ignoring bad message " + bad) |
|
120 } |
|
121 } |
|
122 } |
|
123 |
75 |
124 override def init() |
76 override def init() |
125 { |
77 { |
126 Swing_Thread.require() |
78 Swing_Thread.require() |
127 |
79 JEdit_Lib.parent_window(this).map(_.addWindowFocusListener(window_focus_listener)) |
128 PIDE.session.global_options += main_actor |
|
129 PIDE.session.commands_changed += main_actor |
|
130 PIDE.session.caret_focus += main_actor |
|
131 handle_update(do_update, None) |
|
132 } |
80 } |
133 |
81 |
134 override def exit() |
82 override def exit() |
135 { |
83 { |
136 Swing_Thread.require() |
84 Swing_Thread.require() |
137 |
85 JEdit_Lib.parent_window(this).map(_.removeWindowFocusListener(window_focus_listener)) |
138 PIDE.session.global_options -= main_actor |
|
139 PIDE.session.commands_changed -= main_actor |
|
140 PIDE.session.caret_focus -= main_actor |
|
141 } |
86 } |
142 } |
87 } |