import os, sys, string import Preferences, Utils, Plugins if not Plugins.transportInstalled('ZopeLib.ZopeExplorer'): raise Plugins.SkipPlugin, 'Zope support is not enabled' #---Model----------------------------------------------------------------------- # Define new zope image and a Model for opening in the Editor from ZopeLib.ZopeEditorModels import addZOAImage, ZOAIcons, ZopeBlankEditorModel, ZopeController addZOAImage('Formulator Form', 'Images/ZOA/FormulatorForm.png') field_meta_types = ['FileField', 'MultiCheckBoxField', 'LinesField', 'ListField', 'TextAreaField', 'MultiListField', 'EmailField', 'CheckBoxField', 'PasswordField', 'FloatField', 'PatternField', 'LinkField', 'StringField', 'RawTextAreaField', 'IntegerField', 'RadioField', 'DateTimeField'] for field in field_meta_types: addZOAImage(field, 'Images/ZOA/FormulatorField.png') class FormulatorFormModel(ZopeBlankEditorModel): imgIdx = ZOAIcons['Formulator Form'] #---Controller------------------------------------------------------------------ # Connect controller to the model from Models import Controllers Controllers.modelControllerReg[FormulatorFormModel] = ZopeController #---Views----------------------------------------------------------------------- from Views.EditorViews import EditorView import wx class FormulatorFormOrderView(wx.TreeCtrl, EditorView): viewName = 'Order' refreshBmp = 'Images/Editor/Refresh.png' addGroupBmp = 'Images/Shared/NewItem.png' remGroupBmp = 'Images/Shared/DeleteItem.png' moveUpBmp = 'Images/Shared/up.png' moveDownBmp = 'Images/Shared/down.png' def __init__(self, parent, model): wid = wx.NewId() wx.TreeCtrl.__init__(self, parent, wid, style = wx.TR_HAS_BUTTONS | wx.SUNKEN_BORDER | wx.TR_EDIT_LABELS) EditorView.__init__(self, model, (('Refresh', self.OnRefresh, self.refreshBmp, 'Refresh'), ('-', None, '', ''), ('Add group', self.OnAddGroup, self.addGroupBmp, ''), ('Remove group', self.OnRemoveGroup, self.remGroupBmp, ''), ('Rename group', self.OnRenameGroup, '-', ''), ('-', None, '', ''), ('Move up', self.OnMoveUp, self.moveUpBmp, ''), ('Move down', self.OnMoveDown, self.moveDownBmp, ''), ('Move fields to other group', self.OnMoveFieldToGroup, '-', ''), ), -1) self.Bind(wx.EVT_KEY_UP, self.OnKeyPressed) self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnBeginLabelEdit, id=wid) self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnEndLabelEdit, id=wid) self._groupedFields = [] self.canExplore = True self.active = True def destroy(self): EditorView.destroy(self) self.tokenImgLst = None def getFormulatorForm(self): return self.model.zopeObj.getResource() sysmsg = '
' def getRespMesg(self, html): msgTagStart = string.find(html, self.sysmsg) if msgTagStart != -1: msgStart = msgTagStart+len(self.sysmsg) msgEnd = string.find(html, '
', msgStart) if msgEnd != -1: return html[msgStart:msgEnd] return '' def statusUpdate(self, html): self.model.editor.setStatus(self.getRespMesg(html)) def refreshCtrl(self, selectGroupField=None): node = self.model.zopeObj groupedFields = node.getResource().zoa.props.Formulator.GroupedFields() # ZOA('Formulator_Form_GroupedFields') self._groupedFields = groupedFields self.DeleteAllItems() ri = self.AddRoot(node.name) if selectGroupField is not None: selGrp, selFld = selectGroupField if selGrp == selFld == None: si = ri else: si = None else: selGrp = selFld = None si = None for group, fields in groupedFields: gi = self.AppendItem(ri, group) if group == selGrp and selFld is None: si = gi for field, meta in fields: fi = self.AppendItem(gi, '%s [%s]' %(field, meta), data=wx.TreeItemData( (field, meta, group) )) if group == selGrp and field == selFld: si = fi self.Expand(gi) self.Expand(ri) if si is not None: self.SelectItem(si) self.EnsureVisible(si) def getItemLevel(self, itm): cnt = 0 root = self.GetRootItem() while itm != root: itm = self.GetItemParent(itm) #print itm, itm.IsOk() cnt = cnt + 1 return cnt def OnKeyPressed(self, event): key = event.KeyCode() if key == 13: self.EndEditLabel(self.GetSelection(), 0) def OnAddGroup(self, event): dlg = wx.TextEntryDialog(self, 'Enter new group name', 'Add Group', '') try: if dlg.ShowModal() == wx.ID_OK: grpName = dlg.GetValue() self.getFormulatorForm().add_group(grpName) self.refreshCtrl( (grpName, None) ) finally: dlg.Destroy() def OnRemoveGroup(self, event): ti = self.GetSelection() if self.getItemLevel(ti) != 1: wx.LogError('Selected item is not a group') else: grpName = self.GetItemText(ti) self.getFormulatorForm().remove_group(grpName) self.refreshCtrl( (grpName, None) ) def OnRenameGroup(self, event): ti = self.GetSelection() if self.getItemLevel(ti) != 1: wx.LogError('Selected item is not a group') else: self.EditLabel(ti) def OnMoveUp(self, event): ti = self.GetSelection() lev = self.getItemLevel(ti) lbl = self.GetItemText(ti) if lev == 1: self.statusUpdate(self.getFormulatorForm().manage_move_group_up(lbl)) self.refreshCtrl( (lbl, None) ) elif lev == 2: fld, mta, grp = self.GetItemData(ti).GetData() self.statusUpdate(self.getFormulatorForm().zoa.props.Formulator.move_field('up', grp, fld)) self.refreshCtrl( (grp, fld) ) else: wx.LogError('Cannot move root') def OnMoveDown(self, event): ti = self.GetSelection() lev = self.getItemLevel(ti) lbl = self.GetItemText(ti) if lev == 1: self.statusUpdate(self.getFormulatorForm().manage_move_group_down(lbl)) self.refreshCtrl( (lbl, None) ) elif lev == 2: fld, mta, grp = self.GetItemData(ti).GetData() self.statusUpdate(self.getFormulatorForm().zoa.props.Formulator.move_field('down', grp, fld)) self.refreshCtrl( (grp, fld) ) else: wx.LogError('Cannot move root (%d)'%lev) def OnMoveFieldToGroup(self, event): ti = self.GetSelection() lev = self.getItemLevel(ti) lbl = self.GetItemText(ti) if lev != 2: wx.LogError('Not a field') else: groups = map(lambda d: d[0], self._groupedFields) fld, mta, fromGroup = self.GetItemData(ti).GetData() groups.remove(fromGroup) dlg = wx.SingleChoiceDialog(self, 'Choose group to move to', 'Move to other group', groups) try: if dlg.ShowModal() == wx.ID_OK: toGroup = dlg.GetStringSelection() self.statusUpdate( self.getFormulatorForm().zoa.props.Formulator.move_field( 'group', fromGroup, fld, toGroup)) self.refreshCtrl( (toGroup, fld) ) finally: dlg.Destroy() def OnBeginLabelEdit(self, event): ti = event.GetItem() if self.getItemLevel(ti) != 1: event.Veto() def OnEndLabelEdit(self, event): ti = event.GetItem() oldName = self.GetItemText(ti) newName = event.GetLabel() self.statusUpdate(self.getFormulatorForm().manage_rename_group(oldName, {'new_name':newName})) self.refreshCtrl( (newName, None) ) def OnRefresh(self, event): ti = self.GetSelection() lev = self.getItemLevel(ti) lbl = self.GetItemText(ti) if lev == 2: fld, mta, grp = self.GetItemData(ti).GetData() self.refreshCtrl( (grp, fld) ) elif lev == 1: self.refreshCtrl( (lbl, None) ) elif lev == 0: self.refreshCtrl( (None, None) ) else: self.refreshCtrl( None ) #---Explorer-------------------------------------------------------------------- # Node in the explorer from Views import SourceViews from ZopeLib import ZopeViews from ZopeLib.ZopeExplorer import ZopeItemNode, ZopeNode, zopeClassMap class FormulatorFormNode(ZopeItemNode): Model = FormulatorFormModel defaultViews = (FormulatorFormOrderView,) additionalViews = (ZopeViews.ZopeUndoView, ZopeViews.ZopeSecurityView) def isFolderish(self): return True def checkentry(self, name, metatype, path): return apply(FormulatorFieldNode, (name, path, self.clipboard, -1, self, self.server, self.root, self.properties, metatype)) class FormulatorFieldNode(ZopeNode): Model = FormulatorFormModel def open(self, editor): editor.explorer.controllers['zope'].doInspectZopeItem(self) return None, None zopeClassMap['Formulator Form'] = FormulatorFormNode #---PropertyEditors------------------------------------------------------------- from PropEdit.PropertyEditors import EnumConfPropEdit class EncTypeEnumConfPropEdit(EnumConfPropEdit): def getValues(self): return ['', 'application/x-www-form-urlencoded', 'multipart/form-data'] class MethodEnumConfPropEdit(EnumConfPropEdit): def getValues(self): return ['GET', 'POST'] #---Companion------------------------------------------------------------------- def fieldify(props, prefix='field_'): res = {} for n, v in props.items(): if type(v) == type([]): res[prefix+n] = string.join(v, '\n') else: res[prefix+n] = str(v) return res # Companion used for creation from palette and inspection/posting of props from ZopeLib.ZopeCompanions import CustomZopePropsMixIn, ZopeCompanion, BoolZopePropEdit, EvalZopePropEdit from Companions.BaseCompanions import HelperDTC from PropEdit.PropertyEditors import ContainerConfPropEdit import RTTI class FieldBoolZopePropEdit(BoolZopePropEdit): boolKeyMap = {'true': '1', 'false': ''} class DateTimeFieldConfPropEdit(ContainerConfPropEdit): def getSubCompanion(self): return DateTimeFieldSubCompanion ZopeCompanion.propMapping.update({'field_boolean': FieldBoolZopePropEdit, 'form_enctype': EncTypeEnumConfPropEdit, 'form_method': MethodEnumConfPropEdit, 'field_date': DateTimeFieldConfPropEdit}) class FormulatorFormZC(CustomZopePropsMixIn, ZopeCompanion): def create(self): prodPath = '/manage_addProduct/Formulator/' mime, res = self.call(self.objPath, prodPath+'manage_add', id=self.name, title='', URL1='', submit='') def getProps(self): #path, name = os.path.split(self.objPath) mime, res = self.call(self.objPath, 'zoa/props/Formulator/Form') return eval(res) def SetProp(self, name, value): props = self.getProps() props[name] = value groups = props['Groups']; del props['Groups'] if name == 'Groups': pass else: mime, res = self.callkw(self.objPath, 'manage_settings', fieldify(props)) propOrder = ('title', 'row_length', 'action', 'method', 'enctype', 'Groups') propTypeMap = {'title': ('string', 'title'), 'row_length': ('int', 'row_length'), 'action': ('string', 'action'), 'method': ('form_method', 'method'), 'enctype': ('form_enctype', 'enctype'), 'Groups': ('list', 'Groups'), } class DateTimeFieldSubCompanion(HelperDTC): def __init__(self, name, designer, ownerCompanion, obj, ownerPropWrap): HelperDTC.__init__(self, name, designer, ownerCompanion, obj, ownerPropWrap) self.propItems = [] def getPropEditor(self, prop): return EvalZopePropEdit def getPropList(self): if self.obj is None: raise 'First assign a DateTime to the property.' name, val = self.ownerCompn.propTypeMap[self.name] subProps = [('sub%s_year'%name, self.obj.year() ), ('sub%s_month'%name, self.obj.month() ), ('sub%s_day'%name, self.obj.day() ), ('sub%s_hour'%name, self.obj.hour() ), ('sub%s_minute'%name, self.obj.minute() ),] propLst = [] for prop in subProps: propLst.append(RTTI.PropertyWrapper(prop[0], 'NameRoute', self.GetProp, self.SetProp)) self.propItems = subProps return {'constructor': [], 'properties': propLst} def GetProp(self, name): for prop in self.propItems: if prop[0] == name: return prop[1] def SetProp(self, name, value): raise 'Property editing not supported yet' def keyListFromDictList(key, dctLst): res = [] for dct in dctLst: res.append(dct[key]) return res def dictListFind(name, value, dctLst): for dct in dctLst: if dct.has_key(name) and dct[name] == value: return dct return None def select_d(entries_list, from_clause, where_clause): """ SQL wannabe """ pass FieldPropMap = {'FileField': 'string', #'MultiCheckBoxField': 'list', #'LinesField': 'list', #'ListField': 'list', #'TextAreaField': 'stringlist', #'MultiCheckboxField': 'stringlist', #'MultiListField': 'stringlist', 'EmailField': 'string', 'CheckBoxField': 'field_boolean', 'PasswordField': 'string', #'FloatField': 'float', 'PatternField': 'string', 'LinkField': 'string', 'StringField': 'string', #'RawTextAreaField': 'stringlist', #'IntegerField': 'string', #'RadioField': 'stringlist', 'DateTimeField': 'field_date', } NotSupportedPropTypes = ['date'] class FormulatorFieldZC(CustomZopePropsMixIn, ZopeCompanion): def create(self): # XXX move to one zoa call assertfilteredmetatypesfor(container_metatype) # assert that called only in Formulator mime, res = self.call(self.objPath, 'zoa/metatype') assert res=='Formulator Form', \ 'Formulator fields can only be created inside a Formulator Form' # fetch valid field types mime, res = self.call(self.objPath, 'zoa/filteredmetatypes') availableFields = eval(res) fieldNames = keyListFromDictList('name', availableFields) dlg = wx.SingleChoiceDialog(None, 'Choose the formulator field to add', 'Add field', fieldNames) try: if dlg.ShowModal() == wx.ID_OK: fieldName = dlg.GetStringSelection() else: return finally: dlg.Destroy() mime, res = self.call(self.objPath, 'manage_addProduct/Formulator/manage_addField', id=self.name, title='', fieldname=fieldName, URL1='', submit='') def getPropertyMap(self): propMap = [] for (propName, propVal) in self.propItems: propMap.append( {'id': propName, 'type': self.getPropertyType(propName)} ) return propMap def getPropertyType(self, name): if self.propTypeMap.has_key(name): return self.propTypeMap[name][0] else: return 'default' def getProps(self): mime, res = self.call(self.objPath, 'zoa/props/Formulator/Field') from ZopeLib.DateTime import DateTime lst = eval(res) self.propTypeMap = {} dct = {} for name, val, tpe, opts in lst: propEditType = FieldPropMap.get(tpe, 'default') if propEditType in NotSupportedPropTypes: continue self.propTypeMap[name] = (propEditType, name) dct[name] = val return dct def SetProp(self, name, value): props = self.getProps() props[name] = value messages = props['Messages']; del props['Messages'] ## overrides = props['Overrides']; del props['Overrides'] if name == 'Messages': mime, res = self.callkw(self.objPath, 'manage_messages', fieldify(messages, '')) ## elif name == 'Overrides': ## mime, res = self.callkw(self.objPath, 'manage_override', fieldify(overrides)) else: ##print fieldify(props) mime, res = self.callkw(self.objPath, 'manage_edit', fieldify(props)) propOrder = None # Add to the Zope palette import PaletteStore # form PaletteStore.paletteLists['Zope'].append('Formulator Form') PaletteStore.compInfo['Formulator Form'] = ['FormulatorForm', FormulatorFormZC] # fields PaletteStore.paletteLists['Zope'].append('FormulatorField') fieldCompInfo = ['FormulatorField', FormulatorFieldZC] PaletteStore.compInfo['FormulatorField'] = fieldCompInfo for field in field_meta_types: PaletteStore.compInfo[field] = fieldCompInfo