##// 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 self.setWindowOpacity(self.style().styleHint(
34 self.setWindowOpacity(self.style().styleHint(
35 QtGui.QStyle.SH_ToolTipLabel_Opacity, None, self) / 255.0)
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 # 'QWidget' interface
53 # 'QWidget' interface
39 #--------------------------------------------------------------------------
54 #--------------------------------------------------------------------------
40
55
41 def hideEvent(self, event):
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 QtGui.QLabel.hideEvent(self, event)
59 QtGui.QLabel.hideEvent(self, event)
45 self.parent().cursorPositionChanged.disconnect(self._update_tip)
60 parent = self.parent()
46
61 parent.cursorPositionChanged.disconnect(self._cursor_position_changed)
47 def keyPressEvent(self, event):
62 parent.removeEventFilter(self)
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()
53
63
54 def paintEvent(self, event):
64 def paintEvent(self, event):
55 """ Reimplemented to paint the background panel.
65 """ Reimplemented to paint the background panel.
@@ -63,10 +73,12 b' class CallTipWidget(QtGui.QLabel):'
63 QtGui.QLabel.paintEvent(self, event)
73 QtGui.QLabel.paintEvent(self, event)
64
74
65 def showEvent(self, event):
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 QtGui.QLabel.showEvent(self, event)
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 # 'CallTipWidget' interface
84 # 'CallTipWidget' interface
@@ -139,38 +151,9 b' class CallTipWidget(QtGui.QLabel):'
139 position = -1
151 position = -1
140 return position, commas
152 return position, commas
141
153
142 def _highlight_tip(self, tip, current_argument):
154 #------ Signal handlers ----------------------------------------------------
143 """ Highlight the current argument (arguments start at 0), ending at the
155
144 next comma or unmatched closing parenthesis.
156 def _cursor_position_changed(self):
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):
174 """ Updates the tip based on user cursor movement.
157 """ Updates the tip based on user cursor movement.
175 """
158 """
176 cursor = self.parent().textCursor()
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 def __init__(self, parent):
13 def __init__(self, parent):
@@ -28,43 +28,55 b' class CompletionWidget(QtGui.QListWidget):'
28
28
29 self.itemActivated.connect(self._complete_current)
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 def hideEvent(self, event):
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 QtGui.QListWidget.hideEvent(self, event)
65 QtGui.QListWidget.hideEvent(self, event)
66 parent = self.parent()
35 try:
67 try:
36 self.parent().cursorPositionChanged.disconnect(self._update_current)
68 parent.cursorPositionChanged.disconnect(self._update_current)
37 except TypeError:
69 except TypeError:
38 pass
70 pass
39
71 parent.removeEventFilter(self)
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()
62
72
63 def showEvent(self, event):
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 QtGui.QListWidget.showEvent(self, event)
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 # 'CompletionWidget' interface
82 # 'CompletionWidget' interface
@@ -56,8 +56,7 b' class ConsoleWidget(QtGui.QWidget):'
56 ----------
56 ----------
57 kind : str, optional [default 'plain']
57 kind : str, optional [default 'plain']
58 The type of text widget to use. Valid values are 'plain', which
58 The type of text widget to use. Valid values are 'plain', which
59 specifies a QPlainTextEdit, and 'rich', which specifies an
59 specifies a QPlainTextEdit, and 'rich', which specifies a QTextEdit.
60 QTextEdit.
61
60
62 parent : QWidget, optional [default None]
61 parent : QWidget, optional [default None]
63 The parent for this widget.
62 The parent for this widget.
@@ -332,6 +331,12 b' class ConsoleWidget(QtGui.QWidget):'
332 """
331 """
333 raise NotImplementedError
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 def _prompt_started_hook(self):
340 def _prompt_started_hook(self):
336 """ Called immediately after a new prompt is displayed.
341 """ Called immediately after a new prompt is displayed.
337 """
342 """
@@ -469,12 +474,6 b' class ConsoleWidget(QtGui.QWidget):'
469 QtGui.qApp.sendEvent(self._control, new_event)
474 QtGui.qApp.sendEvent(self._control, new_event)
470 return True
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 # Otherwise, proceed normally and do not return early.
477 # Otherwise, proceed normally and do not return early.
479 intercepted = False
478 intercepted = False
480 cursor = self._control.textCursor()
479 cursor = self._control.textCursor()
@@ -488,7 +487,10 b' class ConsoleWidget(QtGui.QWidget):'
488 intercepted = True
487 intercepted = True
489
488
490 elif ctrl_down:
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 if self._in_buffer(position):
494 if self._in_buffer(position):
493 cursor.movePosition(QtGui.QTextCursor.EndOfLine,
495 cursor.movePosition(QtGui.QTextCursor.EndOfLine,
494 QtGui.QTextCursor.KeepAnchor)
496 QtGui.QTextCursor.KeepAnchor)
@@ -91,28 +91,6 b' class FrontendWidget(HistoryConsoleWidget):'
91 document.contentsChange.connect(self._document_contents_change)
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 # 'ConsoleWidget' abstract interface
94 # 'ConsoleWidget' abstract interface
117 #---------------------------------------------------------------------------
95 #---------------------------------------------------------------------------
118
96
@@ -131,6 +109,13 b' class FrontendWidget(HistoryConsoleWidget):'
131 """
109 """
132 self.kernel_manager.xreq_channel.execute(source)
110 self.kernel_manager.xreq_channel.execute(source)
133 self._hidden = hidden
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 def _prompt_started_hook(self):
120 def _prompt_started_hook(self):
136 """ Called immediately after a new prompt is displayed.
121 """ Called immediately after a new prompt is displayed.
@@ -245,8 +230,8 b' class FrontendWidget(HistoryConsoleWidget):'
245
230
246 # Send the metadata request to the kernel
231 # Send the metadata request to the kernel
247 name = '.'.join(context)
232 name = '.'.join(context)
248 self._calltip_id = self.kernel_manager.xreq_channel.object_info(name)
233 self._call_tip_id = self.kernel_manager.xreq_channel.object_info(name)
249 self._calltip_pos = self._get_cursor().position()
234 self._call_tip_pos = self._get_cursor().position()
250 return True
235 return True
251
236
252 def _complete(self):
237 def _complete(self):
@@ -311,7 +296,7 b' class FrontendWidget(HistoryConsoleWidget):'
311 pass
296 pass
312
297
313 def _document_contents_change(self, position, removed, added):
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 if appropriate.
300 if appropriate.
316 """
301 """
317 # Calculate where the cursor should be *after* the change:
302 # Calculate where the cursor should be *after* the change:
@@ -377,8 +362,8 b' class FrontendWidget(HistoryConsoleWidget):'
377
362
378 def _handle_object_info_reply(self, rep):
363 def _handle_object_info_reply(self, rep):
379 cursor = self._get_cursor()
364 cursor = self._get_cursor()
380 if rep['parent_header']['msg_id'] == self._calltip_id and \
365 if rep['parent_header']['msg_id'] == self._call_tip_id and \
381 cursor.position() == self._calltip_pos:
366 cursor.position() == self._call_tip_pos:
382 doc = rep['content']['docstring']
367 doc = rep['content']['docstring']
383 if doc:
368 if doc:
384 self._call_tip_widget.show_docstring(doc)
369 self._call_tip_widget.show_docstring(doc)
General Comments 0
You need to be logged in to leave comments. Login now