##// END OF EJS Templates
Merge branch 'newkernel' of github.com:ipython/ipython into upstream-newkernel
Merge branch 'newkernel' of github.com:ipython/ipython into upstream-newkernel

File last commit:

r2881:bc516fc7
r2901:61ddddd9 merge
Show More
call_tip_widget.py
174 lines | 6.8 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 #--------------------------------------------------------------------------
def __init__(self, parent):
""" Create a call tip manager that is attached to the specified Qt
text edit widget.
"""
assert isinstance(parent, (QtGui.QTextEdit, QtGui.QPlainTextEdit))
QtGui.QLabel.__init__(self, parent, QtCore.Qt.ToolTip)
self.setFont(parent.document().defaultFont())
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):
""" Reimplemented to hide on certain key presses and on parent focus
changes.
"""
if obj == self.parent():
etype = event.type()
if (etype == QtCore.QEvent.KeyPress and
event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return,
QtCore.Qt.Key_Escape)):
self.hide()
elif etype == QtCore.QEvent.FocusOut:
self.hide()
return QtGui.QLabel.eventFilter(self, obj, event)
epatters
* Added ability to interrupt a kernel to FrontendWidget...
r2687 #--------------------------------------------------------------------------
# 'QWidget' interface
#--------------------------------------------------------------------------
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 typos in CallTipWidget due to copy-paste.
r2673 QtGui.QLabel.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 parent = self.parent()
parent.cursorPositionChanged.disconnect(self._cursor_position_changed)
parent.removeEventFilter(self)
epatters
* Added ability to interrupt a kernel to FrontendWidget...
r2687
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()
QtGui.QLabel.paintEvent(self, event)
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 typos in CallTipWidget due to copy-paste.
r2673 QtGui.QLabel.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 parent = self.parent()
parent.cursorPositionChanged.connect(self._cursor_position_changed)
parent.installEventFilter(self)
epatters
Initial checkin of Qt frontend code.
r2602
#--------------------------------------------------------------------------
# 'CallTipWidget' interface
#--------------------------------------------------------------------------
epatters
Improved docstring formatting in call tips.
r2666 def show_docstring(self, doc, maxlines=20):
""" Attempts to show the specified docstring at the current cursor
location. The docstring is dedented and possibly truncated for
length.
"""
doc = dedent(doc.rstrip()).lstrip()
match = re.match("(?:[^\n]*\n){%i}" % maxlines, doc)
if match:
doc = doc[:match.end()] + '\n[Documentation continues...]'
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
Initial checkin of Qt frontend code.
r2602 text_edit = self.parent()
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.
cursor_rect = text_edit.cursorRect(cursor)
screen_rect = QtGui.qApp.desktop().screenGeometry(text_edit)
point = text_edit.mapToGlobal(cursor_rect.bottomRight())
tip_height = self.size().height()
if point.y() + tip_height > screen_rect.height():
point = text_edit.mapToGlobal(cursor_rect.topRight())
point.setY(point.y() - tip_height)
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
document = self.parent().document()
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
* 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.
"""
cursor = self.parent().textCursor()
if cursor.position() <= self._start_position:
self.hide()
else:
position, commas = self._find_parenthesis(self._start_position + 1)
if position != -1:
self.hide()