src/Tools/jEdit/src/completion_popup.scala
changeset 75393 87ebf5a50283
parent 73367 77ef8bef0593
child 75394 42267c650205
equal deleted inserted replaced
75388:b3ca4a6ed74b 75393:87ebf5a50283
    22 import org.gjt.sp.jedit.textarea.{JEditTextArea, TextArea, Selection}
    22 import org.gjt.sp.jedit.textarea.{JEditTextArea, TextArea, Selection}
    23 import org.gjt.sp.jedit.gui.{HistoryTextField, KeyEventWorkaround}
    23 import org.gjt.sp.jedit.gui.{HistoryTextField, KeyEventWorkaround}
    24 import org.gjt.sp.util.StandardUtilities
    24 import org.gjt.sp.util.StandardUtilities
    25 
    25 
    26 
    26 
    27 object Completion_Popup
    27 object Completion_Popup {
    28 {
       
    29   /** items with HTML rendering **/
    28   /** items with HTML rendering **/
    30 
    29 
    31   private class Item(val item: Completion.Item)
    30   private class Item(val item: Completion.Item) {
    32   {
       
    33     private val html =
    31     private val html =
    34       item.description match {
    32       item.description match {
    35         case a :: bs =>
    33         case a :: bs =>
    36           "<html><b>" + HTML.output(Symbol.print_newlines(a)) + "</b>" +
    34           "<html><b>" + HTML.output(Symbol.print_newlines(a)) + "</b>" +
    37             HTML.output(bs.map(b => " " + Symbol.print_newlines(b)).mkString) + "</html>"
    35             HTML.output(bs.map(b => " " + Symbol.print_newlines(b)).mkString) + "</html>"
    42 
    40 
    43 
    41 
    44 
    42 
    45   /** jEdit text area **/
    43   /** jEdit text area **/
    46 
    44 
    47   object Text_Area
    45   object Text_Area {
    48   {
       
    49     private val key = new Object
    46     private val key = new Object
    50 
    47 
    51     def apply(text_area: TextArea): Option[Completion_Popup.Text_Area] =
    48     def apply(text_area: TextArea): Option[Completion_Popup.Text_Area] = {
    52     {
       
    53       GUI_Thread.require {}
    49       GUI_Thread.require {}
    54       text_area.getClientProperty(key) match {
    50       text_area.getClientProperty(key) match {
    55         case text_area_completion: Completion_Popup.Text_Area => Some(text_area_completion)
    51         case text_area_completion: Completion_Popup.Text_Area => Some(text_area_completion)
    56         case _ => None
    52         case _ => None
    57       }
    53       }
    72             text_area_completion.action(immediate = true, explicit = true, word_only = word_only)
    68             text_area_completion.action(immediate = true, explicit = true, word_only = word_only)
    73           true
    69           true
    74         case None => false
    70         case None => false
    75       }
    71       }
    76 
    72 
    77     def exit(text_area: JEditTextArea): Unit =
    73     def exit(text_area: JEditTextArea): Unit = {
    78     {
       
    79       GUI_Thread.require {}
    74       GUI_Thread.require {}
    80       apply(text_area) match {
    75       apply(text_area) match {
    81         case None =>
    76         case None =>
    82         case Some(text_area_completion) =>
    77         case Some(text_area_completion) =>
    83           text_area_completion.deactivate()
    78           text_area_completion.deactivate()
    84           text_area.putClientProperty(key, null)
    79           text_area.putClientProperty(key, null)
    85       }
    80       }
    86     }
    81     }
    87 
    82 
    88     def init(text_area: JEditTextArea): Completion_Popup.Text_Area =
    83     def init(text_area: JEditTextArea): Completion_Popup.Text_Area = {
    89     {
       
    90       exit(text_area)
    84       exit(text_area)
    91       val text_area_completion = new Text_Area(text_area)
    85       val text_area_completion = new Text_Area(text_area)
    92       text_area.putClientProperty(key, text_area_completion)
    86       text_area.putClientProperty(key, text_area_completion)
    93       text_area_completion.activate()
    87       text_area_completion.activate()
    94       text_area_completion
    88       text_area_completion
    95     }
    89     }
    96 
    90 
    97     def dismissed(text_area: TextArea): Boolean =
    91     def dismissed(text_area: TextArea): Boolean = {
    98     {
       
    99       GUI_Thread.require {}
    92       GUI_Thread.require {}
   100       apply(text_area) match {
    93       apply(text_area) match {
   101         case Some(text_area_completion) => text_area_completion.dismissed()
    94         case Some(text_area_completion) => text_area_completion.dismissed()
   102         case None => false
    95         case None => false
   103       }
    96       }
   104     }
    97     }
   105   }
    98   }
   106 
    99 
   107   class Text_Area private(text_area: JEditTextArea)
   100   class Text_Area private(text_area: JEditTextArea) {
   108   {
       
   109     // owned by GUI thread
   101     // owned by GUI thread
   110     private var completion_popup: Option[Completion_Popup] = None
   102     private var completion_popup: Option[Completion_Popup] = None
   111 
   103 
   112     def active_range: Option[Text.Range] =
   104     def active_range: Option[Text.Range] =
   113       completion_popup match {
   105       completion_popup match {
   116       }
   108       }
   117 
   109 
   118 
   110 
   119     /* rendering */
   111     /* rendering */
   120 
   112 
   121     def rendering(rendering: JEdit_Rendering, line_range: Text.Range): Option[Text.Info[Color]] =
   113     def rendering(rendering: JEdit_Rendering, line_range: Text.Range): Option[Text.Info[Color]] = {
   122     {
       
   123       active_range match {
   114       active_range match {
   124         case Some(range) => range.try_restrict(line_range)
   115         case Some(range) => range.try_restrict(line_range)
   125         case None =>
   116         case None =>
   126           val caret = text_area.getCaretPosition
   117           val caret = text_area.getCaretPosition
   127           if (line_range.contains(caret)) {
   118           if (line_range.contains(caret)) {
   149     /* syntax completion */
   140     /* syntax completion */
   150 
   141 
   151     def syntax_completion(
   142     def syntax_completion(
   152       history: Completion.History,
   143       history: Completion.History,
   153       explicit: Boolean,
   144       explicit: Boolean,
   154       opt_rendering: Option[JEdit_Rendering]): Option[Completion.Result] =
   145       opt_rendering: Option[JEdit_Rendering]
   155     {
   146     ): Option[Completion.Result] = {
   156       val buffer = text_area.getBuffer
   147       val buffer = text_area.getBuffer
   157       val unicode = Isabelle_Encoding.is_active(buffer)
   148       val unicode = Isabelle_Encoding.is_active(buffer)
   158 
   149 
   159       Isabelle.buffer_syntax(buffer) match {
   150       Isabelle.buffer_syntax(buffer) match {
   160         case Some(syntax) =>
   151         case Some(syntax) =>
   181     }
   172     }
   182 
   173 
   183 
   174 
   184     /* completion action: text area */
   175     /* completion action: text area */
   185 
   176 
   186     private def insert(item: Completion.Item): Unit =
   177     private def insert(item: Completion.Item): Unit = {
   187     {
       
   188       GUI_Thread.require {}
   178       GUI_Thread.require {}
   189 
   179 
   190       val buffer = text_area.getBuffer
   180       val buffer = text_area.getBuffer
   191       val range = item.range
   181       val range = item.range
   192       if (buffer.isEditable) {
   182       if (buffer.isEditable) {
   227 
   217 
   228     def action(
   218     def action(
   229       immediate: Boolean = false,
   219       immediate: Boolean = false,
   230       explicit: Boolean = false,
   220       explicit: Boolean = false,
   231       delayed: Boolean = false,
   221       delayed: Boolean = false,
   232       word_only: Boolean = false): Boolean =
   222       word_only: Boolean = false
   233     {
   223     ): Boolean = {
   234       val view = text_area.getView
   224       val view = text_area.getView
   235       val layered = view.getLayeredPane
   225       val layered = view.getLayeredPane
   236       val buffer = text_area.getBuffer
   226       val buffer = text_area.getBuffer
   237       val painter = text_area.getPainter
   227       val painter = text_area.getPainter
   238 
   228 
   239       val history = PIDE.plugin.completion_history.value
   229       val history = PIDE.plugin.completion_history.value
   240       val unicode = Isabelle_Encoding.is_active(buffer)
   230       val unicode = Isabelle_Encoding.is_active(buffer)
   241 
   231 
   242       def open_popup(result: Completion.Result): Unit =
   232       def open_popup(result: Completion.Result): Unit = {
   243       {
       
   244         val font =
   233         val font =
   245           painter.getFont.deriveFont(
   234           painter.getFont.deriveFont(
   246             Font_Info.main_size(PIDE.options.real("jedit_popup_font_scale")))
   235             Font_Info.main_size(PIDE.options.real("jedit_popup_font_scale")))
   247 
   236 
   248         val range = result.range
   237         val range = result.range
   253             SwingUtilities.convertPoint(painter,
   242             SwingUtilities.convertPoint(painter,
   254               loc1.x, loc1.y + painter.getLineHeight, layered)
   243               loc1.x, loc1.y + painter.getLineHeight, layered)
   255 
   244 
   256           val items = result.items.map(new Item(_))
   245           val items = result.items.map(new Item(_))
   257           val completion =
   246           val completion =
   258             new Completion_Popup(Some(range), layered, loc2, font, items)
   247             new Completion_Popup(Some(range), layered, loc2, font, items) {
   259             {
   248               override def complete(item: Completion.Item): Unit = {
   260               override def complete(item: Completion.Item): Unit =
       
   261               {
       
   262                 PIDE.plugin.completion_history.update(item)
   249                 PIDE.plugin.completion_history.update(item)
   263                 insert(item)
   250                 insert(item)
   264               }
   251               }
   265               override def propagate(evt: KeyEvent): Unit =
   252               override def propagate(evt: KeyEvent): Unit = {
   266               {
       
   267                 if (view.getKeyEventInterceptor == null)
   253                 if (view.getKeyEventInterceptor == null)
   268                   JEdit_Lib.propagate_key(view, evt)
   254                   JEdit_Lib.propagate_key(view, evt)
   269                 else if (view.getKeyEventInterceptor == inner_key_listener) {
   255                 else if (view.getKeyEventInterceptor == inner_key_listener) {
   270                   try {
   256                   try {
   271                     view.setKeyEventInterceptor(null)
   257                     view.setKeyEventInterceptor(null)
   275                     if (isDisplayable) view.setKeyEventInterceptor(inner_key_listener)
   261                     if (isDisplayable) view.setKeyEventInterceptor(inner_key_listener)
   276                   }
   262                   }
   277                 }
   263                 }
   278                 if (evt.getID == KeyEvent.KEY_TYPED) input(evt)
   264                 if (evt.getID == KeyEvent.KEY_TYPED) input(evt)
   279               }
   265               }
   280               override def shutdown(focus: Boolean): Unit =
   266               override def shutdown(focus: Boolean): Unit = {
   281               {
       
   282                 if (view.getKeyEventInterceptor == inner_key_listener)
   267                 if (view.getKeyEventInterceptor == inner_key_listener)
   283                   view.setKeyEventInterceptor(null)
   268                   view.setKeyEventInterceptor(null)
   284                 if (focus) text_area.requestFocus()
   269                 if (focus) text_area.requestFocus()
   285                 JEdit_Lib.invalidate_range(text_area, range)
   270                 JEdit_Lib.invalidate_range(text_area, range)
   286               }
   271               }
   296 
   281 
   297       if (buffer.isEditable) {
   282       if (buffer.isEditable) {
   298         val caret = text_area.getCaretPosition
   283         val caret = text_area.getCaretPosition
   299         val opt_rendering = Document_View.get(text_area).map(_.get_rendering())
   284         val opt_rendering = Document_View.get(text_area).map(_.get_rendering())
   300         val result0 = syntax_completion(history, explicit, opt_rendering)
   285         val result0 = syntax_completion(history, explicit, opt_rendering)
   301         val (no_completion, semantic_completion) =
   286         val (no_completion, semantic_completion) = {
   302         {
       
   303           opt_rendering match {
   287           opt_rendering match {
   304             case Some(rendering) =>
   288             case Some(rendering) =>
   305               rendering.semantic_completion_result(history, unicode, result0.map(_.range),
   289               rendering.semantic_completion_result(history, unicode, result0.map(_.range),
   306                 rendering.before_caret_range(caret))
   290                 rendering.before_caret_range(caret))
   307             case None => (false, None)
   291             case None => (false, None)
   308           }
   292           }
   309         }
   293         }
   310         if (no_completion) false
   294         if (no_completion) false
   311         else {
   295         else {
   312           val result =
   296           val result = {
   313           {
       
   314             val result1 =
   297             val result1 =
   315               if (word_only) None
   298               if (word_only) None
   316               else Completion.Result.merge(history, semantic_completion, result0)
   299               else Completion.Result.merge(history, semantic_completion, result0)
   317             opt_rendering match {
   300             opt_rendering match {
   318               case None => result1
   301               case None => result1
   343     }
   326     }
   344 
   327 
   345 
   328 
   346     /* input key events */
   329     /* input key events */
   347 
   330 
   348     def input(evt: KeyEvent): Unit =
   331     def input(evt: KeyEvent): Unit = {
   349     {
       
   350       GUI_Thread.require {}
   332       GUI_Thread.require {}
   351 
   333 
   352       if (!evt.isConsumed) {
   334       if (!evt.isConsumed) {
   353         val special = JEdit_Lib.special_key(evt)
   335         val special = JEdit_Lib.special_key(evt)
   354 
   336 
   381       }
   363       }
   382 
   364 
   383 
   365 
   384     /* dismiss popup */
   366     /* dismiss popup */
   385 
   367 
   386     def dismissed(): Boolean =
   368     def dismissed(): Boolean = {
   387     {
       
   388       GUI_Thread.require {}
   369       GUI_Thread.require {}
   389 
   370 
   390       completion_popup match {
   371       completion_popup match {
   391         case Some(completion) =>
   372         case Some(completion) =>
   392           completion.hide_popup()
   373           completion.hide_popup()
   404       JEdit_Lib.key_listener(key_typed = input)
   385       JEdit_Lib.key_listener(key_typed = input)
   405 
   386 
   406     private def activate(): Unit =
   387     private def activate(): Unit =
   407       text_area.addKeyListener(outer_key_listener)
   388       text_area.addKeyListener(outer_key_listener)
   408 
   389 
   409     private def deactivate(): Unit =
   390     private def deactivate(): Unit = {
   410     {
       
   411       dismissed()
   391       dismissed()
   412       text_area.removeKeyListener(outer_key_listener)
   392       text_area.removeKeyListener(outer_key_listener)
   413     }
   393     }
   414   }
   394   }
   415 
   395 
   420   class History_Text_Field(
   400   class History_Text_Field(
   421     name: String = null,
   401     name: String = null,
   422     instant_popups: Boolean = false,
   402     instant_popups: Boolean = false,
   423     enter_adds_to_history: Boolean = true,
   403     enter_adds_to_history: Boolean = true,
   424     syntax: Outer_Syntax = Outer_Syntax.empty) extends
   404     syntax: Outer_Syntax = Outer_Syntax.empty) extends
   425     HistoryTextField(name, instant_popups, enter_adds_to_history)
   405     HistoryTextField(name, instant_popups, enter_adds_to_history
   426   {
   406   ) {
   427     text_field =>
   407     text_field =>
   428 
   408 
   429     // see https://forums.oracle.com/thread/1361677
   409     // see https://forums.oracle.com/thread/1361677
   430     if (GUI.is_macos_laf) text_field.setCaret(new DefaultCaret)
   410     if (GUI.is_macos_laf) text_field.setCaret(new DefaultCaret)
   431 
   411 
   433     private var completion_popup: Option[Completion_Popup] = None
   413     private var completion_popup: Option[Completion_Popup] = None
   434 
   414 
   435 
   415 
   436     /* dismiss */
   416     /* dismiss */
   437 
   417 
   438     private def dismissed(): Boolean =
   418     private def dismissed(): Boolean = {
   439     {
       
   440       completion_popup match {
   419       completion_popup match {
   441         case Some(completion) =>
   420         case Some(completion) =>
   442           completion.hide_popup()
   421           completion.hide_popup()
   443           completion_popup = None
   422           completion_popup = None
   444           true
   423           true
   448     }
   427     }
   449 
   428 
   450 
   429 
   451     /* insert */
   430     /* insert */
   452 
   431 
   453     private def insert(item: Completion.Item): Unit =
   432     private def insert(item: Completion.Item): Unit = {
   454     {
       
   455       GUI_Thread.require {}
   433       GUI_Thread.require {}
   456 
   434 
   457       val range = item.range
   435       val range = item.range
   458       if (text_field.isEditable) {
   436       if (text_field.isEditable) {
   459         val content = text_field.getText
   437         val content = text_field.getText
   470     }
   448     }
   471 
   449 
   472 
   450 
   473     /* completion action: text field */
   451     /* completion action: text field */
   474 
   452 
   475     def action(): Unit =
   453     def action(): Unit = {
   476     {
       
   477       GUI.layered_pane(text_field) match {
   454       GUI.layered_pane(text_field) match {
   478         case Some(layered) if text_field.isEditable =>
   455         case Some(layered) if text_field.isEditable =>
   479           val history = PIDE.plugin.completion_history.value
   456           val history = PIDE.plugin.completion_history.value
   480 
   457 
   481           val caret = text_field.getCaret.getDot
   458           val caret = text_field.getCaret.getDot
   489               val loc =
   466               val loc =
   490                 SwingUtilities.convertPoint(text_field, fm.stringWidth(text), fm.getHeight, layered)
   467                 SwingUtilities.convertPoint(text_field, fm.stringWidth(text), fm.getHeight, layered)
   491 
   468 
   492               val items = result.items.map(new Item(_))
   469               val items = result.items.map(new Item(_))
   493               val completion =
   470               val completion =
   494                 new Completion_Popup(None, layered, loc, text_field.getFont, items)
   471                 new Completion_Popup(None, layered, loc, text_field.getFont, items) {
   495                 {
   472                   override def complete(item: Completion.Item): Unit = {
   496                   override def complete(item: Completion.Item): Unit =
       
   497                   {
       
   498                     PIDE.plugin.completion_history.update(item)
   473                     PIDE.plugin.completion_history.update(item)
   499                     insert(item)
   474                     insert(item)
   500                   }
   475                   }
   501                   override def propagate(evt: KeyEvent): Unit =
   476                   override def propagate(evt: KeyEvent): Unit =
   502                     if (!evt.isConsumed) text_field.processKeyEvent(evt)
   477                     if (!evt.isConsumed) text_field.processKeyEvent(evt)
   514     }
   489     }
   515 
   490 
   516 
   491 
   517     /* process key event */
   492     /* process key event */
   518 
   493 
   519     private def process(evt: KeyEvent): Unit =
   494     private def process(evt: KeyEvent): Unit = {
   520     {
       
   521       if (PIDE.options.bool("jedit_completion")) {
   495       if (PIDE.options.bool("jedit_completion")) {
   522         dismissed()
   496         dismissed()
   523         if (evt.getKeyChar != '\b') {
   497         if (evt.getKeyChar != '\b') {
   524           val special = JEdit_Lib.special_key(evt)
   498           val special = JEdit_Lib.special_key(evt)
   525           if (PIDE.options.seconds("jedit_completion_delay").is_zero && !special) {
   499           if (PIDE.options.seconds("jedit_completion_delay").is_zero && !special) {
   534     private val process_delay =
   508     private val process_delay =
   535       Delay.last(PIDE.options.seconds("jedit_completion_delay"), gui = true) {
   509       Delay.last(PIDE.options.seconds("jedit_completion_delay"), gui = true) {
   536         action()
   510         action()
   537       }
   511       }
   538 
   512 
   539     override def processKeyEvent(evt0: KeyEvent): Unit =
   513     override def processKeyEvent(evt0: KeyEvent): Unit = {
   540     {
       
   541       val evt = KeyEventWorkaround.processKeyEvent(evt0)
   514       val evt = KeyEventWorkaround.processKeyEvent(evt0)
   542       if (evt != null) {
   515       if (evt != null) {
   543         evt.getID match {
   516         evt.getID match {
   544           case KeyEvent.KEY_PRESSED =>
   517           case KeyEvent.KEY_PRESSED =>
   545             val key_code = evt.getKeyCode
   518             val key_code = evt.getKeyCode
   562 class Completion_Popup private(
   535 class Completion_Popup private(
   563   opt_range: Option[Text.Range],
   536   opt_range: Option[Text.Range],
   564   layered: JLayeredPane,
   537   layered: JLayeredPane,
   565   location: Point,
   538   location: Point,
   566   font: Font,
   539   font: Font,
   567   items: List[Completion_Popup.Item]) extends JPanel(new BorderLayout)
   540   items: List[Completion_Popup.Item]
   568 {
   541 ) extends JPanel(new BorderLayout) {
   569   completion =>
   542   completion =>
   570 
   543 
   571   GUI_Thread.require {}
   544   GUI_Thread.require {}
   572 
   545 
   573   require(items.nonEmpty, "no completion items")
   546   require(items.nonEmpty, "no completion items")
   593   for (cond <-
   566   for (cond <-
   594     List(JComponent.WHEN_FOCUSED,
   567     List(JComponent.WHEN_FOCUSED,
   595       JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
   568       JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
   596       JComponent.WHEN_IN_FOCUSED_WINDOW)) list_view.peer.setInputMap(cond, null)
   569       JComponent.WHEN_IN_FOCUSED_WINDOW)) list_view.peer.setInputMap(cond, null)
   597 
   570 
   598   private def complete_selected(): Boolean =
   571   private def complete_selected(): Boolean = {
   599   {
       
   600     list_view.selection.items.toList match {
   572     list_view.selection.items.toList match {
   601       case item :: _ => complete(item.item); true
   573       case item :: _ => complete(item.item); true
   602       case _ => false
   574       case _ => false
   603     }
   575     }
   604   }
   576   }
   605 
   577 
   606   private def move_items(n: Int): Unit =
   578   private def move_items(n: Int): Unit = {
   607   {
       
   608     val i = list_view.peer.getSelectedIndex
   579     val i = list_view.peer.getSelectedIndex
   609     val j = ((i + n) min (items.length - 1)) max 0
   580     val j = ((i + n) min (items.length - 1)) max 0
   610     if (i != j) {
   581     if (i != j) {
   611       list_view.peer.setSelectedIndex(j)
   582       list_view.peer.setSelectedIndex(j)
   612       list_view.peer.ensureIndexIsVisible(j)
   583       list_view.peer.ensureIndexIsVisible(j)
   613     }
   584     }
   614   }
   585   }
   615 
   586 
   616   private def move_pages(n: Int): Unit =
   587   private def move_pages(n: Int): Unit = {
   617   {
       
   618     val page_size = list_view.peer.getVisibleRowCount - 1
   588     val page_size = list_view.peer.getVisibleRowCount - 1
   619     move_items(page_size * n)
   589     move_items(page_size * n)
   620   }
   590   }
   621 
   591 
   622 
   592 
   623   /* event handling */
   593   /* event handling */
   624 
   594 
   625   val inner_key_listener: KeyListener =
   595   val inner_key_listener: KeyListener =
   626     JEdit_Lib.key_listener(
   596     JEdit_Lib.key_listener(
   627       key_pressed = (e: KeyEvent) =>
   597       key_pressed = (e: KeyEvent) => {
   628         {
   598         if (!e.isConsumed) {
   629           if (!e.isConsumed) {
   599           e.getKeyCode match {
   630             e.getKeyCode match {
   600             case KeyEvent.VK_ENTER if PIDE.options.bool("jedit_completion_select_enter") =>
   631               case KeyEvent.VK_ENTER if PIDE.options.bool("jedit_completion_select_enter") =>
   601               if (complete_selected()) e.consume
   632                 if (complete_selected()) e.consume
   602               hide_popup()
       
   603             case KeyEvent.VK_TAB if PIDE.options.bool("jedit_completion_select_tab") =>
       
   604               if (complete_selected()) e.consume
       
   605               hide_popup()
       
   606             case KeyEvent.VK_ESCAPE =>
       
   607               hide_popup()
       
   608               e.consume
       
   609             case KeyEvent.VK_UP | KeyEvent.VK_KP_UP if multi =>
       
   610               move_items(-1)
       
   611               e.consume
       
   612             case KeyEvent.VK_DOWN | KeyEvent.VK_KP_DOWN if multi =>
       
   613               move_items(1)
       
   614               e.consume
       
   615             case KeyEvent.VK_PAGE_UP if multi =>
       
   616               move_pages(-1)
       
   617               e.consume
       
   618             case KeyEvent.VK_PAGE_DOWN if multi =>
       
   619               move_pages(1)
       
   620               e.consume
       
   621             case _ =>
       
   622               if (e.isActionKey || e.isAltDown || e.isMetaDown || e.isControlDown)
   633                 hide_popup()
   623                 hide_popup()
   634               case KeyEvent.VK_TAB if PIDE.options.bool("jedit_completion_select_tab") =>
   624           }
   635                 if (complete_selected()) e.consume
   625         }
   636                 hide_popup()
   626         propagate(e)
   637               case KeyEvent.VK_ESCAPE =>
   627       },
   638                 hide_popup()
       
   639                 e.consume
       
   640               case KeyEvent.VK_UP | KeyEvent.VK_KP_UP if multi =>
       
   641                 move_items(-1)
       
   642                 e.consume
       
   643               case KeyEvent.VK_DOWN | KeyEvent.VK_KP_DOWN if multi =>
       
   644                 move_items(1)
       
   645                 e.consume
       
   646               case KeyEvent.VK_PAGE_UP if multi =>
       
   647                 move_pages(-1)
       
   648                 e.consume
       
   649               case KeyEvent.VK_PAGE_DOWN if multi =>
       
   650                 move_pages(1)
       
   651                 e.consume
       
   652               case _ =>
       
   653                 if (e.isActionKey || e.isAltDown || e.isMetaDown || e.isControlDown)
       
   654                   hide_popup()
       
   655             }
       
   656           }
       
   657           propagate(e)
       
   658         },
       
   659       key_typed = propagate
   628       key_typed = propagate
   660     )
   629     )
   661 
   630 
   662   list_view.peer.addKeyListener(inner_key_listener)
   631   list_view.peer.addKeyListener(inner_key_listener)
   663 
   632 
   664   list_view.peer.addMouseListener(new MouseAdapter {
   633   list_view.peer.addMouseListener(new MouseAdapter {
   665     override def mouseClicked(e: MouseEvent): Unit =
   634     override def mouseClicked(e: MouseEvent): Unit = {
   666     {
       
   667       if (complete_selected()) e.consume
   635       if (complete_selected()) e.consume
   668       hide_popup()
   636       hide_popup()
   669     }
   637     }
   670   })
   638   })
   671 
   639 
   684   /* popup */
   652   /* popup */
   685 
   653 
   686   def active_range: Option[Text.Range] =
   654   def active_range: Option[Text.Range] =
   687     if (isDisplayable) opt_range else None
   655     if (isDisplayable) opt_range else None
   688 
   656 
   689   private val popup =
   657   private val popup = {
   690   {
       
   691     val screen = GUI.screen_location(layered, location)
   658     val screen = GUI.screen_location(layered, location)
   692     val size =
   659     val size = {
   693     {
       
   694       val geometry = JEdit_Lib.window_geometry(completion, completion)
   660       val geometry = JEdit_Lib.window_geometry(completion, completion)
   695       val bounds = JEdit_Rendering.popup_bounds
   661       val bounds = JEdit_Rendering.popup_bounds
   696       val w = geometry.width min (screen.bounds.width * bounds).toInt min layered.getWidth
   662       val w = geometry.width min (screen.bounds.width * bounds).toInt min layered.getWidth
   697       val h = geometry.height min (screen.bounds.height * bounds).toInt min layered.getHeight
   663       val h = geometry.height min (screen.bounds.height * bounds).toInt min layered.getHeight
   698       new Dimension(w, h)
   664       new Dimension(w, h)
   699     }
   665     }
   700     new Popup(layered, completion, screen.relative(layered, size), size)
   666     new Popup(layered, completion, screen.relative(layered, size), size)
   701   }
   667   }
   702 
   668 
   703   private def show_popup(focus: Boolean): Unit =
   669   private def show_popup(focus: Boolean): Unit = {
   704   {
       
   705     popup.show
   670     popup.show
   706     if (focus) list_view.requestFocus()
   671     if (focus) list_view.requestFocus()
   707   }
   672   }
   708 
   673 
   709   private def hide_popup(): Unit =
   674   private def hide_popup(): Unit = {
   710   {
       
   711     shutdown(list_view.peer.isFocusOwner)
   675     shutdown(list_view.peer.isFocusOwner)
   712     popup.hide
   676     popup.hide
   713   }
   677   }
   714 }
   678 }