##// END OF EJS Templates
* Added 'started_listening' and 'stopped_listening' signals to QtKernelManager. The FrontendWidget listens for these signals....
epatters -
Show More
@@ -0,0 +1,25 b''
1 """ Defines miscellaneous Qt-related helper classes and functions.
2 """
3
4 # System library imports.
5 from PyQt4 import QtCore
6
7 # IPython imports.
8 from IPython.utils.traitlets import HasTraits
9
10
11 MetaHasTraits = type(HasTraits)
12 MetaQObject = type(QtCore.QObject)
13
14 class MetaQObjectHasTraits(MetaQObject, MetaHasTraits):
15 """ A metaclass that inherits from the metaclasses of both HasTraits and
16 QObject.
17
18 Using this metaclass allows a class to inherit from both HasTraits and
19 QObject. See QtKernelManager for an example.
20 """
21
22 def __init__(cls, name, bases, dct):
23 MetaQObject.__init__(cls, name, bases, dct)
24 MetaHasTraits.__init__(cls, name, bases, dct)
25
@@ -121,10 +121,10 b' class ConsoleWidget(QtGui.QPlainTextEdit):'
121 121 # Initialize public and protected variables
122 122 self.ansi_codes = True
123 123 self.buffer_size = 500
124 self.continuation_prompt = '> '
125 124 self.gui_completion = True
126 125 self._ansi_processor = QtAnsiCodeProcessor()
127 126 self._completion_widget = CompletionWidget(self)
127 self._continuation_prompt = '> '
128 128 self._executing = False
129 129 self._prompt = ''
130 130 self._prompt_pos = 0
@@ -261,7 +261,7 b' class ConsoleWidget(QtGui.QPlainTextEdit):'
261 261 if start_line == self._get_prompt_cursor().blockNumber():
262 262 start_pos += len(self._prompt)
263 263 else:
264 start_pos += len(self.continuation_prompt)
264 start_pos += len(self._continuation_prompt)
265 265 if shift_down and self._in_buffer(position):
266 266 self._set_selection(position, start_pos)
267 267 else:
@@ -271,7 +271,7 b' class ConsoleWidget(QtGui.QPlainTextEdit):'
271 271 elif key == QtCore.Qt.Key_Backspace and not alt_down:
272 272
273 273 # Line deletion (remove continuation prompt)
274 len_prompt = len(self.continuation_prompt)
274 len_prompt = len(self._continuation_prompt)
275 275 if cursor.columnNumber() == len_prompt and \
276 276 position != self._prompt_pos:
277 277 cursor.setPosition(position - len_prompt,
@@ -323,6 +323,18 b' class ConsoleWidget(QtGui.QPlainTextEdit):'
323 323 else:
324 324 cursor.insertText(text)
325 325
326 def clear(self, keep_input=False):
327 """ Reimplemented to write a new prompt. If 'keep_input' is set,
328 restores the old input buffer when the new prompt is written.
329 """
330 super(ConsoleWidget, self).clear()
331
332 if keep_input:
333 input_buffer = self.input_buffer
334 self._show_prompt()
335 if keep_input:
336 self.input_buffer = input_buffer
337
326 338 def paste(self):
327 339 """ Reimplemented to ensure that text is pasted in the editing region.
328 340 """
@@ -330,8 +342,8 b' class ConsoleWidget(QtGui.QPlainTextEdit):'
330 342 QtGui.QPlainTextEdit.paste(self)
331 343
332 344 def print_(self, printer):
333 """ Reimplemented to work around bug in PyQt where the C++ level
334 'print_' slot has the wrong signature.
345 """ Reimplemented to work around a bug in PyQt: the C++ level 'print_'
346 slot has the wrong signature.
335 347 """
336 348 QtGui.QPlainTextEdit.print_(self, printer)
337 349
@@ -363,13 +375,13 b' class ConsoleWidget(QtGui.QPlainTextEdit):'
363 375 input_buffer = str(cursor.selection().toPlainText())
364 376
365 377 # Strip out continuation prompts
366 return input_buffer.replace('\n' + self.continuation_prompt, '\n')
378 return input_buffer.replace('\n' + self._continuation_prompt, '\n')
367 379
368 380 def _set_input_buffer(self, string):
369 381 # Add continuation prompts where necessary
370 382 lines = string.splitlines()
371 383 for i in xrange(1, len(lines)):
372 lines[i] = self.continuation_prompt + lines[i]
384 lines[i] = self._continuation_prompt + lines[i]
373 385 string = '\n'.join(lines)
374 386
375 387 # Replace buffer with new text
@@ -389,7 +401,7 b' class ConsoleWidget(QtGui.QPlainTextEdit):'
389 401 if cursor.blockNumber() == self._get_prompt_cursor().blockNumber():
390 402 return text[len(self._prompt):]
391 403 else:
392 return text[len(self.continuation_prompt):]
404 return text[len(self._continuation_prompt):]
393 405 else:
394 406 return None
395 407
@@ -547,18 +559,20 b' class ConsoleWidget(QtGui.QPlainTextEdit):'
547 559 """
548 560 self.setTextCursor(self._get_selection_cursor(start, end))
549 561
550 def _show_prompt(self, prompt):
551 """ Writes a new prompt at the end of the buffer.
562 def _show_prompt(self, prompt=None):
563 """ Writes a new prompt at the end of the buffer. If 'prompt' is not
564 specified, uses the previous prompt.
552 565 """
553 self.appendPlainText('\n' + prompt)
554 self._prompt = prompt
566 if prompt is not None:
567 self._prompt = prompt
568 self.appendPlainText('\n' + self._prompt)
555 569 self._prompt_pos = self._get_end_cursor().position()
556 570 self._prompt_started()
557 571
558 572 def _show_continuation_prompt(self):
559 573 """ Writes a new continuation prompt at the end of the buffer.
560 574 """
561 self.appendPlainText(self.continuation_prompt)
575 self.appendPlainText(self._continuation_prompt)
562 576 self._prompt_started()
563 577
564 578 def _write_text_keeping_prompt(self, text):
@@ -570,7 +584,7 b' class ConsoleWidget(QtGui.QPlainTextEdit):'
570 584 self._prompt_finished()
571 585
572 586 self.appendPlainText(text)
573 self._show_prompt(self._prompt)
587 self._show_prompt()
574 588 self.input_buffer = input_buffer
575 589
576 590 def _in_buffer(self, position):
@@ -26,8 +26,8 b' class FrontendHighlighter(PygmentsHighlighter):'
26 26 """ Highlight a block of text. Reimplemented to highlight selectively.
27 27 """
28 28 if self.highlighting_on:
29 for prompt in (self._frontend._prompt,
30 self._frontend.continuation_prompt):
29 for prompt in (self._frontend._continuation_prompt,
30 self._frontend._prompt):
31 31 if qstring.startsWith(prompt):
32 32 qstring.remove(0, len(prompt))
33 33 self._current_offset = len(prompt)
@@ -52,9 +52,14 b' class FrontendWidget(HistoryConsoleWidget):'
52 52 # 'QWidget' interface
53 53 #---------------------------------------------------------------------------
54 54
55 def __init__(self, kernel_manager, parent=None):
55 def __init__(self, parent=None):
56 56 super(FrontendWidget, self).__init__(parent)
57 57
58 # ConsoleWidget protected variables.
59 self._continuation_prompt = '... '
60 self._prompt = '>>> '
61
62 # FrontendWidget protected variables.
58 63 self._blockbreaker = BlockBreaker(input_mode='replace')
59 64 self._call_tip_widget = CallTipWidget(self)
60 65 self._completion_lexer = CompletionLexer(PythonLexer())
@@ -62,9 +67,6 b' class FrontendWidget(HistoryConsoleWidget):'
62 67 self._highlighter = FrontendHighlighter(self)
63 68 self._kernel_manager = None
64 69
65 self.continuation_prompt = '... '
66 self.kernel_manager = kernel_manager
67
68 70 self.document().contentsChange.connect(self._document_contents_change)
69 71
70 72 def focusOutEvent(self, event):
@@ -144,10 +146,17 b' class FrontendWidget(HistoryConsoleWidget):'
144 146 return self._kernel_manager
145 147
146 148 def _set_kernel_manager(self, kernel_manager):
147 """ Sets a new kernel manager, configuring its channels as necessary.
149 """ Disconnect from the current kernel manager (if any) and set a new
150 kernel manager.
148 151 """
149 # Disconnect the old kernel manager.
152 # Disconnect the old kernel manager, if necessary.
150 153 if self._kernel_manager is not None:
154 self._kernel_manager.started_listening.disconnect(
155 self._started_listening)
156 self._kernel_manager.stopped_listening.disconnect(
157 self._stopped_listening)
158
159 # Disconnect the old kernel manager's channels.
151 160 sub = self._kernel_manager.sub_channel
152 161 xreq = self._kernel_manager.xreq_channel
153 162 sub.message_received.disconnect(self._handle_sub)
@@ -155,8 +164,16 b' class FrontendWidget(HistoryConsoleWidget):'
155 164 xreq.complete_reply.disconnect(self._handle_complete_reply)
156 165 xreq.object_info_reply.disconnect(self._handle_object_info_reply)
157 166
158 # Connect the new kernel manager.
167 # Set the new kernel manager.
159 168 self._kernel_manager = kernel_manager
169 if kernel_manager is None:
170 return
171
172 # Connect the new kernel manager.
173 kernel_manager.started_listening.connect(self._started_listening)
174 kernel_manager.stopped_listening.connect(self._stopped_listening)
175
176 # Connect the new kernel manager's channels.
160 177 sub = kernel_manager.sub_channel
161 178 xreq = kernel_manager.xreq_channel
162 179 sub.message_received.connect(self._handle_sub)
@@ -164,7 +181,10 b' class FrontendWidget(HistoryConsoleWidget):'
164 181 xreq.complete_reply.connect(self._handle_complete_reply)
165 182 xreq.object_info_reply.connect(self._handle_object_info_reply)
166 183
167 self._show_prompt('>>> ')
184 # Handle the case where the kernel manager started listening before
185 # we connected.
186 if kernel_manager.is_listening:
187 self._started_listening()
168 188
169 189 kernel_manager = property(_get_kernel_manager, _set_kernel_manager)
170 190
@@ -256,7 +276,7 b' class FrontendWidget(HistoryConsoleWidget):'
256 276 text = "ERROR: ABORTED\n"
257 277 self.appendPlainText(text)
258 278 self._hidden = True
259 self._show_prompt('>>> ')
279 self._show_prompt()
260 280 self.executed.emit(rep)
261 281
262 282 def _handle_complete_reply(self, rep):
@@ -274,3 +294,9 b' class FrontendWidget(HistoryConsoleWidget):'
274 294 doc = rep['content']['docstring']
275 295 if doc:
276 296 self._call_tip_widget.show_tip(doc)
297
298 def _started_listening(self):
299 self.clear()
300
301 def _stopped_listening(self):
302 pass
@@ -13,8 +13,8 b' class IPythonWidget(FrontendWidget):'
13 13 # 'FrontendWidget' interface
14 14 #---------------------------------------------------------------------------
15 15
16 def __init__(self, kernel_manager, parent=None):
17 super(IPythonWidget, self).__init__(kernel_manager, parent)
16 def __init__(self, parent=None):
17 super(IPythonWidget, self).__init__(parent)
18 18
19 19 self._magic_overrides = {}
20 20
@@ -87,7 +87,8 b" if __name__ == '__main__':"
87 87
88 88 # Launch application
89 89 app = QtGui.QApplication([])
90 widget = IPythonWidget(kernel_manager)
90 widget = IPythonWidget()
91 widget.kernel_manager = kernel_manager
91 92 widget.setWindowTitle('Python')
92 93 widget.resize(640, 480)
93 94 widget.show()
@@ -1,4 +1,4 b''
1 """ A KernelManager that provides channels that use signals and slots.
1 """ Defines a KernelManager that provides signals and slots.
2 2 """
3 3
4 4 # System library imports.
@@ -7,6 +7,7 b' from PyQt4 import QtCore'
7 7 # IPython imports.
8 8 from IPython.zmq.kernelmanager import KernelManager, SubSocketChannel, \
9 9 XReqSocketChannel, RepSocketChannel
10 from util import MetaQObjectHasTraits
10 11
11 12
12 13 class QtSubSocketChannel(SubSocketChannel, QtCore.QObject):
@@ -109,10 +110,35 b' class QtRepSocketChannel(RepSocketChannel, QtCore.QObject):'
109 110 RepSocketChannel.__init__(self, *args, **kw)
110 111
111 112
112 class QtKernelManager(KernelManager):
113 """ A KernelManager that provides channels that use signals and slots.
113 class QtKernelManager(KernelManager, QtCore.QObject):
114 """ A KernelManager that provides signals and slots.
114 115 """
115 116
117 __metaclass__ = MetaQObjectHasTraits
118
119 # Emitted when the kernel manager has started listening.
120 started_listening = QtCore.pyqtSignal()
121
122 # Emitted when the kernel manager has stopped listening.
123 stopped_listening = QtCore.pyqtSignal()
124
125 # Use Qt-specific channel classes that emit signals.
116 126 sub_channel_class = QtSubSocketChannel
117 127 xreq_channel_class = QtXReqSocketChannel
118 128 rep_channel_class = QtRepSocketChannel
129
130 #---------------------------------------------------------------------------
131 # 'KernelManager' interface
132 #---------------------------------------------------------------------------
133
134 def start_listening(self):
135 """ Reimplemented to emit signal.
136 """
137 super(QtKernelManager, self).start_listening()
138 self.started_listening.emit()
139
140 def stop_listening(self):
141 """ Reimplemented to emit signal.
142 """
143 super(QtKernelManager, self).stop_listening()
144 self.stopped_listening.emit()
General Comments 0
You need to be logged in to leave comments. Login now