# # Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/) # This module is free software, and you may redistribute it and/or modify # under the same terms as Python, so long as this copyright message and # disclaimer are retained in their original form. # # IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR # DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING # OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # # $Id: htmltemplate.py,v 1.24 2001-09-27 06:45:58 richard Exp $ import os, re, StringIO, urllib, cgi, errno import hyperdb, date class Base: def __init__(self, db, templates, classname, nodeid=None, form=None, filterspec=None): # TODO: really not happy with the way templates is passed on here self.db, self.templates = db, templates self.classname, self.nodeid = classname, nodeid self.form, self.filterspec = form, filterspec self.cl = self.db.classes[self.classname] self.properties = self.cl.getprops() class Plain(Base): ''' display a String property directly; display a Date property in a specified time zone with an option to omit the time from the date stamp; for a Link or Multilink property, display the key strings of the linked nodes (or the ids if the linked class has no key property) ''' def __call__(self, property, escape=0): if not self.nodeid and self.form is None: return '[Field: not called from item]' propclass = self.properties[property] if self.nodeid: value = self.cl.get(self.nodeid, property) else: # TODO: pull the value from the form if isinstance(propclass, hyperdb.Multilink): value = [] else: value = '' if isinstance(propclass, hyperdb.String): if value is None: value = '' else: value = str(value) elif isinstance(propclass, hyperdb.Date): value = str(value) elif isinstance(propclass, hyperdb.Interval): value = str(value) elif isinstance(propclass, hyperdb.Link): linkcl = self.db.classes[propclass.classname] k = linkcl.labelprop() if value: value = str(linkcl.get(value, k)) else: value = '[unselected]' elif isinstance(propclass, hyperdb.Multilink): linkcl = self.db.classes[propclass.classname] k = linkcl.labelprop() value = ', '.join([linkcl.get(i, k) for i in value]) else: s = 'Plain: bad propclass "%s"'%propclass if escape: return cgi.escape(value) return value class Field(Base): ''' display a property like the plain displayer, but in a text field to be edited ''' def __call__(self, property, size=None, height=None, showid=0): if not self.nodeid and self.form is None and self.filterspec is None: return '[Field: not called from item]' propclass = self.properties[property] if self.nodeid: value = self.cl.get(self.nodeid, property, None) # TODO: remove this from the code ... it's only here for # handling schema changes, and they should be handled outside # of this code... if isinstance(propclass, hyperdb.Multilink) and value is None: value = [] elif self.filterspec is not None: if isinstance(propclass, hyperdb.Multilink): value = self.filterspec.get(property, []) else: value = self.filterspec.get(property, '') else: # TODO: pull the value from the form if isinstance(propclass, hyperdb.Multilink): value = [] else: value = '' if (isinstance(propclass, hyperdb.String) or isinstance(propclass, hyperdb.Date) or isinstance(propclass, hyperdb.Interval)): size = size or 30 if value is None: value = '' else: value = cgi.escape(value) value = '"'.join(value.split('"')) s = ''%(property, value, size) elif isinstance(propclass, hyperdb.Link): linkcl = self.db.classes[propclass.classname] l = ['') s = '\n'.join(l) elif isinstance(propclass, hyperdb.Multilink): linkcl = self.db.classes[propclass.classname] list = linkcl.list() height = height or min(len(list), 7) l = ['') s = '\n'.join(l) else: s = 'Plain: bad propclass "%s"'%propclass return s class Menu(Base): ''' for a Link property, display a menu of the available choices ''' def __call__(self, property, size=None, height=None, showid=0): propclass = self.properties[property] if self.nodeid: value = self.cl.get(self.nodeid, property) else: # TODO: pull the value from the form if isinstance(propclass, hyperdb.Multilink): value = [] else: value = None if isinstance(propclass, hyperdb.Link): linkcl = self.db.classes[propclass.classname] l = ['') return '\n'.join(l) if isinstance(propclass, hyperdb.Multilink): linkcl = self.db.classes[propclass.classname] list = linkcl.list() height = height or min(len(list), 7) l = ['') return '\n'.join(l) return '[Menu: not a link]' #XXX deviates from spec class Link(Base): ''' for a Link or Multilink property, display the names of the linked nodes, hyperlinked to the item views on those nodes for other properties, link to this node with the property as the text ''' def __call__(self, property=None, **args): if not self.nodeid and self.form is None: return '[Link: not called from item]' propclass = self.properties[property] if self.nodeid: value = self.cl.get(self.nodeid, property) else: if isinstance(propclass, hyperdb.Multilink): value = [] else: value = '' if isinstance(propclass, hyperdb.Link): linkname = propclass.classname if value is None: return '[not assigned]' linkcl = self.db.classes[linkname] k = linkcl.labelprop() linkvalue = linkcl.get(value, k) return '%s'%(linkname, value, linkvalue) if isinstance(propclass, hyperdb.Multilink): linkname = propclass.classname linkcl = self.db.classes[linkname] k = linkcl.labelprop() l = [] for value in value: linkvalue = linkcl.get(value, k) l.append('%s'%(linkname, value, linkvalue)) return ', '.join(l) return '%s'%(self.classname, self.nodeid, value) class Count(Base): ''' for a Multilink property, display a count of the number of links in the list ''' def __call__(self, property, **args): if not self.nodeid: return '[Count: not called from item]' propclass = self.properties[property] value = self.cl.get(self.nodeid, property) if isinstance(propclass, hyperdb.Multilink): return str(len(value)) return '[Count: not a Multilink]' # XXX pretty is definitely new ;) class Reldate(Base): ''' display a Date property in terms of an interval relative to the current date (e.g. "+ 3w", "- 2d"). with the 'pretty' flag, make it pretty ''' def __call__(self, property, pretty=0): if not self.nodeid and self.form is None: return '[Reldate: not called from item]' propclass = self.properties[property] if isinstance(not propclass, hyperdb.Date): return '[Reldate: not a Date]' if self.nodeid: value = self.cl.get(self.nodeid, property) else: value = date.Date('.') interval = value - date.Date('.') if pretty: if not self.nodeid: return 'now' pretty = interval.pretty() if pretty is None: pretty = value.pretty() return pretty return str(interval) class Download(Base): ''' show a Link("file") or Multilink("file") property using links that allow you to download files ''' def __call__(self, property, **args): if not self.nodeid: return '[Download: not called from item]' propclass = self.properties[property] value = self.cl.get(self.nodeid, property) if isinstance(propclass, hyperdb.Link): linkcl = self.db.classes[propclass.classname] linkvalue = linkcl.get(value, k) return '%s'%(linkcl, value, linkvalue) if isinstance(propclass, hyperdb.Multilink): linkcl = self.db.classes[propclass.classname] l = [] for value in value: linkvalue = linkcl.get(value, k) l.append('%s'%(linkcl, value, linkvalue)) return ', '.join(l) return '[Download: not a link]' class Checklist(Base): ''' for a Link or Multilink property, display checkboxes for the available choices to permit filtering ''' def __call__(self, property, **args): propclass = self.properties[property] if self.nodeid: value = self.cl.get(self.nodeid, property) elif self.filterspec is not None: value = self.filterspec.get(property, []) else: value = [] if (isinstance(propclass, hyperdb.Link) or isinstance(propclass, hyperdb.Multilink)): linkcl = self.db.classes[propclass.classname] l = [] k = linkcl.labelprop() for optionid in linkcl.list(): option = linkcl.get(optionid, k) if optionid in value or option in value: checked = 'checked' else: checked = '' l.append('%s:'%( option, checked, property, option)) return '\n'.join(l) return '[Checklist: not a link]' class Note(Base): ''' display a "note" field, which is a text area for entering a note to go along with a change. ''' def __call__(self, rows=5, cols=80): # TODO: pull the value from the form return ''%(rows, cols) # XXX new function class List(Base): ''' list the items specified by property using the standard index for the class ''' def __call__(self, property, reverse=0): propclass = self.properties[property] if isinstance(not propclass, hyperdb.Multilink): return '[List: not a Multilink]' fp = StringIO.StringIO() value = self.cl.get(self.nodeid, property) if reverse: value.reverse() # TODO: really not happy with the way templates is passed on here index(fp, self.templates, self.db, propclass.classname, nodeids=value, show_display_form=0) return fp.getvalue() # XXX new function class History(Base): ''' list the history of the item ''' def __call__(self, **args): if self.nodeid is None: return "[History: node doesn't exist]" l = ['
| Date | ', 'User | ', 'Action | ', 'Args | '] for id, date, user, action, args in self.cl.history(self.nodeid): l.append('
| %s | %s | %s | %s |