src/Tools/jEdit/src/debugger_dockable.scala
changeset 60848 7ec20b1c8dc9
parent 60845 c4cb46e3cdd1
child 60849 6e49311ef842
equal deleted inserted replaced
60847:239d7714392b 60848:7ec20b1c8dc9
     7 package isabelle.jedit
     7 package isabelle.jedit
     8 
     8 
     9 
     9 
    10 import isabelle._
    10 import isabelle._
    11 
    11 
    12 import java.awt.BorderLayout
    12 import java.awt.{BorderLayout, Dimension}
    13 import java.awt.event.{ComponentEvent, ComponentAdapter, KeyEvent}
    13 import java.awt.event.{ComponentEvent, ComponentAdapter, KeyEvent, MouseEvent, MouseAdapter}
    14 
    14 import javax.swing.{JTree, JScrollPane}
    15 import scala.swing.{Button, Label, Component}
    15 import javax.swing.tree.{DefaultMutableTreeNode, TreeSelectionModel}
       
    16 import javax.swing.event.{TreeSelectionEvent, TreeSelectionListener}
       
    17 
       
    18 import scala.swing.{Button, Label, Component, SplitPane, Orientation}
    16 import scala.swing.event.ButtonClicked
    19 import scala.swing.event.ButtonClicked
    17 
    20 
    18 import org.gjt.sp.jedit.View
    21 import org.gjt.sp.jedit.View
    19 
    22 
       
    23 
       
    24 object Debugger_Dockable
       
    25 {
       
    26   sealed case class Tree_Entry(thread_name: String, debug_states: List[Debugger.Debug_State])
       
    27   {
       
    28     override def toString: String = thread_name
       
    29   }
       
    30 }
    20 
    31 
    21 class Debugger_Dockable(view: View, position: String) extends Dockable(view, position)
    32 class Debugger_Dockable(view: View, position: String) extends Dockable(view, position)
    22 {
    33 {
    23   GUI_Thread.require {}
    34   GUI_Thread.require {}
    24 
    35 
    25 
    36 
    26   /* component state -- owned by GUI thread */
    37   /* component state -- owned by GUI thread */
    27 
    38 
    28   private var current_snapshot = Document.Snapshot.init
    39   private var current_snapshot = Document.Snapshot.init
       
    40   private var current_threads: Map[String, List[Debugger.Debug_State]] = Map.empty
    29   private var current_output: List[XML.Tree] = Nil
    41   private var current_output: List[XML.Tree] = Nil
    30 
    42 
    31 
    43 
    32   /* common GUI components */
    44   /* pretty text area */
       
    45 
       
    46   val pretty_text_area = new Pretty_Text_Area(view)
       
    47 
       
    48   override def detach_operation = pretty_text_area.detach_operation
       
    49 
       
    50   private def handle_resize()
       
    51   {
       
    52     GUI_Thread.require {}
       
    53 
       
    54     pretty_text_area.resize(
       
    55       Font_Info.main(PIDE.options.real("jedit_font_scale") * zoom.factor / 100))
       
    56   }
       
    57 
       
    58   private def handle_update()
       
    59   {
       
    60     GUI_Thread.require {}
       
    61 
       
    62     val new_state = Debugger.current_state()
       
    63 
       
    64     val new_snapshot = PIDE.editor.current_node_snapshot(view).getOrElse(current_snapshot)
       
    65     val new_threads = new_state.threads
       
    66     val new_output =  // FIXME select by thread name
       
    67       (for ((_, results) <- new_state.output; (_, tree) <- results.iterator)
       
    68         yield tree).toList ::: List(XML.Text(new_threads.toString))
       
    69 
       
    70     if (new_threads != current_threads) {
       
    71       val entries =
       
    72         (for ((a, b) <- new_threads.iterator)
       
    73           yield Debugger_Dockable.Tree_Entry(a, b)).toList.sortBy(_.thread_name)
       
    74       update_tree(entries)
       
    75     }
       
    76 
       
    77     if (new_output != current_output)
       
    78       pretty_text_area.update(new_snapshot, Command.Results.empty, Pretty.separate(new_output))
       
    79 
       
    80     current_snapshot = new_snapshot
       
    81     current_threads = new_threads
       
    82     current_output = new_output
       
    83 
       
    84     revalidate()
       
    85     repaint()
       
    86   }
       
    87 
       
    88 
       
    89   /* tree view */
       
    90 
       
    91   private val root = new DefaultMutableTreeNode("Threads")
       
    92 
       
    93   val tree = new JTree(root)
       
    94   tree.setRowHeight(0)
       
    95   tree.getSelectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION)
       
    96 
       
    97   private def update_tree(entries: List[Debugger_Dockable.Tree_Entry])
       
    98   {
       
    99     tree.clearSelection
       
   100 
       
   101     root.removeAllChildren
       
   102     val entry_nodes = entries.map(entry => new DefaultMutableTreeNode(entry))
       
   103     for (node <- entry_nodes) root.add(node)
       
   104 
       
   105     for (i <- 0 until tree.getRowCount) tree.expandRow(i)
       
   106 
       
   107     for ((entry, node) <- entries zip entry_nodes) {
       
   108       for (debug_state <- entry.debug_states) {
       
   109         val sub_node = new DefaultMutableTreeNode(debug_state.function)
       
   110         node.add(sub_node)
       
   111       }
       
   112     }
       
   113 
       
   114     tree.revalidate()
       
   115   }
       
   116 
       
   117   private def action(node: DefaultMutableTreeNode)
       
   118   {
       
   119     node.getUserObject match {
       
   120       case _ => // FIXME
       
   121     }
       
   122   }
       
   123 
       
   124   tree.addMouseListener(new MouseAdapter {
       
   125     override def mouseClicked(e: MouseEvent)
       
   126     {
       
   127       val click = tree.getPathForLocation(e.getX, e.getY)
       
   128       if (click != null && e.getClickCount == 1) {
       
   129         (click.getLastPathComponent, tree.getLastSelectedPathComponent) match {
       
   130           case (node: DefaultMutableTreeNode, node1: DefaultMutableTreeNode) if node == node1 =>
       
   131             action(node)
       
   132           case _ =>
       
   133         }
       
   134       }
       
   135     }
       
   136   })
       
   137 
       
   138   val tree_view = new JScrollPane(tree)
       
   139   tree_view.setMinimumSize(new Dimension(100, 50))
       
   140 
       
   141 
       
   142   /* controls */
    33 
   143 
    34   private val context_label = new Label("Context:") { tooltip = "Isabelle/ML context (optional)" }
   144   private val context_label = new Label("Context:") { tooltip = "Isabelle/ML context (optional)" }
    35   private val context_field =
   145   private val context_field =
    36     new Completion_Popup.History_Text_Field("isabelle-debugger-context")
   146     new Completion_Popup.History_Text_Field("isabelle-debugger-context")
    37     {
   147     {
    58 
   168 
    59   private val eval_button = new Button("<html><b>Eval</b></html>") {
   169   private val eval_button = new Button("<html><b>Eval</b></html>") {
    60       tooltip = "Evaluate Isabelle/ML expression within optional context"
   170       tooltip = "Evaluate Isabelle/ML expression within optional context"
    61       reactions += { case ButtonClicked(_) => eval_expression() }
   171       reactions += { case ButtonClicked(_) => eval_expression() }
    62     }
   172     }
       
   173   override def focusOnDefaultComponent { eval_button.requestFocus }
    63 
   174 
    64   private def eval_expression()
   175   private def eval_expression()
    65   {
   176   {
    66     // FIXME
   177     // FIXME
    67     Output.writeln("eval context = " + quote(context_field.getText) + " expression = " +
   178     Output.writeln("eval context = " + quote(context_field.getText) + " expression = " +
    68       quote(expression_field.getText))
   179       quote(expression_field.getText))
    69   }
   180   }
    70 
   181 
    71 
       
    72   /* controls */
       
    73 
       
    74   private val debugger_active =
   182   private val debugger_active =
    75     new JEdit_Options.Check_Box("ML_debugger_active", "Active", "Enable debugger at run-time")
   183     new JEdit_Options.Check_Box("ML_debugger_active", "Active", "Enable debugger at run-time")
    76 
   184 
    77   private val debugger_stepping =
   185   private val debugger_stepping =
    78     new JEdit_Options.Check_Box("ML_debugger_stepping", "Stepping", "Enable single-step mode")
   186     new JEdit_Options.Check_Box("ML_debugger_stepping", "Stepping", "Enable single-step mode")
    79 
   187 
    80   private val zoom = new Font_Info.Zoom_Box { def changed = handle_resize() }
   188   private val zoom = new Font_Info.Zoom_Box { def changed = handle_resize() }
    81 
   189 
    82 
   190   private val controls =
    83   /* pretty text area */
   191     new Wrap_Panel(Wrap_Panel.Alignment.Right)(
    84 
   192       context_label, Component.wrap(context_field),
    85   val pretty_text_area = new Pretty_Text_Area(view)
   193       expression_label, Component.wrap(expression_field), eval_button,
    86   set_content(pretty_text_area)
   194       pretty_text_area.search_label, pretty_text_area.search_field,
    87 
   195       debugger_stepping, debugger_active, zoom)
    88   override def detach_operation = pretty_text_area.detach_operation
   196   add(controls.peer, BorderLayout.NORTH)
    89 
   197 
    90 
   198 
    91   private def handle_resize()
   199   /* main panel */
    92   {
   200 
    93     GUI_Thread.require {}
   201   val main_panel = new SplitPane(Orientation.Vertical) {
    94 
   202     oneTouchExpandable = true
    95     pretty_text_area.resize(
   203     leftComponent = Component.wrap(tree_view)
    96       Font_Info.main(PIDE.options.real("jedit_font_scale") * zoom.factor / 100))
   204     rightComponent = Component.wrap(pretty_text_area)
    97   }
   205   }
    98 
   206   set_content(main_panel)
    99   private def handle_update()
       
   100   {
       
   101     GUI_Thread.require {}
       
   102 
       
   103     val new_snapshot = PIDE.editor.current_node_snapshot(view).getOrElse(current_snapshot)
       
   104     val new_output =  // FIXME select by thread name
       
   105       (for ((_, results) <- Debugger.current_state.output; (_, tree) <- results.iterator)
       
   106         yield tree).toList ::: List(XML.Text(Debugger.current_state.threads.toString))
       
   107 
       
   108     if (new_output != current_output)
       
   109       pretty_text_area.update(new_snapshot, Command.Results.empty, Pretty.separate(new_output))
       
   110 
       
   111     current_snapshot = new_snapshot
       
   112     current_output = new_output
       
   113   }
       
   114 
   207 
   115 
   208 
   116   /* main */
   209   /* main */
   117 
   210 
   118   private val main =
   211   private val main =
   152 
   245 
   153   addComponentListener(new ComponentAdapter {
   246   addComponentListener(new ComponentAdapter {
   154     override def componentResized(e: ComponentEvent) { delay_resize.invoke() }
   247     override def componentResized(e: ComponentEvent) { delay_resize.invoke() }
   155     override def componentShown(e: ComponentEvent) { delay_resize.invoke() }
   248     override def componentShown(e: ComponentEvent) { delay_resize.invoke() }
   156   })
   249   })
   157 
       
   158 
       
   159   /* controls */
       
   160 
       
   161   private val controls =
       
   162     new Wrap_Panel(Wrap_Panel.Alignment.Right)(
       
   163       context_label, Component.wrap(context_field),
       
   164       expression_label, Component.wrap(expression_field), eval_button,
       
   165       pretty_text_area.search_label, pretty_text_area.search_field,
       
   166       debugger_stepping, debugger_active, zoom)
       
   167   add(controls.peer, BorderLayout.NORTH)
       
   168 }
   250 }