camelot.camelot.view.controls.formview

Package camelot :: Package camelot :: Package view :: Package controls :: Module formview |
[hide private]
[frames] | no frames]

# Source Code for Module camelot.camelot.view.controls.formview

      1  #  ============================================================================

      2  #

      3  #  Copyright (C) 2007-2008 Conceptive Engineering bvba. All rights reserved.

      4  #  www.conceptive.be / project-camelot@conceptive.be

      5  #

      6  #  This file is part of the Camelot Library.

      7  #

      8  #  This file may be used under the terms of the GNU General Public

      9  #  License version 2.0 as published by the Free Software Foundation

     10  #  and appearing in the file LICENSE.GPL included in the packaging of

     11  #  this file.  Please review the following information to ensure GNU

     12  #  General Public Licensing requirements will be met:

     13  #  http://www.trolltech.com/products/qt/opensource.html

     14  #

     15  #  If you are unsure which license is appropriate for your use, please

     16  #  review the following information:

     17  #  http://www.trolltech.com/products/qt/licensing.html or contact

     18  #  project-camelot@conceptive.be.

     19  #

     20  #  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE

     21  #  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

     22  #

     23  #  For use of this library in commercial applications, please contact

     24  #  project-camelot@conceptive.be

     25  #

     26  #  ============================================================================

     27

     28  """form view"""
     29

     30  import logging
     31  logger = logging.getLogger('camelot.view.controls.formview')
     32

     33  from PyQt4 import QtCore
     34  from PyQt4 import QtGui
     35  from camelot.view.model_thread import model_function
     36

     37

     38 -class FormView(QtGui.QWidget):
     39 -  def __init__(self, title, admin, model, index):
     40      super(FormView, self).__init__(None)
     41      self.admin = admin
     42      self.model = model
     43      self.index = index
     44      self.setWindowTitle(title)
     45      self.widget_mapper = QtGui.QDataWidgetMapper()
     46      self.widget_layout = QtGui.QHBoxLayout()
     47

     48      self.closeAfterValidation = QtCore.SIGNAL('closeAfterValidation()')
     49      sig = 'dataChanged(const QModelIndex &, const QModelIndex &)'
     50      self.connect(self.model, QtCore.SIGNAL(sig), self.dataChanged)
     51

     52      self.widget_mapper.setModel(model)
     53      self.setLayout(self.widget_layout)
     54      self.setMinimumSize(admin.form_size[0], admin.form_size[1])
     55

     56      self.validator = admin.createValidator(model)
     57      self.validate_before_close = True
     58

     59      def getColumnsAndForm():
     60        return (self.model.getColumns(), self.admin.getForm())
     61

     62      self.admin.mt.post(getColumnsAndForm,

     63                         lambda (columns, form):

     64                         self.handleGetColumnsAndForm(columns, form))
     65

     66      def getActions():
     67        return admin.getFormActions(None)
     68

     69      self.admin.mt.post(getActions, self.setActions)
     70

     71 -  def dataChanged(self, index_from, index_to):
     72      #@TODO: only revert if this form is in the changed range

     73      self.widget_mapper.revert()
     74

     75 -  def handleGetColumnsAndForm(self, columns, form):
     76      delegate = self.model.getItemDelegate()
     77      self.setColumnsFormAndDelegate(columns, form, delegate)
     78

     79 -  def setColumnsFormAndDelegate(self, columns, form, delegate):
     80      """Create value and label widgets"""
     81      widgets = {}
     82      self.widget_mapper.setItemDelegate(delegate)
     83

     84      for i, (field_name, field_attributes) in enumerate(columns):
     85        option = None
     86        model_index = self.model.index(self.index, i)
     87        widget_label = QtGui.QLabel(field_attributes['name'])
     88        widget_editor = delegate.createEditor(None, option, model_index)
     89

     90        # required fields font is bold

     91        if ('nullable' in field_attributes) and \

     92           (not field_attributes['nullable']):
     93          font = QtGui.QApplication.font()
     94          font.setBold(True)
     95          widget_label.setFont(font)
     96

     97        self.widget_mapper.addMapping(widget_editor, i)
     98        widgets[field_name] = (widget_label, widget_editor)
     99

    100      self.widget_mapper.setCurrentIndex(self.index)
    101      self.widget_layout.insertWidget(0, form.render(widgets, self))
    102      self.widget_layout.setContentsMargins(7, 7, 7, 7)
    103

    104 -  def getEntity(self):
    105      return self.model._get_object(self.index)
    106

    107 -  def setActions(self, actions):
    108      if actions:
    109        from actions import ActionsBox
    110        logger.debug('setting Actions for formview')
    111        self.actions_widget = ActionsBox(self, self.admin.mt, self.getEntity)
    112        self.actions_widget.setActions(actions)
    113        self.widget_layout.insertWidget(1, self.actions_widget)
    114

    115 -  def viewFirst(self):
    116      """select model's first row"""
    117      # submit should not happen a second time, since then we don't want

    118      # the widgets data to be written to the model

    119      self.widget_mapper.submit()
    120      self.widget_mapper.toFirst()
    121

    122 -  def viewLast(self):
    123      """select model's last row"""
    124      # submit should not happen a second time, since then we don't want

    125      # the widgets data to be written to the model

    126      self.widget_mapper.submit()
    127      self.widget_mapper.toLast()
    128

    129 -  def viewNext(self):
    130      """select model's next row"""
    131      # submit should not happen a second time, since then we don't want

    132      # the widgets data to be written to the model

    133      self.widget_mapper.submit()
    134      self.widget_mapper.toNext()
    135

    136 -  def viewPrevious(self):
    137      """select model's previous row"""
    138      # submit should not happen a second time, since then we don't want

    139      # the widgets data to be written to the model

    140      self.widget_mapper.submit()
    141      self.widget_mapper.toPrevious()
    142

    143 -  def validateClose(self):
    144      logger.debug('validate before close : %s' % self.validate_before_close)
    145      if self.validate_before_close:
    146        # submit should not happen a second time, since then we don't

    147        # want the widgets data to be written to the model

    148        self.widget_mapper.submit()
    149

    150        def validate():
    151          return self.validator.isValid(self.index)
    152

    153        def showMessage(valid):
    154          if not valid:
    155            messages = u'\n'.join(self.validator.validityMessages(self.index))
    156            mbmessages = u"Changes in this window could not be saved :\n%s" \

    157                         u"\n Do you want to lose your changes ?" % messages
    158            reply = QtGui.QMessageBox.question(self,

    159                                               u'Unsaved changes',

    160                                               mbmessages,

    161                                               QtGui.QMessageBox.Yes,

    162                                               QtGui.QMessageBox.No)
    163            if reply == QtGui.QMessageBox.Yes:
    164              # clear mapping to prevent data being written again to the model,

    165              # then we reverted the row

    166              self.widget_mapper.clearMapping()
    167              self.model.revertRow(self.index)
    168              from camelot.view.workspace import get_workspace
    169              self.validate_before_close = False
    170              self.emit(self.closeAfterValidation)
    171          else:
    172            from camelot.view.workspace import get_workspace
    173            self.validate_before_close = False
    174            self.emit(self.closeAfterValidation)
    175

    176        self.admin.mt.post(validate, showMessage)
    177        return False
    178

    179      return True
    180

    181 -  def closeEvent(self, event):
    182      logger.debug('formview closed')
    183      if self.validateClose():
    184        event.accept()
    185      else:
    186        event.ignore()
    187

    188    @model_function
    189 -  def toHtml(self):
    190      """generates html of the form"""
    191

    192      import settings
    193      from jinja import Environment
    194      from jinja import FileSystemLoader
    195

    196      def to_html(d=u''):
    197        """Jinja 1 filter to convert field values to their default html

    198        representation

    199        """
    200

    201        def wrapped_in_table(env, context, value):
    202          if isinstance(value, list):
    203            return u'<table><tr><td>' +\

    204                   u'</td></tr><tr><td>'.join([unicode(e) for e in value]) +\

    205                   u'</td></tr></table>'
    206          return unicode(value)
    207

    208        return wrapped_in_table
    209

    210      entity = self.getEntity()
    211      fields = self.admin.getFields()
    212      table = [dict(field_attributes = field_attributes,

    213                    value = getattr(entity, name))

    214                    for name, field_attributes in fields]
    215

    216      context = {

    217        'title': self.admin.getName(),

    218        'table': table,

    219      }
    220

    221      ld = FileSystemLoader(settings.CAMELOT_TEMPLATES_DIRECTORY)
    222      env = Environment(loader=ld)
    223      env.filters['to_html'] = to_html
    224      tp = env.get_template('form_view.html')
    225

    226      return tp.render(context)
    227

    228 -  def __del__(self):
    229      """deletes formview object"""
    230      logger.debug('%s deleted' % self.__class__.__name__)
    231