diff --git a/IPython/frontend/qt/console/console_widget.py b/IPython/frontend/qt/console/console_widget.py index 9b24ed693af..03b09faeef9 100644 --- a/IPython/frontend/qt/console/console_widget.py +++ b/IPython/frontend/qt/console/console_widget.py @@ -15,27 +15,6 @@ from completion_widget import CompletionWidget -class ConsolePlainTextEdit(QtGui.QPlainTextEdit): - """ A QPlainTextEdit suitable for use with ConsoleWidget. - """ - # Prevents text from being moved by drag and drop. Note that is not, for - # some reason, sufficient to catch drag events in the ConsoleWidget's - # event filter. - def dragEnterEvent(self, event): pass - def dragLeaveEvent(self, event): pass - def dragMoveEvent(self, event): pass - def dropEvent(self, event): pass - -class ConsoleTextEdit(QtGui.QTextEdit): - """ A QTextEdit suitable for use with ConsoleWidget. - """ - # See above. - def dragEnterEvent(self, event): pass - def dragLeaveEvent(self, event): pass - def dragMoveEvent(self, event): pass - def dropEvent(self, event): pass - - class ConsoleWidget(Configurable, QtGui.QWidget): """ An abstract base class for console-type widgets. This class has functionality for: @@ -205,6 +184,11 @@ def eventFilter(self, obj, event): event.accept() return False + # Prevent text from being moved by drag and drop. + elif etype in (QtCore.QEvent.DragEnter, QtCore.QEvent.DragLeave, + QtCore.QEvent.DragMove, QtCore.QEvent.Drop): + return True + return super(ConsoleWidget, self).eventFilter(obj, event) #--------------------------------------------------------------------------- @@ -267,7 +251,7 @@ def clear(self, keep_input=True): self.input_buffer = input_buffer def copy(self): - """ Copy the current selected text to the clipboard. + """ Copy the currently selected text to the clipboard. """ self._control.copy() @@ -667,13 +651,13 @@ def _create_control(self): """ # Create the underlying control. if self.kind == 'plain': - control = ConsolePlainTextEdit() + control = QtGui.QPlainTextEdit() elif self.kind == 'rich': - control = ConsoleTextEdit() + control = QtGui.QTextEdit() control.setAcceptRichText(False) # Install event filters. The filter on the viewport is needed for - # mouse events. + # mouse events and drag events. control.installEventFilter(self) control.viewport().installEventFilter(self) @@ -694,7 +678,7 @@ def _create_control(self): def _create_page_control(self): """ Creates and connects the underlying paging widget. """ - control = ConsolePlainTextEdit() + control = QtGui.QPlainTextEdit() control.installEventFilter(self) control.setReadOnly(True) control.setUndoRedoEnabled(False) @@ -713,8 +697,11 @@ def _event_filter_console_keypress(self, event): alt_down = event.modifiers() & QtCore.Qt.AltModifier shift_down = event.modifiers() & QtCore.Qt.ShiftModifier - if event.matches(QtGui.QKeySequence.Paste): - # Call our paste instead of the underlying text widget's. + if event.matches(QtGui.QKeySequence.Copy): + self.copy() + intercepted = True + + elif event.matches(QtGui.QKeySequence.Paste): self.paste() intercepted = True diff --git a/IPython/frontend/qt/console/frontend_widget.py b/IPython/frontend/qt/console/frontend_widget.py index 5d9f392d8cb..7792e27c589 100644 --- a/IPython/frontend/qt/console/frontend_widget.py +++ b/IPython/frontend/qt/console/frontend_widget.py @@ -8,7 +8,7 @@ from PyQt4 import QtCore, QtGui # Local imports -from IPython.core.inputsplitter import InputSplitter +from IPython.core.inputsplitter import InputSplitter, transform_classic_prompt from IPython.frontend.qt.base_frontend_mixin import BaseFrontendMixin from IPython.utils.io import raw_print from IPython.utils.traitlets import Bool @@ -126,6 +126,21 @@ def __init__(self, *args, **kw): document = self._control.document() document.contentsChange.connect(self._document_contents_change) + #--------------------------------------------------------------------------- + # 'ConsoleWidget' public interface + #--------------------------------------------------------------------------- + + def copy(self): + """ Copy the currently selected text to the clipboard, removing prompts. + """ + text = str(self._control.textCursor().selection().toPlainText()) + if text: + # Remove prompts. + lines = map(transform_classic_prompt, text.splitlines()) + text = '\n'.join(lines) + # Expand tabs so that we respect PEP-8. + QtGui.QApplication.clipboard().setText(text.expandtabs(4)) + #--------------------------------------------------------------------------- # 'ConsoleWidget' abstract interface #--------------------------------------------------------------------------- @@ -306,7 +321,7 @@ def _stopped_channels(self): self._highlighter.highlighting_on = False #--------------------------------------------------------------------------- - # 'FrontendWidget' interface + # 'FrontendWidget' public interface #--------------------------------------------------------------------------- def execute_file(self, path, hidden=False): diff --git a/IPython/frontend/qt/console/ipython_widget.py b/IPython/frontend/qt/console/ipython_widget.py index 910fd8e4a3a..3d8c049d1bc 100644 --- a/IPython/frontend/qt/console/ipython_widget.py +++ b/IPython/frontend/qt/console/ipython_widget.py @@ -19,7 +19,8 @@ from PyQt4 import QtCore, QtGui # Local imports -from IPython.core.inputsplitter import IPythonInputSplitter +from IPython.core.inputsplitter import IPythonInputSplitter, \ + transform_ipy_prompt from IPython.core.usage import default_banner from IPython.utils.traitlets import Bool, Str from frontend_widget import FrontendWidget @@ -198,7 +199,23 @@ def _started_channels(self): #self.kernel_manager.xreq_channel.history(raw=True, output=False) #--------------------------------------------------------------------------- - # 'FrontendWidget' interface + # 'ConsoleWidget' public interface + #--------------------------------------------------------------------------- + + def copy(self): + """ Copy the currently selected text to the clipboard, removing prompts + if possible. + """ + text = str(self._control.textCursor().selection().toPlainText()) + if text: + # Remove prompts. + lines = map(transform_ipy_prompt, text.splitlines()) + text = '\n'.join(lines) + # Expand tabs so that we respect PEP-8. + QtGui.QApplication.clipboard().setText(text.expandtabs(4)) + + #--------------------------------------------------------------------------- + # 'FrontendWidget' public interface #--------------------------------------------------------------------------- def execute_file(self, path, hidden=False):