##// END OF EJS Templates
Allow the user to interact with link anchors in the qtconsole...
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.

File last commit:

r4872:34c10438
r8532:9891d074
Show More
bracket_matcher.py
100 lines | 3.7 KiB | text/x-python | PythonLexer
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 """ Provides bracket matching for Q[Plain]TextEdit widgets.
"""
# System library imports
Evan Patterson
Paved the way for PySide support....
r3304 from IPython.external.qt import QtCore, QtGui
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894
class BracketMatcher(QtCore.QObject):
""" Matches square brackets, braces, and parentheses based on cursor
position.
"""
Bernardo B. Marques
remove all trailling spaces
r4872
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 # Protected class variables.
_opening_map = { '(':')', '{':'}', '[':']' }
_closing_map = { ')':'(', '}':'{', ']':'[' }
#--------------------------------------------------------------------------
# 'QObject' interface
#--------------------------------------------------------------------------
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 def __init__(self, text_edit):
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 """ Create a call tip manager that is attached to the specified Qt
text edit widget.
"""
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 assert isinstance(text_edit, (QtGui.QTextEdit, QtGui.QPlainTextEdit))
super(BracketMatcher, self).__init__()
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894
# The format to apply to matching brackets.
self.format = QtGui.QTextCharFormat()
self.format.setBackground(QtGui.QColor('silver'))
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 self._text_edit = text_edit
text_edit.cursorPositionChanged.connect(self._cursor_position_changed)
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894
#--------------------------------------------------------------------------
# Protected interface
#--------------------------------------------------------------------------
def _find_match(self, position):
""" Given a valid position in the text document, try to find the
position of the matching bracket. Returns -1 if unsuccessful.
"""
# Decide what character to search for and what direction to search in.
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 document = self._text_edit.document()
Evan Patterson
Paved the way for PySide support....
r3304 start_char = document.characterAt(position)
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 search_char = self._opening_map.get(start_char)
if search_char:
increment = 1
else:
search_char = self._closing_map.get(start_char)
if search_char:
increment = -1
else:
return -1
# Search for the character.
Evan Patterson
Paved the way for PySide support....
r3304 char = start_char
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 depth = 0
while position >= 0 and position < document.characterCount():
if char == start_char:
depth += 1
elif char == search_char:
depth -= 1
if depth == 0:
break
position += increment
Evan Patterson
Paved the way for PySide support....
r3304 char = document.characterAt(position)
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 else:
position = -1
return position
def _selection_for_character(self, position):
""" Convenience method for selecting a character.
"""
selection = QtGui.QTextEdit.ExtraSelection()
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 cursor = self._text_edit.textCursor()
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 cursor.setPosition(position)
Bernardo B. Marques
remove all trailling spaces
r4872 cursor.movePosition(QtGui.QTextCursor.NextCharacter,
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 QtGui.QTextCursor.KeepAnchor)
selection.cursor = cursor
selection.format = self.format
return selection
#------ Signal handlers ----------------------------------------------------
def _cursor_position_changed(self):
""" Updates the document formatting based on the new cursor position.
"""
# Clear out the old formatting.
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 self._text_edit.setExtraSelections([])
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894
# Attempt to match a bracket for the new cursor position.
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 cursor = self._text_edit.textCursor()
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 if not cursor.hasSelection():
position = cursor.position() - 1
match_position = self._find_match(position)
if match_position != -1:
extra_selections = [ self._selection_for_character(pos)
for pos in (position, match_position) ]
epatters
Fixed the segfaults on application exit. The BracketMatcher, CallTipWidget, and CompletionWidget were using the text control as their parents. This should not be a problem, but for some reason it resulted in problems during shutdown. I suspect that PyQt is bugged and was deleting the C++ objects a second time in the garbage collection phase after they had already been deleted automatically by the C++ layer of Qt.
r2982 self._text_edit.setExtraSelections(extra_selections)