--- 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)
}