src/Tools/jEdit/src/completion_popup.scala
author wenzelm
Mon, 17 Mar 2014 23:16:26 +0100
changeset 56197 416f7a00e4cb
parent 56177 bfa9dfb722de
child 56325 ffbfc92e6508
permissions -rw-r--r--
back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups; discontinued obsolete option jedit_completion_dismiss_delay (see 750561986828); more explicit shutdown;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
     1
/*  Title:      Tools/jEdit/src/completion_popup.scala
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
     3
53246
8d34caf5bf82 more elementary Popup via JLayeredPane -- avoid javax.swing.PopupFactory with its many problems and dangers of accidental HeavyWeightPopup (especially on Mac OS X);
wenzelm
parents: 53244
diff changeset
     4
Completion popup.
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
     5
*/
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
     6
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
     7
package isabelle.jedit
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
     8
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
     9
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    10
import isabelle._
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    11
53297
64c31de7f21c border as for Pretty_Tooltip;
wenzelm
parents: 53296
diff changeset
    12
import java.awt.{Color, Font, Point, BorderLayout, Dimension}
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
    13
import java.awt.event.{KeyEvent, MouseEvent, MouseAdapter, FocusAdapter, FocusEvent}
53246
8d34caf5bf82 more elementary Popup via JLayeredPane -- avoid javax.swing.PopupFactory with its many problems and dangers of accidental HeavyWeightPopup (especially on Mac OS X);
wenzelm
parents: 53244
diff changeset
    14
import javax.swing.{JPanel, JComponent, JLayeredPane, SwingUtilities}
53297
64c31de7f21c border as for Pretty_Tooltip;
wenzelm
parents: 53296
diff changeset
    15
import javax.swing.border.LineBorder
53848
8d7029eb0c31 disable standard behaviour of Mac OS X text field (i.e. select-all after focus gain) in order to make completion work more smoothly;
wenzelm
parents: 53784
diff changeset
    16
import javax.swing.text.DefaultCaret
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    17
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    18
import scala.swing.{ListView, ScrollPane}
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    19
import scala.swing.event.MouseClicked
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    20
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
    21
import org.gjt.sp.jedit.View
55712
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    22
import org.gjt.sp.jedit.textarea.{JEditTextArea, TextArea}
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
    23
