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