diff --git a/IPython/frontend/qt/console/console_widget.py b/IPython/frontend/qt/console/console_widget.py index 1cfa695..b6b85c4 100644 --- a/IPython/frontend/qt/console/console_widget.py +++ b/IPython/frontend/qt/console/console_widget.py @@ -268,7 +268,6 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): self._continuation_prompt = '> ' self._continuation_prompt_html = None self._executing = False - self._filter_drag = False self._filter_resize = False self._html_exporter = HtmlExporter(self._control) self._input_buffer_executing = '' @@ -343,7 +342,37 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): triggered=self.reset_font) self.addAction(self.reset_font_size) + # Accept drag and drop events here. Drops were already turned off + # in self._control when that widget was created. + self.setAcceptDrops(True) + #--------------------------------------------------------------------------- + # Drag and drop support + #--------------------------------------------------------------------------- + + def dragEnterEvent(self, e): + if e.mimeData().hasText(): + # By changing the action to copy we don't need to worry about + # the user accidentally moving text around in the widget. + e.setDropAction(QtCore.Qt.CopyAction) + e.accept() + + def dragMoveEvent(self, e): + if e.mimeData().hasText(): + cursor = self._control.cursorForPosition(e.pos()) + if self._in_buffer(cursor.position()): + e.setDropAction(QtCore.Qt.CopyAction) + self._control.setTextCursor(cursor) + else: + e.setDropAction(QtCore.Qt.IgnoreAction) + e.accept() + + def dropEvent(self, e): + if e.mimeData().hasText(): + cursor = self._control.cursorForPosition(e.pos()) + if self._in_buffer(cursor.position()): + text = e.mimeData().text() + self._insert_plain_text_into_buffer(cursor, text) def eventFilter(self, obj, event): """ Reimplemented to ensure a console-like behavior in the underlying @@ -392,39 +421,6 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): event.key() in self._shortcuts: event.accept() - # Ensure that drags are safe. The problem is that the drag starting - # logic, which determines whether the drag is a Copy or Move, is locked - # down in QTextControl. If the widget is editable, which it must be if - # we're not executing, the drag will be a Move. The following hack - # prevents QTextControl from deleting the text by clearing the selection - # when a drag leave event originating from this widget is dispatched. - # The fact that we have to clear the user's selection is unfortunate, - # but the alternative--trying to prevent Qt from using its hardwired - # drag logic and writing our own--is worse. - elif etype == QtCore.QEvent.DragEnter and \ - obj == self._control.viewport() and \ - event.source() == self._control.viewport(): - self._filter_drag = True - elif etype == QtCore.QEvent.DragLeave and \ - obj == self._control.viewport() and \ - self._filter_drag: - cursor = self._control.textCursor() - cursor.clearSelection() - self._control.setTextCursor(cursor) - self._filter_drag = False - - # Ensure that drops are safe. - elif etype == QtCore.QEvent.Drop and obj == self._control.viewport(): - cursor = self._control.cursorForPosition(event.pos()) - if self._in_buffer(cursor.position()): - text = event.mimeData().text() - self._insert_plain_text_into_buffer(cursor, text) - - # Qt is expecting to get something here--drag and drop occurs in its - # own event loop. Send a DragLeave event to end it. - QtGui.qApp.sendEvent(obj, QtGui.QDragLeaveEvent()) - return True - # Handle scrolling of the vsplit pager. This hack attempts to solve # problems with tearing of the help text inside the pager window. This # happens only on Mac OS X with both PySide and PyQt. This fix isn't @@ -1035,8 +1031,12 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): control.setAcceptRichText(False) control.setMouseTracking(True) + # Prevent the widget from handling drops, as we already provide + # the logic in this class. + control.setAcceptDrops(False) + # Install event filters. The filter on the viewport is needed for - # mouse events and drag events. + # mouse events. control.installEventFilter(self) control.viewport().installEventFilter(self)