Source code for camelot.view.controls.delegates.customdelegate

#  ============================================================================
#
#  Copyright (C) 2007-2011 Conceptive Engineering bvba. All rights reserved.
#  www.conceptive.be / project-camelot@conceptive.be
#
#  This file is part of the Camelot Library.
#
#  This file may be used under the terms of the GNU General Public
#  License version 2.0 as published by the Free Software Foundation
#  and appearing in the file license.txt included in the packaging of
#  this file.  Please review this information to ensure GNU
#  General Public Licensing requirements will be met.
#
#  If you are unsure which license is appropriate for your use, please
#  visit www.python-camelot.com or contact project-camelot@conceptive.be
#
#  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
#  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
#  For use of this library in commercial applications, please contact
#  project-camelot@conceptive.be
#
#  ============================================================================

from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QItemDelegate
from camelot.core.utils import variant_to_pyobject

from camelot.core.utils import create_constant_function
from camelot.view.proxy import ValueLoading

# custom color
not_editable_background = QtGui.QColor(235, 233, 237)
# darkgray
not_editable_foreground = QtGui.QColor(Qt.darkGray)


[docs]def DocumentationMetaclass(name, bases, dct): dct['__doc__'] = dct.get('__doc__','') + """ .. _delegate-%s: .. image:: /_static/delegates/%s_unselected_disabled.png .. image:: /_static/delegates/%s_unselected_editable.png .. image:: /_static/delegates/%s_selected_disabled.png .. image:: /_static/delegates/%s_selected_editable.png """%(name, name, name, name, name,) import inspect def add_field_attribute_item(a): """Add the name of a field attribute and a reference to its documentation to the docstring""" dct['__doc__'] = dct['__doc__'] + "\n * :ref:`%s <field-attribute-%s>`"%(arg, arg) if '__init__' in dct: dct['__doc__'] = dct['__doc__'] + 'Field attributes supported by the delegate : \n' args, _varargs, _varkw, _defaults = inspect.getargspec(dct['__init__']) for arg in args: if arg not in ['self', 'parent']: add_field_attribute_item(arg) if 'editor' in dct: row_separator = '+' + '-'*40 + '+' + '-'*90 + '+' row_format = """| %-38s | %-88s |""" states = {'editable':['editable=True'], 'disabled':['editable=False'], 'editable_tooltip':['editable=True', "tooltip='tooltip'"], 'disabled_tooltip':['editable=False', "tooltip='tooltip'"], 'editable_background_color':['editable=True', 'background_color=ColorScheme.green'], 'disabled_background_color':['editable=False', 'background_color=ColorScheme.green'] } dct['__doc__'] = dct['__doc__'] + '\n\nBy default, creates a %s as its editor.\n\n'%dct['editor'].__name__ dct['__doc__'] = dct['__doc__'] + row_separator + '\n' dct['__doc__'] = dct['__doc__'] + row_format%('**Field Attributes**', '**Editor**') + '\n' dct['__doc__'] = dct['__doc__'] + row_separator + '\n' for state, attrs in states.items(): for i,attr in enumerate(attrs): if i==0: image = '.. image:: /_static/editors/%s_%s.png'%(dct['editor'].__name__, state) else: image = '' dct['__doc__'] = dct['__doc__'] + row_format%(attr, image) + '\n' dct['__doc__'] = dct['__doc__'] + row_separator + '\n' dct['__doc__'] = dct['__doc__'] + '\nStatic attributes supported by this editor : \n' args, _varargs, _varkw, _defaults = inspect.getargspec(dct['editor'].__init__) for arg in args: if arg not in ['self', 'parent']: add_field_attribute_item(arg) if hasattr(dct['editor'], 'set_field_attributes'): dct['__doc__'] = dct['__doc__'] + '\n\nDynamic field attributes supported by the editor : \n' args, _varargs, _varkw, _defaults = inspect.getargspec(dct['editor'].set_field_attributes) for arg in args: if arg not in ['self', 'parent']: add_field_attribute_item(arg) dct['__doc__'] = dct['__doc__'] + '\n\n' return type(name, bases, dct)
[docs]class CustomDelegate(QItemDelegate): """Base class for implementing custom delegates. .. attribute:: editor class attribute specifies the editor class that should be used """ editor = None def __init__(self, parent=None, editable=True, **kwargs): """:param parent: the parent object for the delegate :param editable: a boolean indicating if the field associated to the delegate is editable """ QItemDelegate.__init__(self, parent) self.editable = editable self.kwargs = kwargs self._font_metrics = QtGui.QFontMetrics(QtGui.QApplication.font()) self._height = self._font_metrics.lineSpacing() + 10 self._width = self._font_metrics.averageCharWidth() * 20
[docs] def createEditor(self, parent, option, index): """ :param option: use an option with version 5 to indicate the widget will be put onto a form """ editor = self.editor(parent, editable = self.editable, option = option, **self.kwargs) assert editor != None assert isinstance(editor, (QtGui.QWidget,)) if option.version != 5: editor.setAutoFillBackground(True) editor.editingFinished.connect( self.commitAndCloseEditor ) return editor
[docs] def sizeHint(self, option, index): return QtCore.QSize(self._width, self._height) #@QtCore.pyqtSlot() # not yet converted to new style sig slot because sender doesn't work # in certain versions of pyqt
[docs] def commitAndCloseEditor(self): editor = self.sender() assert editor != None assert isinstance(editor, (QtGui.QWidget,)) self.commitData.emit(editor) # * Closing the editor results in the calculator not working # * not closing the editor results in the virtualaddresseditor not # getting closed always #self.closeEditor.emit(editor, QtGui.QAbstractItemDelegate.NoHint)
[docs] def setEditorData(self, editor, index): if not index.model(): return value = variant_to_pyobject(index.model().data(index, Qt.EditRole)) field_attributes = variant_to_pyobject(index.data(Qt.UserRole)) or dict() # ok i think i'm onto something, dynamically set tooltip doesn't change # Qt model's data for Qt.ToolTipRole # but i wonder if we should make the detour by Qt.ToolTipRole or just # get our tooltip from field_attributes # (Nick G.): Avoid 'None' being set as tooltip. if field_attributes.get('tooltip'): editor.setToolTip( unicode( field_attributes.get('tooltip', '') ) ) # # first set the field attributes, as these may change the 'state' of the # editor to properly display and hold the value, eg 'precision' of a # float might be changed # editor.set_field_attributes(**field_attributes) editor.set_value(value)
[docs] def setModelData(self, editor, model, index): if isinstance(model, QtGui.QStandardItemModel): val = QtCore.QVariant(editor.get_value()) else: val = create_constant_function(editor.get_value()) model.setData(index, val)
[docs] def paint(self, painter, option, index): painter.save() self.drawBackground(painter, option, index) value = variant_to_pyobject(index.model().data(index, Qt.DisplayRole)) if value in (None, ValueLoading): value_str = '' else: value_str = unicode( value ) self.paint_text( painter, option, index, value_str ) painter.restore()
[docs] def paint_text( self, painter, option, index, text, margin_left=0, margin_right=0, horizontal_align=Qt.AlignLeft, vertical_align=Qt.AlignVCenter ): """Paint unicode text into the given rect defined by option, and fill the rect with the background color :arg margin_left: additional margin to the left, to be used for icons or others :arg margin_right: additional margin to the right, to be used for icons or others""" rect = option.rect # prevent text being centered if the height of the cell increases beyond multiple # lines of text if rect.height() > 2 * self._height: vertical_align = Qt.AlignTop field_attributes = variant_to_pyobject( index.model().data( index, Qt.UserRole ) ) tooltip = None if field_attributes != ValueLoading: editable = field_attributes.get( 'editable', True ) background_color = field_attributes.get( 'background_color', None ) prefix = field_attributes.get( 'prefix', None ) suffix = field_attributes.get( 'suffix', None ) tooltip = field_attributes.get( 'tooltip', None ) if( option.state & QtGui.QStyle.State_Selected ): painter.fillRect(option.rect, option.palette.highlight()) fontColor = option.palette.highlightedText().color() else: if editable: painter.fillRect(rect, background_color or option.palette.base() ) fontColor = QtGui.QColor() fontColor.setRgb(0,0,0) else: painter.fillRect(rect, background_color or option.palette.window() ) fontColor = QtGui.QColor() fontColor.setRgb(130,130,130) # The tooltip has to be drawn after the fillRect()'s of above. if tooltip: painter.drawPixmap(rect.x(), rect.y(), QtGui.QPixmap(':/tooltip_visualization_7x7_glow.png')) if prefix: text = '%s %s' % (unicode( prefix ).strip(), unicode( text ).strip() ) if suffix: text = '%s %s' % (unicode( text ).strip(), unicode( suffix ).strip() ) painter.setPen(fontColor.toRgb()) painter.drawText(rect.x() + 2 + margin_left, rect.y() + 2, rect.width() - 4 - (margin_left + margin_right), rect.height() - 4, # not -10, because the row might not be high enough for this vertical_align | horizontal_align, text)
[docs] def render_ooxml( self, value ): """Generator for label text in Office Open XML representing this form""" yield '<w:r>' yield ' <w:t>%s</w:t>' % unicode(value) yield '</w:r>'
[docs] def render_html( self, index ): """Generator that renders a value to html""" value = variant_to_pyobject(index.model().data(index, Qt.DisplayRole)) yield unicode( value )

Comments
blog comments powered by Disqus