import org.gjt.sp.jedit.gui.{HistoryTextField, KeyEventWorkaround}
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    24
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    25
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    26
object Completion_Popup
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
    27
{
55978
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    28
  /** items with HTML rendering **/
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    29
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    30
  private class Item(val item: Completion.Item)
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    31
  {
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    32
    private val html =
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    33
      item.description match {
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    34
        case a :: bs =>
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    35
          "<html><b>" + HTML.encode(a) + "</b>" +
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    36
            HTML.encode(bs.map(" " + _).mkString) + "</html>"
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    37
        case Nil => ""
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    38
      }
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    39
    override def toString: String = html
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    40
  }
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    41
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    42
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
    43
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
    44
  /** jEdit text area **/
53235
1b6a44859549 register single instance within root, in order to get rid of old popup as user continues typing;
wenzelm
parents: 53234
diff changeset
    45
53242
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
    46
  object Text_Area
53233
4b422e5d64fd some actual completion via outer syntax;
wenzelm
parents: 53232
diff changeset
    47
  {
53274
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    48
    private val key = new Object
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    49
55712
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    50
    def apply(text_area: TextArea): Option[Completion_Popup.Text_Area] =
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    51
    {
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    52
      Swing_Thread.require()
53274
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    53
      text_area.getClientProperty(key) match {
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    54
        case text_area_completion: Completion_Popup.Text_Area => Some(text_area_completion)
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    55
        case _ => None
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    56
      }
55712
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    57
    }
53274
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    58
55712
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    59
    def active_range(text_area: TextArea): Option[Text.Range] =
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    60
      apply(text_area) match {
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    61
        case Some(text_area_completion) => text_area_completion.active_range
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    62
        case None => None
55711
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
    63
      }
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
    64
56170
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
    65
    def action(text_area: TextArea): Boolean =
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
    66
      apply(text_area) match {
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
    67
        case Some(text_area_completion) =>
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
    68
          if (text_area_completion.active_range.isDefined)
56177
bfa9dfb722de proper flags for main action (amending 638b29331549);
wenzelm
parents: 56175
diff changeset
    69
            text_area_completion.action()
bfa9dfb722de proper flags for main action (amending 638b29331549);
wenzelm
parents: 56175
diff changeset
    70
          else
56170
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
    71
            text_area_completion.action(immediate = true, explicit = true)
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
    72
          true
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
    73
        case None => false
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
    74
      }
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
    75
53274
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    76
    def exit(text_area: JEditTextArea)
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    77
    {
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    78
      Swing_Thread.require()
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    79
      apply(text_area) match {
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    80
        case None =>
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    81
        case Some(text_area_completion) =>
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    82
          text_area_completion.deactivate()
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    83
          text_area.putClientProperty(key, null)
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    84
      }
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    85
    }
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    86
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    87
    def init(text_area: JEditTextArea): Completion_Popup.Text_Area =
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    88
    {
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    89
      exit(text_area)
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    90
      val text_area_completion = new Text_Area(text_area)
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    91
      text_area.putClientProperty(key, text_area_completion)
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    92
      text_area_completion.activate()
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    93
      text_area_completion
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    94
    }
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    95
55712
e757e8c8d8ea tuned signature -- weaker type requirement;
wenzelm
parents: 55711
diff changeset
    96
    def dismissed(text_area: TextArea): Boolean =
53274
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    97
    {
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    98
      Swing_Thread.require()
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
    99
      apply(text_area) match {
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   100
        case Some(text_area_completion) => text_area_completion.dismissed()
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   101
        case None => false
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   102
      }
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   103
    }
53272
0dfd78ff7696 more abstract Completion_Popup.Text_Area;
wenzelm
parents: 53247
diff changeset
   104
  }
0dfd78ff7696 more abstract Completion_Popup.Text_Area;
wenzelm
parents: 53247
diff changeset
   105
53274
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   106
  class Text_Area private(text_area: JEditTextArea)
53272
0dfd78ff7696 more abstract Completion_Popup.Text_Area;
wenzelm
parents: 53247
diff changeset
   107
  {
55711
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   108
    // owned by Swing thread
53272
0dfd78ff7696 more abstract Completion_Popup.Text_Area;
wenzelm
parents: 53247
diff changeset
   109
    private var completion_popup: Option[Completion_Popup] = None
0dfd78ff7696 more abstract Completion_Popup.Text_Area;
wenzelm
parents: 53247
diff changeset
   110
55711
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   111
    def active_range: Option[Text.Range] =
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   112
      completion_popup match {
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   113
        case Some(completion) =>
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   114
          completion.active_range match {
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   115
            case Some(range) if completion.isDisplayable => Some(range)
55711
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   116
            case _ => None
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   117
          }
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   118
        case None => None
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   119
      }
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   120
53272
0dfd78ff7696 more abstract Completion_Popup.Text_Area;
wenzelm
parents: 53247
diff changeset
   121
55767
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   122
    /* caret */
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   123
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   124
    def before_caret_range(rendering: Rendering): Text.Range =
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   125
    {
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   126
      val snapshot = rendering.snapshot
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   127
      val former_caret = snapshot.revert(text_area.getCaretPosition)
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   128
      snapshot.convert(Text.Range(former_caret - 1, former_caret))
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   129
    }
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   130
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   131
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   132
    /* rendering */
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   133
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   134
    def rendering(rendering: Rendering, line_range: Text.Range): Option[Text.Info[Color]] =
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   135
    {
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   136
      active_range match {
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   137
        case Some(range) => range.try_restrict(line_range)
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   138
        case None =>
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   139
          val buffer = text_area.getBuffer
55767
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   140
          if (line_range.contains(text_area.getCaretPosition)) {
96ddf9bf12ac more precise before_caret_range (looking both in space and time);
wenzelm
parents: 55752
diff changeset
   141
            before_caret_range(rendering).try_restrict(line_range) match {
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   142
              case Some(range) if !range.is_singularity =>
56173
62f10624339a tuned signature;
wenzelm
parents: 56171
diff changeset
   143
                rendering.semantic_completion(range) match {
56175
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   144
                  case Some(Text.Info(_, Completion.No_Completion)) => None
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   145
                  case Some(Text.Info(range1, _: Completion.Names)) => Some(range1)
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   146
                  case None =>
56175
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   147
                    syntax_completion(Completion.History.empty, false, Some(rendering)).map(_.range)
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   148
                }
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   149
              case _ => None
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   150
            }
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   151
          }
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   152
          else None
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   153
      }
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   154
    }.map(range => Text.Info(range, rendering.completion_color))
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   155
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   156
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   157
    /* syntax completion */
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   158
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   159
    def syntax_completion(
56175
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   160
      history: Completion.History,
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   161
      explicit: Boolean,
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   162
      opt_rendering: Option[Rendering]): Option[Completion.Result] =
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   163
    {
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   164
      val buffer = text_area.getBuffer
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   165
      val decode = Isabelle_Encoding.is_active(buffer)
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   166
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   167
      Isabelle.mode_syntax(JEdit_Lib.buffer_mode(buffer)) match {
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   168
        case Some(syntax) =>
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   169
          val caret = text_area.getCaretPosition
55813
08a1c860bc12 allow completion within a word (or symbol), like semantic completion;
wenzelm
parents: 55767
diff changeset
   170
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   171
          val line = buffer.getLineOfOffset(caret)
55813
08a1c860bc12 allow completion within a word (or symbol), like semantic completion;
wenzelm
parents: 55767
diff changeset
   172
          val line_start = buffer.getLineStartOffset(line)
08a1c860bc12 allow completion within a word (or symbol), like semantic completion;
wenzelm
parents: 55767
diff changeset
   173
          val line_length = (buffer.getLineEndOffset(line) min buffer.getLength) - line_start
08a1c860bc12 allow completion within a word (or symbol), like semantic completion;
wenzelm
parents: 55767
diff changeset
   174
          val line_text = buffer.getSegment(line_start, line_length)
55748
2e1398b484aa no word completion within word context;
wenzelm
parents: 55747
diff changeset
   175
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   176
          val context =
56175
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   177
            (opt_rendering match {
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   178
              case Some(rendering) =>
56173
62f10624339a tuned signature;
wenzelm
parents: 56171
diff changeset
   179
                rendering.language_context(before_caret_range(rendering))
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   180
              case None => None
55749
75a48dc4383e tuned signature;
wenzelm
parents: 55748
diff changeset
   181
            }) getOrElse syntax.language_context
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   182
55813
08a1c860bc12 allow completion within a word (or symbol), like semantic completion;
wenzelm
parents: 55767
diff changeset
   183
          syntax.completion.complete(
55850
7f229b0212fe no extend_word for now, it is in conflict with manual reformatting of sources via TAB (e.g. accidental replacement of 'assume' by 'assumes');
wenzelm
parents: 55828
diff changeset
   184
            history, decode, explicit, line_start, line_text, caret - line_start, false, context)
55747
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   185
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   186
        case None => None
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   187
      }
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   188
    }
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   189
bef19c929ba5 more completion rendering: active, semantic, syntactic;
wenzelm
parents: 55712
diff changeset
   190
56170
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
   191
    /* completion action: text area */
53273
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   192
53275
b34aac6511ab tuned signature;
wenzelm
parents: 53274
diff changeset
   193
    private def insert(item: Completion.Item)
53242
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   194
    {
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   195
      Swing_Thread.require()
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   196
53242
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   197
      val buffer = text_area.getBuffer
55692
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   198
      val range = item.range
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   199
      if (buffer.isEditable && range.length > 0) {
53242
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   200
        JEdit_Lib.buffer_edit(buffer) {
55692
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   201
          JEdit_Lib.try_get_text(buffer, range) match {
53242
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   202
            case Some(text) if text == item.original =>
55692
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   203
              buffer.remove(range.start, range.length)
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   204
              buffer.insert(range.start, item.replacement)
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   205
              text_area.moveCaretPosition(range.start + item.replacement.length + item.move)
53242
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   206
            case _ =>
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   207
          }
53233
4b422e5d64fd some actual completion via outer syntax;
wenzelm
parents: 53232
diff changeset
   208
        }
4b422e5d64fd some actual completion via outer syntax;
wenzelm
parents: 53232
diff changeset
   209
      }
4b422e5d64fd some actual completion via outer syntax;
wenzelm
parents: 53232
diff changeset
   210
    }
53242
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   211
53322
a4cd032172e0 allow short words for explicit completion;
wenzelm
parents: 53297
diff changeset
   212
    def action(immediate: Boolean = false, explicit: Boolean = false)
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   213
    {
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   214
      val view = text_area.getView
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   215
      val layered = view.getLayeredPane
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   216
      val buffer = text_area.getBuffer
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   217
      val painter = text_area.getPainter
53273
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   218
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   219
      val history = PIDE.completion_history.value
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   220
      val decode = Isabelle_Encoding.is_active(buffer)
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   221
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   222
      def open_popup(result: Completion.Result)
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   223
      {
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   224
        val font =
55825
694833e3e4a0 tuned signature -- separate module Font_Info;
wenzelm
parents: 55813
diff changeset
   225
          painter.getFont.deriveFont(
694833e3e4a0 tuned signature -- separate module Font_Info;
wenzelm
parents: 55813
diff changeset
   226
            Font_Info.main_size(PIDE.options.real("jedit_popup_font_scale")))
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   227
55711
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   228
        val range = result.range
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   229
        def invalidate(): Unit = JEdit_Lib.invalidate_range(text_area, range)
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   230
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   231
        val loc1 = text_area.offsetToXY(range.start)
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   232
        if (loc1 != null) {
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   233
          val loc2 =
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   234
            SwingUtilities.convertPoint(painter,
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   235
              loc1.x, loc1.y + painter.getFontMetrics.getHeight, layered)
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   236
55978
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   237
          val items = result.items.map(new Item(_))
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   238
          val completion =
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   239
            new Completion_Popup(Some(range), layered, loc2, font, items)
55978
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   240
            {
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   241
              override def complete(item: Completion.Item) {
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   242
                PIDE.completion_history.update(item)
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   243
                insert(item)
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   244
              }
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   245
              override def propagate(evt: KeyEvent) {
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   246
                if (view.getKeyEventInterceptor == inner_key_listener) {
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   247
                  try {
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   248
                    view.setKeyEventInterceptor(null)
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   249
                    JEdit_Lib.propagate_key(view, evt)
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   250
                  }
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   251
                  finally {
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   252
                    if (isDisplayable) view.setKeyEventInterceptor(inner_key_listener)
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   253
                  }
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   254
                }
56171
15351577da10 clarified key event propagation, in accordance to outer_key_listener;
wenzelm
parents: 56170
diff changeset
   255
                if (evt.getID == KeyEvent.KEY_TYPED) input(evt)
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   256
              }
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   257
              override def shutdown(focus: Boolean) {
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   258
                if (view.getKeyEventInterceptor == inner_key_listener)
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   259
                  view.setKeyEventInterceptor(null)
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   260
                if (focus) text_area.requestFocus
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   261
                invalidate()
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   262
              }
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   263
            }
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   264
          completion_popup = Some(completion)
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   265
          view.setKeyEventInterceptor(completion.inner_key_listener)
55711
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   266
          invalidate()
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   267
          completion.show_popup(false)
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   268
        }
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   269
      }
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   270
56175
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   271
      if (buffer.isEditable) {
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   272
        val (no_completion, semantic_completion, opt_rendering) =
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   273
        {
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   274
          PIDE.document_view(text_area) match {
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   275
            case Some(doc_view) =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   276
              val rendering = doc_view.get_rendering()
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   277
              val (no_completion, result) =
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   278
                rendering.semantic_completion(before_caret_range(rendering)) match {
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   279
                  case Some(Text.Info(_, Completion.No_Completion)) =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   280
                    (true, None)
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   281
                  case Some(Text.Info(range, names: Completion.Names)) =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   282
                    val result =
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   283
                      JEdit_Lib.try_get_text(buffer, range) match {
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   284
                        case Some(original) => names.complete(range, history, decode, original)
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   285
                        case None => None
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   286
                      }
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   287
                    (false, result)
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   288
                  case None =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   289
                    (false, None)
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   290
                }
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   291
              (no_completion, result, Some(rendering))
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   292
            case None =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   293
              (false, None, None)
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   294
          }
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   295
        }
56175
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   296
        if (!no_completion) {
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   297
          val result =
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   298
            Completion.Result.merge(history,
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   299
              semantic_completion, syntax_completion(history, explicit, opt_rendering))
55693
93ba0085e888 try explicit semantic completion before syntax completion;
wenzelm
parents: 55692
diff changeset
   300
56175
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   301
          result match {
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   302
            case Some(result) =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   303
              result.items match {
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   304
                case List(item) if result.unique && item.immediate && immediate =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   305
                  insert(item)
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   306
                case _ :: _ =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   307
                  open_popup(result)
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   308
                case _ =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   309
              }
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   310
            case None =>
79c29244b377 merge semantic and syntax completion;
wenzelm
parents: 56173
diff changeset
   311
          }
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   312
        }
55752
43d0e2a34c9d uniform insert vs. popup policy;
wenzelm
parents: 55749
diff changeset
   313
      }
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   314
    }
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   315
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   316
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   317
    /* input key events */
53273
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   318
53272
0dfd78ff7696 more abstract Completion_Popup.Text_Area;
wenzelm
parents: 53247
diff changeset
   319
    def input(evt: KeyEvent)
53242
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   320
    {
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   321
      Swing_Thread.require()
53233
4b422e5d64fd some actual completion via outer syntax;
wenzelm
parents: 53232
diff changeset
   322
53273
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   323
      if (PIDE.options.bool("jedit_completion")) {
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   324
        if (!evt.isConsumed) {
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   325
          dismissed()
53397
b179cdfa9d82 no completion on backspace -- too intrusive, e.g. when deleting keywords;
wenzelm
parents: 53337
diff changeset
   326
          if (evt.getKeyChar != '\b') {
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   327
            val special = JEdit_Lib.special_key(evt)
53397
b179cdfa9d82 no completion on backspace -- too intrusive, e.g. when deleting keywords;
wenzelm
parents: 53337
diff changeset
   328
            if (PIDE.options.seconds("jedit_completion_delay").is_zero && !special) {
b179cdfa9d82 no completion on backspace -- too intrusive, e.g. when deleting keywords;
wenzelm
parents: 53337
diff changeset
   329
              input_delay.revoke()
b179cdfa9d82 no completion on backspace -- too intrusive, e.g. when deleting keywords;
wenzelm
parents: 53337
diff changeset
   330
              action(immediate = PIDE.options.bool("jedit_completion_immediate"))
b179cdfa9d82 no completion on backspace -- too intrusive, e.g. when deleting keywords;
wenzelm
parents: 53337
diff changeset
   331
            }
b179cdfa9d82 no completion on backspace -- too intrusive, e.g. when deleting keywords;
wenzelm
parents: 53337
diff changeset
   332
            else input_delay.invoke()
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   333
          }
53242
142f4fff4e40 tuned signature;
wenzelm
parents: 53237
diff changeset
   334
        }
53228
f6c6688961db some key event handling in the manner of SideKickBindings, SideKickCompletionPopup;
wenzelm
parents: 53226
diff changeset
   335
      }
f6c6688961db some key event handling in the manner of SideKickBindings, SideKickCompletionPopup;
wenzelm
parents: 53226
diff changeset
   336
    }
53273
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   337
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   338
    private val input_delay =
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   339
      Swing_Thread.delay_last(PIDE.options.seconds("jedit_completion_delay")) {
53322
a4cd032172e0 allow short words for explicit completion;
wenzelm
parents: 53297
diff changeset
   340
        action()
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   341
      }
53273
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   342
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   343
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   344
    /* dismiss popup */
53273
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   345
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   346
    def dismissed(): Boolean =
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   347
    {
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   348
      Swing_Thread.require()
53273
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   349
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   350
      completion_popup match {
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   351
        case Some(completion) =>
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   352
          completion.hide_popup()
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   353
          completion_popup = None
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   354
          true
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   355
        case None =>
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   356
          false
53273
473ea1ed7503 some completion options;
wenzelm
parents: 53272
diff changeset
   357
      }
53292
f567c1c7b180 option to insert unique completion immediately into buffer;
wenzelm
parents: 53275
diff changeset
   358
    }
53274
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   359
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   360
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   361
    /* activation */
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   362
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   363
    private val outer_key_listener =
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   364
      JEdit_Lib.key_listener(key_typed = input _)
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   365
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   366
    private def activate()
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   367
    {
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   368
      text_area.addKeyListener(outer_key_listener)
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   369
    }
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   370
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   371
    private def deactivate()
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   372
    {
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   373
      dismissed()
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   374
      text_area.removeKeyListener(outer_key_listener)
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   375
    }
53228
f6c6688961db some key event handling in the manner of SideKickBindings, SideKickCompletionPopup;
wenzelm
parents: 53226
diff changeset
   376
  }
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   377
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   378
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   379
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   380
  /** history text field **/
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   381
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   382
  class History_Text_Field(
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   383
    name: String = null,
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   384
    instant_popups: Boolean = false,
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   385
    enter_adds_to_history: Boolean = true,
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   386
    syntax: Outer_Syntax = Outer_Syntax.init) extends
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   387
    HistoryTextField(name, instant_popups, enter_adds_to_history)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   388
  {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   389
    text_field =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   390
53848
8d7029eb0c31 disable standard behaviour of Mac OS X text field (i.e. select-all after focus gain) in order to make completion work more smoothly;
wenzelm
parents: 53784
diff changeset
   391
    // see https://forums.oracle.com/thread/1361677
8d7029eb0c31 disable standard behaviour of Mac OS X text field (i.e. select-all after focus gain) in order to make completion work more smoothly;
wenzelm
parents: 53784
diff changeset
   392
    if (GUI.is_macos_laf) text_field.setCaret(new DefaultCaret)
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   393
55711
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   394
    // owned by Swing thread
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   395
    private var completion_popup: Option[Completion_Popup] = None
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   396
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   397
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   398
    /* dismiss */
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   399
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   400
    private def dismissed(): Boolean =
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   401
    {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   402
      completion_popup match {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   403
        case Some(completion) =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   404
          completion.hide_popup()
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   405
          completion_popup = None
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   406
          true
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   407
        case None =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   408
          false
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   409
      }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   410
    }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   411
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   412
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   413
    /* insert */
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   414
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   415
    private def insert(item: Completion.Item)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   416
    {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   417
      Swing_Thread.require()
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   418
55692
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   419
      val range = item.range
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   420
      if (text_field.isEditable && range.length > 0) {
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   421
        val content = text_field.getText
55692
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   422
        JEdit_Lib.try_get_text(content, range) match {
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   423
          case Some(text) if text == item.original =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   424
            text_field.setText(
55692
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   425
              content.substring(0, range.start) +
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   426
              item.replacement +
55692
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   427
              content.substring(range.stop))
19e8b00684f7 more explicit Completion.Item.range, independently of caret;
wenzelm
parents: 55690
diff changeset
   428
            text_field.getCaret.setDot(range.start + item.replacement.length + item.move)
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   429
          case _ =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   430
        }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   431
      }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   432
    }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   433
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   434
56170
638b29331549 allow implicit semantic completion, notably after delay that exceeds usual round-trip time;
wenzelm
parents: 55978
diff changeset
   435
    /* completion action: text field */
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   436
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   437
    def action()
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   438
    {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   439
      GUI.layered_pane(text_field) match {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   440
        case Some(layered) if text_field.isEditable =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   441
          val history = PIDE.completion_history.value
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   442
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   443
          val caret = text_field.getCaret.getDot
55813
08a1c860bc12 allow completion within a word (or symbol), like semantic completion;
wenzelm
parents: 55767
diff changeset
   444
          val text = text_field.getText
55748
2e1398b484aa no word completion within word context;
wenzelm
parents: 55747
diff changeset
   445
55749
75a48dc4383e tuned signature;
wenzelm
parents: 55748
diff changeset
   446
          val context = syntax.language_context
55748
2e1398b484aa no word completion within word context;
wenzelm
parents: 55747
diff changeset
   447
55813
08a1c860bc12 allow completion within a word (or symbol), like semantic completion;
wenzelm
parents: 55767
diff changeset
   448
          syntax.completion.complete(history, true, false, 0, text, caret, false, context) match {
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   449
            case Some(result) =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   450
              val fm = text_field.getFontMetrics(text_field.getFont)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   451
              val loc =
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   452
                SwingUtilities.convertPoint(text_field, fm.stringWidth(text), fm.getHeight, layered)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   453
55978
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   454
              val items = result.items.map(new Item(_))
55711
9e3d64e5919a paint completion range of active popup;
wenzelm
parents: 55693
diff changeset
   455
              val completion =
55978
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   456
                new Completion_Popup(None, layered, loc, text_field.getFont, items)
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   457
                {
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   458
                  override def complete(item: Completion.Item) {
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   459
                    PIDE.completion_history.update(item)
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   460
                    insert(item)
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   461
                  }
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   462
                  override def propagate(evt: KeyEvent) {
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   463
                    if (!evt.isConsumed) text_field.processKeyEvent(evt)
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   464
                  }
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   465
                  override def shutdown(focus: Boolean) { if (focus) text_field.requestFocus }
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   466
                }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   467
              completion_popup = Some(completion)
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   468
              completion.show_popup(true)
53784
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   469
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   470
            case None =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   471
          }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   472
        case _ =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   473
      }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   474
    }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   475
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   476
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   477
    /* process key event */
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   478
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   479
    private def process(evt: KeyEvent)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   480
    {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   481
      if (PIDE.options.bool("jedit_completion")) {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   482
        dismissed()
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   483
        if (evt.getKeyChar != '\b') {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   484
          val special = JEdit_Lib.special_key(evt)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   485
          if (PIDE.options.seconds("jedit_completion_delay").is_zero && !special) {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   486
            process_delay.revoke()
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   487
            action()
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   488
          }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   489
          else process_delay.invoke()
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   490
        }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   491
      }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   492
    }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   493
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   494
    private val process_delay =
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   495
      Swing_Thread.delay_last(PIDE.options.seconds("jedit_completion_delay")) {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   496
        action()
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   497
      }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   498
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   499
    override def processKeyEvent(evt0: KeyEvent)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   500
    {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   501
      val evt = KeyEventWorkaround.processKeyEvent(evt0)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   502
      if (evt != null) {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   503
        evt.getID match {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   504
          case KeyEvent.KEY_PRESSED =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   505
            val key_code = evt.getKeyCode
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   506
            if (key_code == KeyEvent.VK_ESCAPE) {
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   507
              if (dismissed()) evt.consume
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   508
            }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   509
          case KeyEvent.KEY_TYPED =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   510
            super.processKeyEvent(evt)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   511
            process(evt)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   512
            evt.consume
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   513
          case _ =>
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   514
        }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   515
        if (!evt.isConsumed) super.processKeyEvent(evt)
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   516
      }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   517
    }
322a3ff42b33 completion popup for history text field;
wenzelm
parents: 53407
diff changeset
   518
  }
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   519
}
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   520
53233
4b422e5d64fd some actual completion via outer syntax;
wenzelm
parents: 53232
diff changeset
   521
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   522
class Completion_Popup private(
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   523
  val active_range: Option[Text.Range],
53246
8d34caf5bf82 more elementary Popup via JLayeredPane -- avoid javax.swing.PopupFactory with its many problems and dangers of accidental HeavyWeightPopup (especially on Mac OS X);
wenzelm
parents: 53244
diff changeset
   524
  layered: JLayeredPane,
8d34caf5bf82 more elementary Popup via JLayeredPane -- avoid javax.swing.PopupFactory with its many problems and dangers of accidental HeavyWeightPopup (especially on Mac OS X);
wenzelm
parents: 53244
diff changeset
   525
  location: Point,
53272
0dfd78ff7696 more abstract Completion_Popup.Text_Area;
wenzelm
parents: 53247
diff changeset
   526
  font: Font,
55978
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   527
  items: List[Completion_Popup.Item]) extends JPanel(new BorderLayout)
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   528
{
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   529
  completion =>
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   530
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   531
  Swing_Thread.require()
53405
ed2b48af04d9 interpret keys more movement only when needed;
wenzelm
parents: 53398
diff changeset
   532
53232
4a3762693452 tuned signature;
wenzelm
parents: 53231
diff changeset
   533
  require(!items.isEmpty)
53405
ed2b48af04d9 interpret keys more movement only when needed;
wenzelm
parents: 53398
diff changeset
   534
  val multi = items.length > 1
53232
4a3762693452 tuned signature;
wenzelm
parents: 53231
diff changeset
   535
4a3762693452 tuned signature;
wenzelm
parents: 53231
diff changeset
   536
4a3762693452 tuned signature;
wenzelm
parents: 53231
diff changeset
   537
  /* actions */
4a3762693452 tuned signature;
wenzelm
parents: 53231
diff changeset
   538
53275
b34aac6511ab tuned signature;
wenzelm
parents: 53274
diff changeset
   539
  def complete(item: Completion.Item) { }
53232
4a3762693452 tuned signature;
wenzelm
parents: 53231
diff changeset
   540
  def propagate(evt: KeyEvent) { }
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   541
  def shutdown(focus: Boolean) { }
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   542
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   543
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   544
  /* list view */
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   545
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   546
  private val list_view = new ListView(items)
53272
0dfd78ff7696 more abstract Completion_Popup.Text_Area;
wenzelm
parents: 53247
diff changeset
   547
  list_view.font = font
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   548
  list_view.selection.intervalMode = ListView.IntervalMode.Single
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   549
  list_view.peer.setFocusTraversalKeysEnabled(false)
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   550
  list_view.peer.setVisibleRowCount(items.length min 8)
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   551
  list_view.peer.setSelectedIndex(0)
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   552
53398
f8b150e8778b remove Swing input map, which might bind keys in unexpected ways (e.g. LEFT/RIGHT in singleton list);
wenzelm
parents: 53397
diff changeset
   553
  for (cond <-
f8b150e8778b remove Swing input map, which might bind keys in unexpected ways (e.g. LEFT/RIGHT in singleton list);
wenzelm
parents: 53397
diff changeset
   554
    List(JComponent.WHEN_FOCUSED,
f8b150e8778b remove Swing input map, which might bind keys in unexpected ways (e.g. LEFT/RIGHT in singleton list);
wenzelm
parents: 53397
diff changeset
   555
      JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
f8b150e8778b remove Swing input map, which might bind keys in unexpected ways (e.g. LEFT/RIGHT in singleton list);
wenzelm
parents: 53397
diff changeset
   556
      JComponent.WHEN_IN_FOCUSED_WINDOW)) list_view.peer.setInputMap(cond, null)
f8b150e8778b remove Swing input map, which might bind keys in unexpected ways (e.g. LEFT/RIGHT in singleton list);
wenzelm
parents: 53397
diff changeset
   557
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   558
  private def complete_selected(): Boolean =
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   559
  {
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   560
    list_view.selection.items.toList match {
55978
56645c447ee9 tuned description and its rendering;
wenzelm
parents: 55914
diff changeset
   561
      case item :: _ => complete(item.item); true
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   562
      case _ => false
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   563
    }
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   564
  }
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   565
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   566
  private def move_items(n: Int)
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   567
  {
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   568
    val i = list_view.peer.getSelectedIndex
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   569
    val j = ((i + n) min (items.length - 1)) max 0
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   570
    if (i != j) {
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   571
      list_view.peer.setSelectedIndex(j)
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   572
      list_view.peer.ensureIndexIsVisible(j)
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   573
    }
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   574
  }
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   575
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   576
  private def move_pages(n: Int)
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   577
  {
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   578
    val page_size = list_view.peer.getVisibleRowCount - 1
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   579
    move_items(page_size * n)
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   580
  }
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   581
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   582
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   583
  /* event handling */
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   584
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   585
  val inner_key_listener =
53226
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   586
    JEdit_Lib.key_listener(
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   587
      key_pressed = (e: KeyEvent) =>
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   588
        {
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   589
          if (!e.isConsumed) {
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   590
            e.getKeyCode match {
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   591
              case KeyEvent.VK_TAB =>
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   592
                if (complete_selected()) e.consume
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   593
                hide_popup()
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   594
              case KeyEvent.VK_ESCAPE =>
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   595
                hide_popup()
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   596
                e.consume
53405
ed2b48af04d9 interpret keys more movement only when needed;
wenzelm
parents: 53398
diff changeset
   597
              case KeyEvent.VK_UP | KeyEvent.VK_KP_UP if multi =>
53407
wenzelm
parents: 53405
diff changeset
   598
                move_items(-1)
wenzelm
parents: 53405
diff changeset
   599
                e.consume
53405
ed2b48af04d9 interpret keys more movement only when needed;
wenzelm
parents: 53398
diff changeset
   600
              case KeyEvent.VK_DOWN | KeyEvent.VK_KP_DOWN if multi =>
53407
wenzelm
parents: 53405
diff changeset
   601
                move_items(1)
wenzelm
parents: 53405
diff changeset
   602
                e.consume
53405
ed2b48af04d9 interpret keys more movement only when needed;
wenzelm
parents: 53398
diff changeset
   603
              case KeyEvent.VK_PAGE_UP if multi =>
53407
wenzelm
parents: 53405
diff changeset
   604
                move_pages(-1)
wenzelm
parents: 53405
diff changeset
   605
                e.consume
53405
ed2b48af04d9 interpret keys more movement only when needed;
wenzelm
parents: 53398
diff changeset
   606
              case KeyEvent.VK_PAGE_DOWN if multi =>
53407
wenzelm
parents: 53405
diff changeset
   607
                move_pages(1)
wenzelm
parents: 53405
diff changeset
   608
                e.consume
53226
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   609
              case _ =>
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   610
                if (e.isActionKey || e.isAltDown || e.isMetaDown || e.isControlDown)
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   611
                  hide_popup()
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   612
            }
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   613
          }
53232
4a3762693452 tuned signature;
wenzelm
parents: 53231
diff changeset
   614
          propagate(e)
53226
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   615
        },
53232
4a3762693452 tuned signature;
wenzelm
parents: 53231
diff changeset
   616
      key_typed = propagate _
53226
9cf8e2263ca7 more systematic JEdit_Lib.key_listener with optional KeyEventWorkaround;
wenzelm
parents: 53023
diff changeset
   617
    )
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   618
53274
1760c01f1c78 maintain Completion_Popup.Text_Area as client property like Document_View;
wenzelm
parents: 53273
diff changeset
   619
  list_view.peer.addKeyListener(inner_key_listener)
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   620
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   621
  list_view.peer.addMouseListener(new MouseAdapter {
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   622
    override def mouseClicked(e: MouseEvent) {
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   623
      if (complete_selected()) e.consume
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   624
      hide_popup()
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   625
    }
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   626
  })
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   627
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   628
  list_view.peer.addFocusListener(new FocusAdapter {
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   629
    override def focusLost(e: FocusEvent) { hide_popup() }
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   630
  })
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   631
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   632
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   633
  /* main content */
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   634
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   635
  override def getFocusTraversalKeysEnabled = false
53297
64c31de7f21c border as for Pretty_Tooltip;
wenzelm
parents: 53296
diff changeset
   636
  completion.setBorder(new LineBorder(Color.BLACK))
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   637
  completion.add((new ScrollPane(list_view)).peer.asInstanceOf[JComponent])
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   638
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   639
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   640
  /* popup */
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   641
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   642
  private val popup =
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   643
  {
53247
bd595338ca18 uniform use of isabelle.jEdit.Popup, based on generic screen location operations;
wenzelm
parents: 53246
diff changeset
   644
    val screen = JEdit_Lib.screen_location(layered, location)
bd595338ca18 uniform use of isabelle.jEdit.Popup, based on generic screen location operations;
wenzelm
parents: 53246
diff changeset
   645
    val size =
53230
6589ff56cc3c determine completion geometry like tooltip;
wenzelm
parents: 53229
diff changeset
   646
    {
6589ff56cc3c determine completion geometry like tooltip;
wenzelm
parents: 53229
diff changeset
   647
      val geometry = JEdit_Lib.window_geometry(completion, completion)
6589ff56cc3c determine completion geometry like tooltip;
wenzelm
parents: 53229
diff changeset
   648
      val bounds = Rendering.popup_bounds
53247
bd595338ca18 uniform use of isabelle.jEdit.Popup, based on generic screen location operations;
wenzelm
parents: 53246
diff changeset
   649
      val w = geometry.width min (screen.bounds.width * bounds).toInt min layered.getWidth
bd595338ca18 uniform use of isabelle.jEdit.Popup, based on generic screen location operations;
wenzelm
parents: 53246
diff changeset
   650
      val h = geometry.height min (screen.bounds.height * bounds).toInt min layered.getHeight
bd595338ca18 uniform use of isabelle.jEdit.Popup, based on generic screen location operations;
wenzelm
parents: 53246
diff changeset
   651
      new Dimension(w, h)
53230
6589ff56cc3c determine completion geometry like tooltip;
wenzelm
parents: 53229
diff changeset
   652
    }
53247
bd595338ca18 uniform use of isabelle.jEdit.Popup, based on generic screen location operations;
wenzelm
parents: 53246
diff changeset
   653
    new Popup(layered, completion, screen.relative(layered, size), size)
53246
8d34caf5bf82 more elementary Popup via JLayeredPane -- avoid javax.swing.PopupFactory with its many problems and dangers of accidental HeavyWeightPopup (especially on Mac OS X);
wenzelm
parents: 53244
diff changeset
   654
  }
8d34caf5bf82 more elementary Popup via JLayeredPane -- avoid javax.swing.PopupFactory with its many problems and dangers of accidental HeavyWeightPopup (especially on Mac OS X);
wenzelm
parents: 53244
diff changeset
   655
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   656
  private def show_popup(focus: Boolean)
53246
8d34caf5bf82 more elementary Popup via JLayeredPane -- avoid javax.swing.PopupFactory with its many problems and dangers of accidental HeavyWeightPopup (especially on Mac OS X);
wenzelm
parents: 53244
diff changeset
   657
  {
8d34caf5bf82 more elementary Popup via JLayeredPane -- avoid javax.swing.PopupFactory with its many problems and dangers of accidental HeavyWeightPopup (especially on Mac OS X);
wenzelm
parents: 53244
diff changeset
   658
    popup.show
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   659
    if (focus) list_view.requestFocus
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   660
  }
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   661
53232
4a3762693452 tuned signature;
wenzelm
parents: 53231
diff changeset
   662
  private def hide_popup()
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   663
  {
56197
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   664
    shutdown(list_view.peer.isFocusOwner)
416f7a00e4cb back to KeyEventInterceptor (see 423e29f1f304), but without focus change, which helps to avoid loosing key events due to quick opening and closing of popups;
wenzelm
parents: 56177
diff changeset
   665
    popup.hide
53023
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   666
  }
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   667
}
f127e949389f Completion popup based on javax.swing.PopupFactory, which has better cross-platform chances than JWindow (cf. org/gjt/jedit/gui/CompletionPopup.java);
wenzelm
parents:
diff changeset
   668