stateless dockable window for graphview, which is triggered by the active area of the corresponding diagnostic command;
authorwenzelm
Mon, 10 Dec 2012 15:17:47 +0100
changeset 50452 bfb5964e3041
parent 50451 2af559170d07
child 50453 262dc5873f80
stateless dockable window for graphview, which is triggered by the active area of the corresponding diagnostic command;
src/Pure/General/graph.scala
src/Tools/jEdit/src/Isabelle.props
src/Tools/jEdit/src/actions.xml
src/Tools/jEdit/src/active.scala
src/Tools/jEdit/src/graphview_dockable.scala
--- a/src/Pure/General/graph.scala	Mon Dec 10 15:13:13 2012 +0100
+++ b/src/Pure/General/graph.scala	Mon Dec 10 15:17:47 2012 +0100
@@ -237,7 +237,8 @@
   def transitive_reduction_acyclic: Graph[Key, A] =
   {
     val trans = this.transitive_closure
-    assert(!trans.entries.exists({ case (x, (_, (_, succs))) => succs.contains(x) }))
+    if (trans.entries.exists({ case (x, (_, (_, succs))) => succs.contains(x) }))
+      error("Cyclic graph")
 
     var graph = this
     for {
--- a/src/Tools/jEdit/src/Isabelle.props	Mon Dec 10 15:13:13 2012 +0100
+++ b/src/Tools/jEdit/src/Isabelle.props	Mon Dec 10 15:17:47 2012 +0100
@@ -29,7 +29,6 @@
 #menu actions
 plugin.isabelle.jedit.Plugin.menu.label=Isabelle
 plugin.isabelle.jedit.Plugin.menu= \
-  isabelle.graphview-panel \
   isabelle.monitor-panel \
   isabelle.output-panel \
   isabelle.protocol-panel \
@@ -38,7 +37,6 @@
   isabelle.symbols-panel \
   isabelle.syslog-panel \
   isabelle.theories-panel
-isabelle.graphview-panel.label=Graphview panel
 isabelle.monitor-panel.label=Monitor panel
 isabelle.output-panel.label=Output panel
 isabelle.protocol-panel.label=Protocol panel
@@ -49,7 +47,6 @@
 isabelle.theories-panel.label=Theories panel
 
 #dockables
-isabelle-graphview.title=Graphview
 isabelle-info.title=Info
 isabelle-monitor.title=Monitor
 isabelle-output.title=Output
--- a/src/Tools/jEdit/src/actions.xml	Mon Dec 10 15:13:13 2012 +0100
+++ b/src/Tools/jEdit/src/actions.xml	Mon Dec 10 15:17:47 2012 +0100
@@ -22,11 +22,6 @@
 			wm.addDockableWindow("isabelle-output");
 		</CODE>
 	</ACTION>
-	<ACTION NAME="isabelle.graphview-panel">
-		<CODE>
-			wm.addDockableWindow("isabelle-graphview");
-		</CODE>
-	</ACTION>
 	<ACTION NAME="isabelle.raw-output-panel">
 		<CODE>
 			wm.addDockableWindow("isabelle-raw-output");
--- a/src/Tools/jEdit/src/active.scala	Mon Dec 10 15:13:13 2012 +0100
+++ b/src/Tools/jEdit/src/active.scala	Mon Dec 10 15:17:47 2012 +0100
@@ -26,31 +26,45 @@
           val buffer = model.buffer
           val snapshot = model.snapshot()
 
+          def try_replace_command(exec_id: Document.ID, s: String)
+          {
+            snapshot.state.execs.get(exec_id).map(_.command) match {
+              case Some(command) =>
+                snapshot.node.command_start(command) match {
+                  case Some(start) =>
+                    JEdit_Lib.buffer_edit(buffer) {
+                      buffer.remove(start, command.proper_range.length)
+                      buffer.insert(start, s)
+                    }
+                  case None =>
+                }
+              case None =>
+            }
+          }
+
           if (!snapshot.is_outdated) {
             elem match {
               case XML.Elem(Markup(Markup.SENDBACK, props), _) =>
                 props match {
                   case Position.Id(exec_id) =>
-                    snapshot.state.execs.get(exec_id).map(_.command) match {
-                      case Some(command) =>
-                        snapshot.node.command_start(command) match {
-                          case Some(start) =>
-                            JEdit_Lib.buffer_edit(buffer) {
-                              buffer.remove(start, command.proper_range.length)
-                              buffer.insert(start, text)
-                            }
-                          case None =>
-                        }
-                      case None =>
-                    }
+                    try_replace_command(exec_id, text)
                   case _ =>
                     if (props.exists(_ == Markup.PADDING_LINE))
                       Isabelle.insert_line_padding(text_area, text)
                     else text_area.setSelectedText(text)
                 }
 
-              case XML.Elem(Markup(Markup.GRAPHVIEW, props), body) =>
-                java.lang.System.err.println("graphview " + props)  // FIXME
+              case XML.Elem(Markup(Markup.GRAPHVIEW, Position.Id(exec_id)), body) =>
+                try_replace_command(exec_id, "")
+                default_thread_pool.submit(() =>
+                  {
+                    val graph =
+                      Exn.capture {
+                        isabelle.graphview.Model.decode_graph(body)
+                          .transitive_reduction_acyclic
+                      }
+                    Swing_Thread.later { Graphview_Dockable(view, snapshot, graph) }
+                  })
 
               case _ =>
             }
--- a/src/Tools/jEdit/src/graphview_dockable.scala	Mon Dec 10 15:13:13 2012 +0100
+++ b/src/Tools/jEdit/src/graphview_dockable.scala	Mon Dec 10 15:17:47 2012 +0100
@@ -1,8 +1,7 @@
 /*  Title:      Tools/jEdit/src/graphview_dockable.scala
-    Author:     Markus Kaiser, TU Muenchen
     Author:     Makarius
 
-Dockable window for graphview.
+Stateless dockable window for graphview.
 */
 
 package isabelle.jedit
@@ -10,133 +9,79 @@
 
 import isabelle._
 
-import java.awt.BorderLayout
-import javax.swing.{JPanel, JComponent}
-
-import scala.actors.Actor._
+import javax.swing.JComponent
+import java.awt.event.{WindowFocusListener, WindowEvent}
 
 import org.gjt.sp.jedit.View
 
+import scala.swing.TextArea
+
+
+object Graphview_Dockable
+{
+  /* implicit arguments -- owned by Swing thread */
+
+  private var implicit_snapshot = Document.State.init.snapshot()
+
+  private val no_graph: Exn.Result[graphview.Model.Graph] = Exn.Exn(ERROR("No graph"))
+  private var implicit_graph = no_graph
+
+  private def set_implicit(snapshot: Document.Snapshot, graph: Exn.Result[graphview.Model.Graph])
+  {
+    Swing_Thread.require()
+
+    implicit_snapshot = snapshot
+    implicit_graph = graph
+  }
+
+  private def reset_implicit(): Unit =
+    set_implicit(Document.State.init.snapshot(), no_graph)
+
+  def apply(view: View, snapshot: Document.Snapshot, graph: Exn.Result[graphview.Model.Graph])
+  {
+    set_implicit(snapshot, graph)
+    view.getDockableWindowManager.floatDockableWindow("isabelle-graphview")
+  }
+}
+
 
 class Graphview_Dockable(view: View, position: String) extends Dockable(view, position)
 {
   Swing_Thread.require()
 
-
-  /* component state -- owned by Swing thread */
-
-  private val do_update = true  // FIXME
-
-  private var current_snapshot = Document.State.init.snapshot()
-  private var current_state = Command.empty.init_state
-  private var current_graph: XML.Body = Nil
-
-
-  /* GUI components */
-
-  private val graphview = new JPanel
-
-  // FIXME mutable GUI content
-  private def set_graphview(snapshot: Document.Snapshot, graph_xml: XML.Body)
-  {
-    val graph = isabelle.graphview.Model.decode_graph(graph_xml).transitive_reduction_acyclic
+  private val snapshot = Graphview_Dockable.implicit_snapshot
+  private val graph = Graphview_Dockable.implicit_graph
 
-    graphview.removeAll()
-    graphview.setLayout(new BorderLayout)
-    val panel =
-      new isabelle.graphview.Main_Panel(graph) {
-        override def make_tooltip(parent: JComponent, x: Int, y: Int, body: XML.Body): String =
-        {
-          val rendering = Rendering(snapshot, PIDE.options.value)
-          new Pretty_Tooltip(view, parent, rendering, x, y, body)
-          null
-        }
-      }
-    graphview.add(panel.peer, BorderLayout.CENTER)
-    graphview.revalidate()
-  }
-
-  set_graphview(current_snapshot, current_graph)
-  set_content(graphview)
-
-
-  private def handle_update(follow: Boolean, restriction: Option[Set[Command]])
-  {
-    Swing_Thread.require()
+  private val window_focus_listener =
+    new WindowFocusListener {
+      def windowGainedFocus(e: WindowEvent) { Graphview_Dockable.set_implicit(snapshot, graph) }
+      def windowLostFocus(e: WindowEvent) { Graphview_Dockable.reset_implicit() }
+    }
 
-    val (new_snapshot, new_state) =
-      Document_View(view.getTextArea) match {
-        case Some(doc_view) =>
-          val snapshot = doc_view.model.snapshot()
-          if (follow && !snapshot.is_outdated) {
-            snapshot.node.command_at(doc_view.text_area.getCaretPosition).map(_._1) match {
-              case Some(cmd) =>
-                (snapshot, snapshot.state.command_state(snapshot.version, cmd))
-              case None =>
-                (Document.State.init.snapshot(), Command.empty.init_state)
-            }
+  val graphview =
+    graph match {
+      case Exn.Res(proper_graph) =>
+        new isabelle.graphview.Main_Panel(proper_graph) {
+          override def make_tooltip(parent: JComponent, x: Int, y: Int, body: XML.Body): String =
+          {
+            val rendering = Rendering(snapshot, PIDE.options.value)
+            new Pretty_Tooltip(view, parent, rendering, x, y, body)
+            null
           }
-          else (current_snapshot, current_state)
-        case None => (current_snapshot, current_state)
-      }
-
-    val new_graph =
-      if (!restriction.isDefined || restriction.get.contains(new_state.command)) {
-        new_state.markup.cumulate[Option[XML.Body]](
-          new_state.command.range, None, Some(Set(Markup.GRAPHVIEW)),
-        {
-          case (_, Text.Info(_, XML.Elem(Markup(Markup.GRAPHVIEW, _), graph))) =>
-            Some(graph)
-        }).filter(_.info.isDefined) match {
-          case Text.Info(_, Some(graph)) #:: _ => graph
-          case _ => Nil
         }
-      }
-      else current_graph
-
-    if (new_graph != current_graph) set_graphview(new_snapshot, new_graph)
-
-    current_snapshot = new_snapshot
-    current_state = new_state
-    current_graph = new_graph
-  }
-
-
-  /* main actor */
-
-  private val main_actor = actor {
-    loop {
-      react {
-        case _: Session.Global_Options =>  // FIXME
-
-        case changed: Session.Commands_Changed =>
-          Swing_Thread.later { handle_update(do_update, Some(changed.commands)) }
-
-        case Session.Caret_Focus =>
-          Swing_Thread.later { handle_update(do_update, None) }
-
-        case bad =>
-          java.lang.System.err.println("Graphview_Dockable: ignoring bad message " + bad)
-      }
+      case Exn.Exn(exn) => new TextArea(Exn.message(exn))
     }
-  }
+  set_content(graphview)
 
   override def init()
   {
     Swing_Thread.require()
-
-    PIDE.session.global_options += main_actor
-    PIDE.session.commands_changed += main_actor
-    PIDE.session.caret_focus += main_actor
-    handle_update(do_update, None)
+    JEdit_Lib.parent_window(this).map(_.addWindowFocusListener(window_focus_listener))
   }
 
   override def exit()
   {
     Swing_Thread.require()
-
-    PIDE.session.global_options -= main_actor
-    PIDE.session.commands_changed -= main_actor
-    PIDE.session.caret_focus -= main_actor
+    JEdit_Lib.parent_window(this).map(_.removeWindowFocusListener(window_focus_listener))
   }
 }