##// END OF EJS Templates
Fixed bug where calltips would sometimes inappropriately disappear on OSX.
Fixed bug where calltips would sometimes inappropriately disappear on OSX.

File last commit:

r3309:7a72909b
r3309:7a72909b
Show More
call_tip_widget.py
230 lines | 8.7 KiB | text/x-python | PythonLexer
epatters
Improved docstring formatting in call tips.
r2666 # Standard library imports
import re
from textwrap import dedent
epatters
Initial checkin of Qt frontend code.
r2602 # System library imports
from PyQt4 import QtCore, QtGui
class CallTipWidget(QtGui.QLabel):
""" Shows call tips by parsing the current text of Q[Plain]TextEdit.
"""
#--------------------------------------------------------------------------
epatters
* Added ability to interrupt a kernel to FrontendWidget...
r2687 # 'QObject' interface
epatters
Initial checkin of Qt frontend code.
r2602 #--------------------------------------------------------------------------
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
Initial checkin of Qt frontend code.
r2602 """ 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(CallTipWidget, self).__init__(None, QtCore.Qt.ToolTip)
epatters
Initial checkin of Qt frontend code.
r2602
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964 self._hide_timer = QtCore.QBasicTimer()
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
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964
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.setFont(text_edit.document().defaultFont())
epatters
Initial checkin of Qt frontend code.
r2602 self.setForegroundRole(QtGui.QPalette.ToolTipText)
self.setBackgroundRole(QtGui.QPalette.ToolTipBase)
self.setPalette(QtGui.QToolTip.palette())
self.setAlignment(QtCore.Qt.AlignLeft)
self.setIndent(1)
self.setFrameStyle(QtGui.QFrame.NoFrame)
self.setMargin(1 + self.style().pixelMetric(
QtGui.QStyle.PM_ToolTipLabelFrameWidth, None, self))
self.setWindowOpacity(self.style().styleHint(
QtGui.QStyle.SH_ToolTipLabel_Opacity, None, self) / 255.0)
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 def eventFilter(self, obj, event):
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 """ Reimplemented to hide on certain key presses and on text edit focus
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 changes.
"""
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 if obj == self._text_edit:
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 etype = event.type()
epatters
Fixed bug where closing a call tip by pressing Escape also cleared the input buffer.
r2962
if etype == QtCore.QEvent.KeyPress:
key = event.key()
if key in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
self.hide()
elif key == QtCore.Qt.Key_Escape:
self.hide()
return True
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 elif etype == QtCore.QEvent.FocusOut:
self.hide()
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964 elif etype == QtCore.QEvent.Enter:
self._hide_timer.stop()
elif etype == QtCore.QEvent.Leave:
epatters
Fixed bug where calltips would sometimes inappropriately disappear on OSX.
r3309 self._leave_event_hide()
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964
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 return super(CallTipWidget, self).eventFilter(obj, event)
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964 def timerEvent(self, event):
""" Reimplemented to hide the widget when the hide timer fires.
"""
if event.timerId() == self._hide_timer.timerId():
self._hide_timer.stop()
self.hide()
epatters
* Added ability to interrupt a kernel to FrontendWidget...
r2687 #--------------------------------------------------------------------------
# 'QWidget' interface
#--------------------------------------------------------------------------
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964 def enterEvent(self, event):
""" Reimplemented to cancel the hide timer.
"""
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 super(CallTipWidget, self).enterEvent(event)
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964 self._hide_timer.stop()
epatters
Initial checkin of Qt frontend code.
r2602 def hideEvent(self, event):
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 """ Reimplemented to disconnect signal handlers and event filter.
epatters
Initial checkin of Qt frontend code.
r2602 """
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 super(CallTipWidget, self).hideEvent(event)
self._text_edit.cursorPositionChanged.disconnect(
self._cursor_position_changed)
self._text_edit.removeEventFilter(self)
epatters
* Added ability to interrupt a kernel to FrontendWidget...
r2687
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964 def leaveEvent(self, event):
""" Reimplemented to start the hide timer.
"""
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 super(CallTipWidget, self).leaveEvent(event)
epatters
Fixed bug where calltips would sometimes inappropriately disappear on OSX.
r3309 self._leave_event_hide()
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964
epatters
Initial checkin of Qt frontend code.
r2602 def paintEvent(self, event):
""" Reimplemented to paint the background panel.
"""
painter = QtGui.QStylePainter(self)
option = QtGui.QStyleOptionFrame()
option.init(self)
painter.drawPrimitive(QtGui.QStyle.PE_PanelTipLabel, option)
painter.end()
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 super(CallTipWidget, self).paintEvent(event)
epatters
Initial checkin of Qt frontend code.
r2602
epatters
Fixed font changes not being propagated to CallTipWidget.
r3031 def setFont(self, font):
""" Reimplemented to allow use of this method as a slot.
"""
super(CallTipWidget, self).setFont(font)
epatters
Initial checkin of Qt frontend code.
r2602 def showEvent(self, event):
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 """ Reimplemented to connect signal handlers and event filter.
epatters
Initial checkin of Qt frontend code.
r2602 """
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 super(CallTipWidget, self).showEvent(event)
self._text_edit.cursorPositionChanged.connect(
self._cursor_position_changed)
self._text_edit.installEventFilter(self)
epatters
Initial checkin of Qt frontend code.
r2602
#--------------------------------------------------------------------------
# 'CallTipWidget' interface
#--------------------------------------------------------------------------
Fernando Perez
Add function signature info to calltips....
r3051 def show_call_info(self, call_line=None, doc=None, maxlines=20):
""" Attempts to show the specified call line and docstring at the
current cursor location. The docstring is possibly truncated for
epatters
Improved docstring formatting in call tips.
r2666 length.
"""
Fernando Perez
Add function signature info to calltips....
r3051 if doc:
match = re.match("(?:[^\n]*\n){%i}" % maxlines, doc)
if match:
doc = doc[:match.end()] + '\n[Documentation continues...]'
else:
doc = ''
if call_line:
doc = '\n\n'.join([call_line, doc])
epatters
Improved docstring formatting in call tips.
r2666 return self.show_tip(doc)
epatters
Initial checkin of Qt frontend code.
r2602 def show_tip(self, tip):
""" Attempts to show the specified tip at the current cursor location.
"""
epatters
Call tips are now positioned more intelligently: if a call tip below the current line would be outside the screen, it is positioned above the line instead.
r2881 # Attempt to find the cursor position at which to show the call tip.
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 text_edit = self._text_edit
epatters
Initial checkin of Qt frontend code.
r2602 document = text_edit.document()
cursor = text_edit.textCursor()
search_pos = cursor.position() - 1
self._start_position, _ = self._find_parenthesis(search_pos,
forward=False)
if self._start_position == -1:
return False
epatters
Call tips are now positioned more intelligently: if a call tip below the current line would be outside the screen, it is positioned above the line instead.
r2881
# Set the text and resize the widget accordingly.
epatters
Initial checkin of Qt frontend code.
r2602 self.setText(tip)
epatters
* The SVG payload matplotlib backend now works....
r2758 self.resize(self.sizeHint())
epatters
Call tips are now positioned more intelligently: if a call tip below the current line would be outside the screen, it is positioned above the line instead.
r2881
# Locate and show the widget. Place the tip below the current line
# unless it would be off the screen. In that case, place it above
# the current line.
epatters
Added some padding between the text and the call tip to improve readability.
r2963 padding = 3 # Distance in pixels between cursor bounds and tip box.
epatters
Call tips are now positioned more intelligently: if a call tip below the current line would be outside the screen, it is positioned above the line instead.
r2881 cursor_rect = text_edit.cursorRect(cursor)
screen_rect = QtGui.qApp.desktop().screenGeometry(text_edit)
point = text_edit.mapToGlobal(cursor_rect.bottomRight())
epatters
Added some padding between the text and the call tip to improve readability.
r2963 point.setY(point.y() + padding)
epatters
Call tips are now positioned more intelligently: if a call tip below the current line would be outside the screen, it is positioned above the line instead.
r2881 tip_height = self.size().height()
if point.y() + tip_height > screen_rect.height():
point = text_edit.mapToGlobal(cursor_rect.topRight())
epatters
Added some padding between the text and the call tip to improve readability.
r2963 point.setY(point.y() - tip_height - padding)
epatters
Call tips are now positioned more intelligently: if a call tip below the current line would be outside the screen, it is positioned above the line instead.
r2881 self.move(point)
epatters
* The SVG payload matplotlib backend now works....
r2758 self.show()
epatters
Initial checkin of Qt frontend code.
r2602 return True
#--------------------------------------------------------------------------
# Protected interface
#--------------------------------------------------------------------------
def _find_parenthesis(self, position, forward=True):
""" If 'forward' is True (resp. False), proceed forwards
(resp. backwards) through the line that contains 'position' until an
unmatched closing (resp. opening) parenthesis is found. Returns a
tuple containing the position of this parenthesis (or -1 if it is
not found) and the number commas (at depth 0) found along the way.
"""
commas = depth = 0
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()
epatters
Initial checkin of Qt frontend code.
r2602 qchar = document.characterAt(position)
while (position > 0 and qchar.isPrint() and
# Need to check explicitly for line/paragraph separators:
qchar.unicode() not in (0x2028, 0x2029)):
char = qchar.toAscii()
if char == ',' and depth == 0:
commas += 1
elif char == ')':
if forward and depth == 0:
break
depth += 1
elif char == '(':
if not forward and depth == 0:
break
depth -= 1
position += 1 if forward else -1
qchar = document.characterAt(position)
else:
position = -1
return position, commas
epatters
Fixed bug where calltips would sometimes inappropriately disappear on OSX.
r3309 def _leave_event_hide(self):
""" Hides the tooltip after some time has passed (assuming the cursor is
not over the tooltip).
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964 """
epatters
Fixed bug where calltips would sometimes inappropriately disappear on OSX.
r3309 if (not self._hide_timer.isActive() and
# If Enter events always came after Leave events, we wouldn't need
# this check. But on Mac OS, it sometimes happens the other way
# around when the tooltip is created.
QtGui.qApp.topLevelAt(QtGui.QCursor.pos()) != self):
epatters
The CallTipWidget is now smarter about automatically hiding itself.
r2964 self._hide_timer.start(300, self)
epatters
* CallTipWidget and CompletionWidget no longer need to be fed key presses. This means that can be attached to any Q[Plain]TextEdit with zero hassle....
r2744 #------ Signal handlers ----------------------------------------------------
def _cursor_position_changed(self):
epatters
Initial checkin of Qt frontend code.
r2602 """ Updates the tip based on user cursor movement.
"""
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
Initial checkin of Qt frontend code.
r2602 if cursor.position() <= self._start_position:
self.hide()
else:
position, commas = self._find_parenthesis(self._start_position + 1)
if position != -1:
self.hide()