src/Tools/jEdit/src/theories_dockable.scala
author wenzelm
Wed Jul 31 10:54:37 2013 +0200 (2013-07-31)
changeset 52807 b859a180936b
parent 52802 0b98561d0790
child 52809 e750169a5884
permissions -rw-r--r--
simplified flag for continuous checking: avoid GUI complexity and slow checking of all theories (including prints);
     1 /*  Title:      Tools/jEdit/src/theories_dockable.scala
     2     Author:     Makarius
     3 
     4 Dockable window for theories managed by prover.
     5 */
     6 
     7 package isabelle.jedit
     8 
     9 
    10 import isabelle._
    11 
    12 import scala.actors.Actor._
    13 import scala.swing.{FlowPanel, Button, TextArea, Label, ListView, Alignment,
    14   ScrollPane, Component, CheckBox}
    15 import scala.swing.event.{ButtonClicked, MouseClicked}
    16 
    17 import java.lang.System
    18 import java.awt.{BorderLayout, Graphics2D, Insets}
    19 import javax.swing.{JList, BorderFactory}
    20 import javax.swing.border.{BevelBorder, SoftBevelBorder}
    21 
    22 import org.gjt.sp.jedit.{View, jEdit}
    23 
    24 
    25 class Theories_Dockable(view: View, position: String) extends Dockable(view, position)
    26 {
    27   /* status */
    28 
    29   private val status = new ListView(Nil: List[Document.Node.Name]) {
    30     listenTo(mouse.clicks)
    31     reactions += {
    32       case MouseClicked(_, point, _, clicks, _) if clicks == 2 =>
    33         val index = peer.locationToIndex(point)
    34         if (index >= 0) Hyperlink(listData(index).node).follow(view)
    35     }
    36   }
    37   status.peer.setLayoutOrientation(JList.HORIZONTAL_WRAP)
    38   status.peer.setVisibleRowCount(0)
    39   status.selection.intervalMode = ListView.IntervalMode.Single
    40 
    41   set_content(new ScrollPane(status))
    42 
    43 
    44   /* controls */
    45 
    46   def phase_text(phase: Session.Phase): String =
    47     "Prover: " + Library.lowercase(phase.toString)
    48 
    49   private val session_phase = new Label(phase_text(PIDE.session.phase))
    50   session_phase.border = new SoftBevelBorder(BevelBorder.LOWERED)
    51   session_phase.tooltip = "Status of prover session"
    52 
    53   private def handle_phase(phase: Session.Phase)
    54   {
    55     Swing_Thread.later { session_phase.text = " " + phase_text(phase) + " " }
    56   }
    57 
    58   private val continuous_checking = new CheckBox("Continuous checking") {
    59     tooltip = "Continuous checking of proof document (visible and required parts)"
    60     reactions += { case ButtonClicked(_) => PIDE.continuous_checking = selected }
    61     def load() { selected = PIDE.continuous_checking }
    62     load()
    63   }
    64 
    65   private val logic = Isabelle_Logic.logic_selector(true)
    66 
    67   private val controls =
    68     new FlowPanel(FlowPanel.Alignment.Right)(continuous_checking, session_phase, logic)
    69   add(controls.peer, BorderLayout.NORTH)
    70 
    71 
    72   /* component state -- owned by Swing thread */
    73 
    74   private var nodes_status: Map[Document.Node.Name, Protocol.Node_Status] = Map.empty
    75 
    76   private object Node_Renderer_Component extends Label
    77   {
    78     opaque = false
    79     xAlignment = Alignment.Leading
    80     border = BorderFactory.createEmptyBorder(2, 2, 2, 2)
    81 
    82     var node_name = Document.Node.Name.empty
    83     override def paintComponent(gfx: Graphics2D)
    84     {
    85       nodes_status.get(node_name) match {
    86         case Some(st) if st.total > 0 =>
    87           val colors = List(
    88             (st.unprocessed, PIDE.options.color_value("unprocessed1_color")),
    89             (st.running, PIDE.options.color_value("running_color")),
    90             (st.warned, PIDE.options.color_value("warning_color")),
    91             (st.failed, PIDE.options.color_value("error_color")))
    92 
    93           val size = peer.getSize()
    94           val insets = border.getBorderInsets(peer)
    95           val w = size.width - insets.left - insets.right
    96           val h = size.height - insets.top - insets.bottom
    97           var end = size.width - insets.right
    98 
    99           for { (n, color) <- colors }
   100           {
   101             gfx.setColor(color)
   102             val v = (n * (w - colors.length) / st.total) max (if (n > 0) 4 else 0)
   103             gfx.fillRect(end - v, insets.top, v, h)
   104             end = end - v - 1
   105           }
   106         case _ =>
   107       }
   108       super.paintComponent(gfx)
   109     }
   110   }
   111 
   112   private class Node_Renderer extends ListView.Renderer[Document.Node.Name]
   113   {
   114     def componentFor(list: ListView[_], isSelected: Boolean, focused: Boolean,
   115       name: Document.Node.Name, index: Int): Component =
   116     {
   117       val component = Node_Renderer_Component
   118       component.node_name = name
   119       component.text = name.theory
   120       component
   121     }
   122   }
   123   status.renderer = new Node_Renderer
   124 
   125   private def handle_update(restriction: Option[Set[Document.Node.Name]] = None)
   126   {
   127     Swing_Thread.now {
   128       val snapshot = PIDE.session.snapshot()
   129 
   130       val iterator =
   131         restriction match {
   132           case Some(names) => names.iterator.map(name => (name, snapshot.version.nodes(name)))
   133           case None => snapshot.version.nodes.entries
   134         }
   135       val nodes_status1 =
   136         (nodes_status /: iterator)({ case (status, (name, node)) =>
   137             if (PIDE.thy_load.loaded_theories(name.theory)) status
   138             else status + (name -> Protocol.node_status(snapshot.state, snapshot.version, node)) })
   139 
   140       if (nodes_status != nodes_status1) {
   141         nodes_status = nodes_status1
   142         status.listData =
   143           snapshot.version.nodes.topological_order.filter(
   144             (name: Document.Node.Name) => nodes_status.isDefinedAt(name))
   145       }
   146     }
   147   }
   148 
   149 
   150   /* main actor */
   151 
   152   private val main_actor = actor {
   153     loop {
   154       react {
   155         case phase: Session.Phase => handle_phase(phase)
   156 
   157         case _: Session.Global_Options =>
   158           Swing_Thread.later {
   159             continuous_checking.load()
   160             logic.load ()
   161           }
   162 
   163         case changed: Session.Commands_Changed => handle_update(Some(changed.nodes))
   164 
   165         case bad => System.err.println("Theories_Dockable: ignoring bad message " + bad)
   166       }
   167     }
   168   }
   169 
   170   override def init()
   171   {
   172     PIDE.session.phase_changed += main_actor; handle_phase(PIDE.session.phase)
   173     PIDE.session.global_options += main_actor
   174     PIDE.session.commands_changed += main_actor; handle_update()
   175   }
   176 
   177   override def exit()
   178   {
   179     PIDE.session.phase_changed -= main_actor
   180     PIDE.session.global_options -= main_actor
   181     PIDE.session.commands_changed -= main_actor
   182   }
   183 }