##// END OF EJS Templates
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
epatters -
Show More
@@ -34,22 +34,32 b' class CallTipWidget(QtGui.QLabel):'
34 34 self.setWindowOpacity(self.style().styleHint(
35 35 QtGui.QStyle.SH_ToolTipLabel_Opacity, None, self) / 255.0)
36 36
37 def eventFilter(self, obj, event):
38 """ Reimplemented to hide on certain key presses and on parent focus
39 changes.
40 """
41 if obj == self.parent():
42 etype = event.type()
43 if (etype == QtCore.QEvent.KeyPress and
44 event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return,
45 QtCore.Qt.Key_Escape)):
46 self.hide()
47 elif etype == QtCore.QEvent.FocusOut:
48 self.hide()
49
50 return QtGui.QLabel.eventFilter(self, obj, event)
51
37 52 #--------------------------------------------------------------------------
38 53 # 'QWidget' interface
39 54 #--------------------------------------------------------------------------
40 55
41 56 def hideEvent(self, event):
42 """ Reimplemented to disconnect the cursor movement handler.
57 """ Reimplemented to disconnect signal handlers and event filter.
43 58 """
44 59 QtGui.QLabel.hideEvent(self, event)
45 self.parent().cursorPositionChanged.disconnect(self._update_tip)
46
47 def keyPressEvent(self, event):
48 """ Reimplemented to hide on certain key presses.
49 """
50 if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return,
51 QtCore.Qt.Key_Escape):
52 self.hide()
60 parent = self.parent()
61 parent.cursorPositionChanged.disconnect(self._cursor_position_changed)
62 parent.removeEventFilter(self)
53 63
54 64 def paintEvent(self, event):
55 65 """ Reimplemented to paint the background panel.
@@ -63,10 +73,12 b' class CallTipWidget(QtGui.QLabel):'
63 73 QtGui.QLabel.paintEvent(self, event)
64 74
65 75 def showEvent(self, event):
66 """ Reimplemented to connect the cursor movement handler.
76 """ Reimplemented to connect signal handlers and event filter.
67 77 """
68 78 QtGui.QLabel.showEvent(self, event)
69 self.parent().cursorPositionChanged.connect(self._update_tip)
79 parent = self.parent()
80 parent.cursorPositionChanged.connect(self._cursor_position_changed)
81 parent.installEventFilter(self)
70 82
71 83 #--------------------------------------------------------------------------
72 84 # 'CallTipWidget' interface
@@ -139,38 +151,9 b' class CallTipWidget(QtGui.QLabel):'
139 151 position = -1
140 152 return position, commas
141 153
142 def _highlight_tip(self, tip, current_argument):
143 """ Highlight the current argument (arguments start at 0), ending at the
144 next comma or unmatched closing parenthesis.
145
146 FIXME: This is an unreliable way to do things and it isn't being
147 used right now. Instead, we should use inspect.getargspec
148 metadata for this purpose.
149 """
150 start = tip.find('(')
151 if start != -1:
152 for i in xrange(current_argument):
153 start = tip.find(',', start)
154 if start != -1:
155 end = start + 1
156 while end < len(tip):
157 char = tip[end]
158 depth = 0
159 if (char == ',' and depth == 0):
160 break
161 elif char == '(':
162 depth += 1
163 elif char == ')':
164 if depth == 0:
165 break
166 depth -= 1
167 end += 1
168 tip = tip[:start+1] + '<font color="blue">' + \
169 tip[start+1:end] + '</font>' + tip[end:]
170 tip = tip.replace('\n', '<br/>')
171 return tip
172
173 def _update_tip(self):
154 #------ Signal handlers ----------------------------------------------------
155
156 def _cursor_position_changed(self):
174 157 """ Updates the tip based on user cursor movement.
175 158 """
176 159 cursor = self.parent().textCursor()
@@ -7,7 +7,7 b' class CompletionWidget(QtGui.QListWidget):'
7 7 """
8 8
9 9 #--------------------------------------------------------------------------
10 # 'QWidget' interface
10 # 'QObject' interface
11 11 #--------------------------------------------------------------------------
12 12
13 13 def __init__(self, parent):
@@ -28,43 +28,55 b' class CompletionWidget(QtGui.QListWidget):'
28 28
29 29 self.itemActivated.connect(self._complete_current)
30 30
31 def eventFilter(self, obj, event):
32 """ Reimplemented to handle keyboard input and to auto-hide when our
33 parent loses focus.
34 """
35 if obj == self.parent():
36 etype = event.type()
37
38 if etype == QtCore.QEvent.KeyPress:
39 key, text = event.key(), event.text()
40 if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter,
41 QtCore.Qt.Key_Tab):
42 self._complete_current()
43 return True
44 elif key == QtCore.Qt.Key_Escape:
45 self.hide()
46 return True
47 elif key in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down,
48 QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown,
49 QtCore.Qt.Key_Home, QtCore.Qt.Key_End):
50 QtGui.QListWidget.keyPressEvent(self, event)
51 return True
52
53 elif etype == QtCore.QEvent.FocusOut:
54 self.hide()
55
56 return QtGui.QListWidget.eventFilter(self, obj, event)
57
58 #--------------------------------------------------------------------------
59 # 'QWidget' interface
60 #--------------------------------------------------------------------------
61
31 62 def hideEvent(self, event):
32 """ Reimplemented to disconnect the cursor movement handler.
63 """ Reimplemented to disconnect signal handlers and event filter.
33 64 """
34 65 QtGui.QListWidget.hideEvent(self, event)
66 parent = self.parent()
35 67 try:
36 self.parent().cursorPositionChanged.disconnect(self._update_current)
68 parent.cursorPositionChanged.disconnect(self._update_current)
37 69 except TypeError:
38 70 pass
39
40 def keyPressEvent(self, event):
41 """ Reimplemented to update the list.
42 """
43 key, text = event.key(), event.text()
44
45 if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter,
46 QtCore.Qt.Key_Tab):
47 self._complete_current()
48 event.accept()
49
50 elif key == QtCore.Qt.Key_Escape:
51 self.hide()
52 event.accept()
53
54 elif key in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down,
55 QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown,
56 QtCore.Qt.Key_Home, QtCore.Qt.Key_End):
57 QtGui.QListWidget.keyPressEvent(self, event)
58 event.accept()
59
60 else:
61 event.ignore()
71 parent.removeEventFilter(self)
62 72
63 73 def showEvent(self, event):
64 """ Reimplemented to connect the cursor movement handler.
74 """ Reimplemented to connect signal handlers and event filter.
65 75 """
66 76 QtGui.QListWidget.showEvent(self, event)
67 self.parent().cursorPositionChanged.connect(self._update_current)
77 parent = self.parent()
78 parent.cursorPositionChanged.connect(self._update_current)
79 parent.installEventFilter(self)
68 80
69 81 #--------------------------------------------------------------------------
70 82 # 'CompletionWidget' interface
@@ -56,8 +56,7 b' class ConsoleWidget(QtGui.QWidget):'
56 56 ----------
57 57 kind : str, optional [default 'plain']
58 58 The type of text widget to use. Valid values are 'plain', which
59 specifies a QPlainTextEdit, and 'rich', which specifies an
60 QTextEdit.
59 specifies a QPlainTextEdit, and 'rich', which specifies a QTextEdit.
61 60
62 61 parent : QWidget, optional [default None]
63 62 The parent for this widget.
@@ -332,6 +331,12 b' class ConsoleWidget(QtGui.QWidget):'
332 331 """
333 332 raise NotImplementedError
334 333
334 def _execute_interrupt(self):
335 """ Attempts to stop execution. Returns whether this method has an
336 implementation.
337 """
338 return False
339
335 340 def _prompt_started_hook(self):
336 341 """ Called immediately after a new prompt is displayed.
337 342 """
@@ -469,12 +474,6 b' class ConsoleWidget(QtGui.QWidget):'
469 474 QtGui.qApp.sendEvent(self._control, new_event)
470 475 return True
471 476
472 # If the completion widget accepts the key press, return immediately.
473 if self._completion_widget.isVisible():
474 self._completion_widget.keyPressEvent(event)
475 if event.isAccepted():
476 return True
477
478 477 # Otherwise, proceed normally and do not return early.
479 478 intercepted = False
480 479 cursor = self._control.textCursor()
@@ -488,7 +487,10 b' class ConsoleWidget(QtGui.QWidget):'
488 487 intercepted = True
489 488
490 489 elif ctrl_down:
491 if key == QtCore.Qt.Key_K:
490 if key == QtCore.Qt.Key_C and self._executing:
491 intercepted = self._execute_interrupt()
492
493 elif key == QtCore.Qt.Key_K:
492 494 if self._in_buffer(position):
493 495 cursor.movePosition(QtGui.QTextCursor.EndOfLine,
494 496 QtGui.QTextCursor.KeepAnchor)
@@ -91,28 +91,6 b' class FrontendWidget(HistoryConsoleWidget):'
91 91 document.contentsChange.connect(self._document_contents_change)
92 92
93 93 #---------------------------------------------------------------------------
94 # 'QWidget' interface
95 #---------------------------------------------------------------------------
96
97 def focusOutEvent(self, event):
98 """ Reimplemented to hide calltips.
99 """
100 self._call_tip_widget.hide()
101 super(FrontendWidget, self).focusOutEvent(event)
102
103 def keyPressEvent(self, event):
104 """ Reimplemented to allow calltips to process events and to send
105 signals to the kernel.
106 """
107 if self._executing and event.key() == QtCore.Qt.Key_C and \
108 self._control_down(event.modifiers()):
109 self._interrupt_kernel()
110 else:
111 if self._call_tip_widget.isVisible():
112 self._call_tip_widget.keyPressEvent(event)
113 super(FrontendWidget, self).keyPressEvent(event)
114
115 #---------------------------------------------------------------------------
116 94 # 'ConsoleWidget' abstract interface
117 95 #---------------------------------------------------------------------------
118 96
@@ -131,6 +109,13 b' class FrontendWidget(HistoryConsoleWidget):'
131 109 """
132 110 self.kernel_manager.xreq_channel.execute(source)
133 111 self._hidden = hidden
112
113 def _execute_interrupt(self):
114 """ Attempts to stop execution. Returns whether this method has an
115 implementation.
116 """
117 self._interrupt_kernel()
118 return True
134 119
135 120 def _prompt_started_hook(self):
136 121 """ Called immediately after a new prompt is displayed.
@@ -245,8 +230,8 b' class FrontendWidget(HistoryConsoleWidget):'
245 230
246 231 # Send the metadata request to the kernel
247 232 name = '.'.join(context)
248 self._calltip_id = self.kernel_manager.xreq_channel.object_info(name)
249 self._calltip_pos = self._get_cursor().position()
233 self._call_tip_id = self.kernel_manager.xreq_channel.object_info(name)
234 self._call_tip_pos = self._get_cursor().position()
250 235 return True
251 236
252 237 def _complete(self):
@@ -311,7 +296,7 b' class FrontendWidget(HistoryConsoleWidget):'
311 296 pass
312 297
313 298 def _document_contents_change(self, position, removed, added):
314 """ Called whenever the document's content changes. Display a calltip
299 """ Called whenever the document's content changes. Display a call tip
315 300 if appropriate.
316 301 """
317 302 # Calculate where the cursor should be *after* the change:
@@ -377,8 +362,8 b' class FrontendWidget(HistoryConsoleWidget):'
377 362
378 363 def _handle_object_info_reply(self, rep):
379 364 cursor = self._get_cursor()
380 if rep['parent_header']['msg_id'] == self._calltip_id and \
381 cursor.position() == self._calltip_pos:
365 if rep['parent_header']['msg_id'] == self._call_tip_id and \
366 cursor.position() == self._call_tip_pos:
382 367 doc = rep['content']['docstring']
383 368 if doc:
384 369 self._call_tip_widget.show_docstring(doc)
General Comments 0
You need to be logged in to leave comments. Login now