From 9891d0744c6a6b01b2e0aa652f3028a6cda371b6 2012-10-04 03:24:22 From: Diane Trout Date: 2012-10-04 03:24:22 Subject: [PATCH] Allow the user to interact with link anchors in the qtconsole Since the qtconsole can display hyperlinks, it would be useful to allow interacting with them. This adds showing a tooltip when the mouse is over a link. The tooltip code stores the anchor in ConsoleWidget._anchor, so when the user right-clicks to select the context menu for "Open Link" or "Copy Link Address", it uses the text that was displayed and not whats under the current context menu pointer location. Also storing the anchor allows me to check to see if we've already displayed that anchor on a new mouseMoveEvent so the tooltip doesn't keep getting redrawn. --- diff --git a/IPython/frontend/qt/console/console_widget.py b/IPython/frontend/qt/console/console_widget.py index e146488..53e36e9 100644 --- a/IPython/frontend/qt/console/console_widget.py +++ b/IPython/frontend/qt/console/console_widget.py @@ -10,6 +10,7 @@ import re import sys from textwrap import dedent from unicodedata import category +import webbrowser # System library imports from IPython.external.qt import QtCore, QtGui @@ -264,6 +265,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): elif self.gui_completion == 'plain': self._completion_widget = CompletionPlain(self) + self._anchor = None self._continuation_prompt = '> ' self._continuation_prompt_html = None self._executing = False @@ -511,6 +513,12 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): """ self.layout().currentWidget().copy() + def copy_anchor(self): + """ Copy anchor text to the clipboard + """ + if self._anchor: + QtGui.QApplication.clipboard().setText(self._anchor) + def cut(self): """ Copy the currently selected text to the clipboard and delete it if it's inside the input buffer. @@ -678,6 +686,12 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): font = property(_get_font, _set_font) + def open_anchor(self): + """ Open selected anchor in the default webbrowser + """ + if self._anchor: + webbrowser.open( self._anchor ) + def paste(self, mode=QtGui.QClipboard.Clipboard): """ Paste the contents of the clipboard into the input region. @@ -971,6 +985,13 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): self.paste_action.setEnabled(self.can_paste()) self.paste_action.setShortcut(QtGui.QKeySequence.Paste) + if self._anchor: + menu.addSeparator() + self.copy_link_action = menu.addAction('Copy Link Address', + self.copy_anchor) + self.open_link_action = menu.addAction('Open Link', + self.open_anchor) + menu.addSeparator() menu.addAction(self.select_all_action) @@ -1009,6 +1030,8 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): elif self.kind == 'rich': control = QtGui.QTextEdit() control.setAcceptRichText(False) + control.setMouseTracking(True) + control.mouseMoveEvent = self.mouseMoveEvent # Install event filters. The filter on the viewport is needed for # mouse events and drag events. @@ -1713,6 +1736,18 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): else: self.input_buffer = '' + def mouseMoveEvent(self, event): + """ Show tooltip if the mouse is hovering over an anchor + """ + pos = event.pos() + anchor = self._control.anchorAt(pos) + if len(anchor) == 0: + self._anchor = None + QtGui.QToolTip.hideText() + elif anchor != self._anchor: + self._anchor = anchor + QtGui.QToolTip.showText(pos, self._anchor) + def _page(self, text, html=False): """ Displays text using the pager if it exceeds the height of the viewport.