follow debugger focus;
authorwenzelm
Mon, 10 Aug 2015 14:14:49 +0200
changeset 60875 ee23c1d21ac3
parent 60874 7865e03a7fc1
child 60876 52edced9cce5
follow debugger focus;
src/Pure/Tools/debugger.scala
src/Tools/jEdit/src/debugger_dockable.scala
--- a/src/Pure/Tools/debugger.scala	Mon Aug 10 14:13:49 2015 +0200
+++ b/src/Pure/Tools/debugger.scala	Mon Aug 10 14:14:49 2015 +0200
@@ -17,12 +17,16 @@
 
   sealed case class State(
     session: Session = new Session(Resources.empty),
+    focus: Option[Position.T] = None,  // position of active GUI component
     threads: Map[String, List[Debug_State]] = Map.empty,  // thread name ~> stack of debug states
     output: Map[String, Command.Results] = Map.empty)  // thread name ~> output messages
   {
     def set_session(new_session: Session): State =
       copy(session = new_session)
 
+    def set_focus(new_focus: Option[Position.T]): State =
+      copy(focus = new_focus)
+
     def get_thread(thread_name: String): List[Debug_State] =
       threads.getOrElse(thread_name, Nil)
 
@@ -120,6 +124,9 @@
     current_state().session.protocol_command("Debugger.init")
   }
 
+  def focus(new_focus: Option[Position.T]): Boolean =
+    global_state.change_result(state => (state.focus != new_focus, state.set_focus(new_focus)))
+
   def cancel(thread_name: String): Unit =
     current_state().session.protocol_command("Debugger.cancel", thread_name)
 
--- a/src/Tools/jEdit/src/debugger_dockable.scala	Mon Aug 10 14:13:49 2015 +0200
+++ b/src/Tools/jEdit/src/debugger_dockable.scala	Mon Aug 10 14:14:49 2015 +0200
@@ -10,7 +10,8 @@
 import isabelle._
 
 import java.awt.{BorderLayout, Dimension}
-import java.awt.event.{ComponentEvent, ComponentAdapter, KeyEvent, MouseEvent, MouseAdapter}
+import java.awt.event.{ComponentEvent, ComponentAdapter, KeyEvent, MouseEvent, MouseAdapter,
+  FocusAdapter, FocusEvent}
 import javax.swing.{JTree, JScrollPane}
 import javax.swing.tree.{DefaultMutableTreeNode, DefaultTreeModel, TreeSelectionModel}
 import javax.swing.event.{TreeSelectionEvent, TreeSelectionListener}
@@ -18,7 +19,7 @@
 import scala.swing.{Button, Label, Component, SplitPane, Orientation, CheckBox}
 import scala.swing.event.ButtonClicked
 
-import org.gjt.sp.jedit.View
+import org.gjt.sp.jedit.{jEdit, View}
 
 
 object Debugger_Dockable
@@ -117,6 +118,14 @@
 
   def thread_selection(): Option[String] = tree_selection().map(sel => sel._1.thread_name)
 
+  def focus_selection(): Option[Position.T] =
+    tree_selection() match {
+      case Some((t, opt_index)) =>
+        val i = opt_index getOrElse 0
+        if (i < t.debug_states.length) Some(t.debug_states(i).pos) else None
+      case _ => None
+    }
+
   private def update_tree(thread_entries: List[Debugger_Dockable.Thread_Entry])
   {
     val old_thread_selection = thread_selection()
@@ -149,10 +158,10 @@
     tree.revalidate()
   }
 
-  private def action(node: DefaultMutableTreeNode)
-  {
-    handle_update()
-  }
+  tree.addTreeSelectionListener(
+    new TreeSelectionListener {
+      override def valueChanged(e: TreeSelectionEvent) { update_focus(focus_selection()) }
+    })
 
   tree.addMouseListener(new MouseAdapter {
     override def mouseClicked(e: MouseEvent)
@@ -161,7 +170,7 @@
       if (click != null && e.getClickCount == 1) {
         (click.getLastPathComponent, tree.getLastSelectedPathComponent) match {
           case (node: DefaultMutableTreeNode, node1: DefaultMutableTreeNode) if node == node1 =>
-            action(node)
+            handle_update()
           case _ =>
         }
       }
@@ -212,7 +221,6 @@
       tooltip = "Evaluate ML expression within optional context"
       reactions += { case ButtonClicked(_) => eval_expression() }
     }
-  override def focusOnDefaultComponent { eval_button.requestFocus }
 
   private def eval_expression()
   {
@@ -270,6 +278,22 @@
   add(controls.peer, BorderLayout.NORTH)
 
 
+  /* focus */
+
+  override def focusOnDefaultComponent { eval_button.requestFocus }
+
+  addFocusListener(new FocusAdapter {
+    override def focusGained(e: FocusEvent) { update_focus(focus_selection()) }
+    override def focusLost(e: FocusEvent) { update_focus(None) }
+  })
+
+  private def update_focus(focus: Option[Position.T])
+  {
+    if (Debugger.focus(focus) && focus.isDefined)
+      PIDE.editor.hyperlink_position(current_snapshot, focus.get).foreach(_.follow(view))
+  }
+
+
   /* main panel */
 
   val main_panel = new SplitPane(Orientation.Vertical) {
@@ -309,6 +333,7 @@
     PIDE.session.global_options -= main
     PIDE.session.debugger_updates -= main
     delay_resize.revoke()
+    update_focus(None)
   }