Skip to content

Commit

Permalink
Merge pull request ipython#2467 from detrout/clickable-links
Browse files Browse the repository at this point in the history
Qt console: Add "Open Link" & "Copy Link Address" to right click menu.
  • Loading branch information
bfroehle committed Oct 25, 2012
2 parents 2e1736c + 2bfb3b7 commit 3d4dc71
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 1 deletion.
25 changes: 25 additions & 0 deletions IPython/frontend/qt/console/console_widget.py
Expand Up @@ -10,6 +10,7 @@
import sys
from textwrap import dedent
from unicodedata import category
import webbrowser

# System library imports
from IPython.external.qt import QtCore, QtGui
Expand Down Expand Up @@ -432,6 +433,11 @@ def eventFilter(self, obj, event):
obj == self._page_control:
self._page_control.repaint()
return True

elif etype == QtCore.QEvent.MouseMove:
anchor = self._control.anchorAt(event.pos())
QtGui.QToolTip.showText(event.globalPos(), anchor)

return super(ConsoleWidget, self).eventFilter(obj, event)

#---------------------------------------------------------------------------
Expand Down Expand Up @@ -511,6 +517,11 @@ def copy(self):
"""
self.layout().currentWidget().copy()

def copy_anchor(self, anchor):
""" Copy anchor text to the clipboard
"""
QtGui.QApplication.clipboard().setText(anchor)

def cut(self):
""" Copy the currently selected text to the clipboard and delete it
if it's inside the input buffer.
Expand Down Expand Up @@ -678,6 +689,11 @@ def _set_font(self, font):

font = property(_get_font, _set_font)

def open_anchor(self, anchor):
""" Open selected anchor in the default webbrowser
"""
webbrowser.open( anchor )

def paste(self, mode=QtGui.QClipboard.Clipboard):
""" Paste the contents of the clipboard into the input region.
Expand Down Expand Up @@ -971,6 +987,14 @@ def _context_menu_make(self, pos):
self.paste_action.setEnabled(self.can_paste())
self.paste_action.setShortcut(QtGui.QKeySequence.Paste)

anchor = self._control.anchorAt(pos)
if anchor:
menu.addSeparator()
self.copy_link_action = menu.addAction(
'Copy Link Address', lambda: self.copy_anchor(anchor=anchor))
self.open_link_action = menu.addAction(
'Open Link', lambda: self.open_anchor(anchor=anchor))

menu.addSeparator()
menu.addAction(self.select_all_action)

Expand Down Expand Up @@ -1009,6 +1033,7 @@ def _create_control(self):
elif self.kind == 'rich':
control = QtGui.QTextEdit()
control.setAcceptRichText(False)
control.setMouseTracking(True)

# Install event filters. The filter on the viewport is needed for
# mouse events and drag events.
Expand Down
40 changes: 39 additions & 1 deletion IPython/frontend/qt/console/tests/test_console_widget.py
Expand Up @@ -2,7 +2,7 @@
import unittest

# System library imports
from IPython.external.qt import QtGui
from IPython.external.qt import QtCore, QtGui

# Local imports
from IPython.frontend.qt.console.console_widget import ConsoleWidget
Expand Down Expand Up @@ -40,3 +40,41 @@ def test_special_characters(self):
self.assertEqual(expected_outputs[i], selection)
# clear all the text
cursor.insertText('')

def test_link_handling(self):
noKeys = QtCore.Qt
noButton = QtCore.Qt.MouseButton(0)
noButtons = QtCore.Qt.MouseButtons(0)
noModifiers = QtCore.Qt.KeyboardModifiers(0)
MouseMove = QtCore.QEvent.MouseMove
QMouseEvent = QtGui.QMouseEvent

w = ConsoleWidget()
cursor = w._get_prompt_cursor()
w._insert_html(cursor, '<a href="http://python.org">written in</a>')
obj = w._control
tip = QtGui.QToolTip
self.assertEqual(tip.text(), u'')

# should be somewhere else
elsewhereEvent = QMouseEvent(MouseMove, QtCore.QPoint(50,50),
noButton, noButtons, noModifiers)
w.eventFilter(obj, elsewhereEvent)
self.assertEqual(tip.isVisible(), False)
self.assertEqual(tip.text(), u'')

#self.assertEqual(tip.text(), u'')
# should be over text
overTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
noButton, noButtons, noModifiers)
w.eventFilter(obj, overTextEvent)
self.assertEqual(tip.isVisible(), True)
self.assertEqual(tip.text(), "http://python.org")

# should still be over text
stillOverTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
noButton, noButtons, noModifiers)
w.eventFilter(obj, stillOverTextEvent)
self.assertEqual(tip.isVisible(), True)
self.assertEqual(tip.text(), "http://python.org")

0 comments on commit 3d4dc71

Please sign in to comment.