[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
r6590 - in trunk/gnue-appserver: share src src/generator
From: |
johannes |
Subject: |
r6590 - in trunk/gnue-appserver: share src src/generator |
Date: |
Mon, 1 Nov 2004 02:43:18 -0600 (CST) |
Author: johannes
Date: 2004-11-01 02:43:14 -0600 (Mon, 01 Nov 2004)
New Revision: 6590
Added:
trunk/gnue-appserver/src/generator/
trunk/gnue-appserver/src/generator/__init__.py
trunk/gnue-appserver/src/generator/classdef.py
trunk/gnue-appserver/src/generator/form.py
trunk/gnue-appserver/src/generator/layout.py
Removed:
trunk/gnue-appserver/src/labels.py
Modified:
trunk/gnue-appserver/share/gnue.gsd
Log:
Reorganized resource-generation capabilities; generate grid forms when possible
Modified: trunk/gnue-appserver/share/gnue.gsd
===================================================================
--- trunk/gnue-appserver/share/gnue.gsd 2004-10-30 22:01:35 UTC (rev 6589)
+++ trunk/gnue-appserver/share/gnue.gsd 2004-11-01 08:43:14 UTC (rev 6590)
@@ -893,12 +893,10 @@
<value field="gnue_nullable">TRUE</value>
<value field="gnue_type">string</value>
<value field="gnue_code">
- from gnue.appserver import labels
- labels.find = find
- labels.abort = abort
- formGen = labels.FormGenerator (self, language, connection,
- formwidth, formheight)
- return formGen.generateForm ()
+ from gnue.appserver.generator.form import FormGenerator
+ formGen = FormGenerator (session, self, language, connection,
+ formwidth, formheight)
+ return formGen.run ()
</value>
</row>
</rows>
Property changes on: trunk/gnue-appserver/src/generator
___________________________________________________________________
Name: svn:ignore
+ *.pyc
Added: trunk/gnue-appserver/src/generator/__init__.py
===================================================================
Added: trunk/gnue-appserver/src/generator/classdef.py
===================================================================
--- trunk/gnue-appserver/src/generator/classdef.py 2004-10-30 22:01:35 UTC
(rev 6589)
+++ trunk/gnue-appserver/src/generator/classdef.py 2004-11-01 08:43:14 UTC
(rev 6590)
@@ -0,0 +1,478 @@
+# GNU Enterprise Application Server - Generators - Class definition
+#
+# Copyright 2001-2004 Free Software Foundation
+#
+# This file is part of GNU Enterprise
+#
+# GNU Enterprise is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+
+import mx
+
+from gnue.appserver.classrep import Namespace
+
+# =============================================================================
+# This class implements a collection of properties for a business class
+# =============================================================================
+
+class ClassDef:
+
+ # ---------------------------------------------------------------------------
+ # Constructor
+ # ---------------------------------------------------------------------------
+
+ def __init__ (self, session, klass, language, asReference = False):
+ """
+ @param session: Language interface session instance
+ @param klass: Language interface object with the class to be processed
+ @param language: language to be preferred for labels
+ @param asReference: if True, only references should be held
+ """
+
+ self.__session = session
+ self.__class = klass
+ self.__language = language
+ self.classname = Namespace.createName (klass.module.name, klass.name)
+ self.classLabel = "%s %s" % (klass.module.name.title (),
+ klass.name.title ())
+ self.isReference = asReference
+ self.isLookup = False
+
+ (self.properties, self.specials) = self.__loadProperties ()
+ self.__loadLabels (klass.gnue_id, self.properties)
+
+ self.__updateReferences ()
+
+ self.virtualPages = self.__buildVirtualPages ()
+
+
+ # ---------------------------------------------------------------------------
+ # Get the name of the sort column for a class definitino
+ # ---------------------------------------------------------------------------
+
+ def sortColumn (self):
+ """
+ This function iterates over all search-properties and returns the property
+ with the lowest search-value or None if no search properties are available
+
+ @return: property instance with the lowest search-order or None
+ """
+
+ search = []
+ for item in self.properties:
+ if item.search is not None:
+ search.append ((item.search, item.dbField))
+
+ search.sort ()
+
+ return len (search) and search [0][1] or None
+
+
+ # ---------------------------------------------------------------------------
+ # Create a sequence of languages to be processed for labels
+ # ---------------------------------------------------------------------------
+
+ def __buildLanguageList (self, language):
+ """
+ This function creates a sequence of languages to be processed for labels.
+ The order is from most general (starting with 'C') to most specific.
+
+ @param language: a language like 'de_AT'
+ @return: sequence of languages like ['C', 'de', 'de_AT']
+ """
+
+ result = ['C']
+
+ if '_' in language:
+ add = language.split ('_') [0]
+ if not add in result:
+ result.append (add)
+
+ if not language in result:
+ result.append (language)
+
+ return result
+
+
+ # ---------------------------------------------------------------------------
+ # Load all properties and calculated fields of the requested class
+ # ---------------------------------------------------------------------------
+
+ def __loadProperties (self):
+ """
+ This function populates two squences of properties of the given class.
+ The sequence 'properties' contains all 'normal' properties and calculated
+ fields, and the sequence 'specials' holds all allowed special properties.
+ Both sequences are unordered. If this instance had 'isReference' set, only
+ reference properties will be added.
+
+ @return: tuple with both sequences (properties, specials)
+ """
+
+ properties = []
+ specials = []
+ classId = self.__class.gnue_id
+
+ cond = {'gnue_class': classId}
+ pList = ['gnue_name', 'gnue_length', 'gnue_scale', 'gnue_type']
+
+ for prop in self.__session.find ('gnue_property', cond, [], pList):
+ if prop.gnue_module.gnue_name == 'gnue' or prop.gnue_type == 'id':
+ if prop.gnue_name in ['createdate', 'createuser', 'modifydate',
+ 'modifyuser']:
+ if not self.isReference:
+ specials.append (Property (self, prop, isSpecial = True))
+
+ continue
+
+ # Do not include filter properties
+ filterClass = prop.gnue_class.gnue_filter
+ if filterClass:
+ if prop.gnue_name == filterClass.gnue_name and \
+ prop.gnue_module.gnue_name == filterClass.gnue_module.gnue_name:
+ continue
+
+ properties.append (Property (self, prop))
+
+ # Add all calculated fields from the procedure definitions
+ cond = ['and', ['eq', ['field', 'gnue_class'], ['const', classId]],
+ ['notnull', ['field', 'gnue_type']],
+ ['like', ['field', 'gnue_name'], ['const', 'get%']]]
+
+ for proc in self.__session.find ('gnue_procedure', cond, [], pList):
+ # calculated fields must not have parameters
+ if self.__session.find ('gnue_parameter',
+ {'gnue_procedure': proc.gnue_id}, [], []):
+ continue
+
+ properties.append (Property (self, proc, isCalculated = True))
+
+ return (properties, specials)
+
+
+ # ---------------------------------------------------------------------------
+ # Load labels for the given class and update the property sequence
+ # ---------------------------------------------------------------------------
+
+ def __loadLabels (self, classId, properties):
+ """
+ This function loads all label information for a given class and updates all
+ items given by a property sequence. All hidden properties (position = 0)
+ are removed from the property sequence.
+
+ @param classId: gnue_id of the class to fetch labels for
+ @param properties: unordered sequence of properties to be updated
+ """
+
+ pList = ['gnue_label', 'gnue_position', 'gnue_search', 'gnue_info',
+ 'gnue_page']
+
+ for locale in self.__buildLanguageList (self.__language):
+ cond = ['and', ['eq', ['field', 'gnue_language'], ['const', locale]],
+ ['eq', ['field', 'gnue_property.gnue_class'],
+ ['const', classId]]]
+
+ if self.isReference:
+ cond.append (['or', ['notnull', ['field', 'gnue_search']],
+ ['notnull', ['field', 'gnue_info']]])
+
+ for label in self.__session.find ('gnue_label', cond, [], pList):
+
+ full = Namespace.createName (label.gnue_property.module.name,
+ label.gnue_property.name)
+ if full == 'gnue_id' and len (label.label):
+ self.classLabel = label.label
+ continue
+
+ for item in properties:
+ if item.propDef.gnue_id == label.gnue_property.gnue_id:
+ item.updateLabel (label)
+
+ # Add labels for calculated properties
+ cond = ['and', ['eq', ['field', 'gnue_language'], ['const', locale]],
+ ['eq', ['field', 'gnue_procedure.gnue_class'],
+ ['const', classId]]]
+
+ if self.isReference:
+ cond.append (['or', ['notnull', ['field', 'gnue_search']],
+ ['notnull', ['field', 'gnue_info']]])
+
+ for label in self.__session.find ('gnue_label', cond, [], pList):
+ for item in properties:
+ if item.propDef.gnue_id == label.gnue_procedure.gnue_id:
+ item.updateLabel (label)
+
+ if self.isReference:
+ for item in properties [:]:
+ if item.search is None and item.info is None:
+ properties.remove (item)
+
+ # Remove all properties with a explicit position of 0. These are 'hidden'
+ # properties.
+ for item in properties [:]:
+ if item.position == 0:
+ properties.remove (item)
+
+
+ # ---------------------------------------------------------------------------
+ # Update all reference properties
+ # ---------------------------------------------------------------------------
+
+ def __updateReferences (self):
+ """
+ This function updates reference information for the class definition. If a
+ class definition is a reference, all properties will be sorted according to
+ their search- and info-attributes. If the class definition is not a
+ reference, this function iterates over all properties, and creates such
+ reference class definitions for reference properties.
+ """
+
+ if self.isReference:
+ order = []
+
+ for item in self.properties:
+ order.append ((item.search or item.info, item))
+
+ order.sort ()
+ self.properties = [item [1] for item in order]
+
+ # a reference is a 'lookup reference' if the first search field has a
+ # search-order other than 0. Otherwise it would be a 'search reference'
+ first = self.properties [0]
+ self.isLookup = first.search is not None and first.search != 0
+
+ for item in self.properties:
+ item.updateStyle ()
+
+ else:
+ for item in self.properties:
+ if '_' in item.propDef.gnue_type:
+ (refMod, refName) = Namespace.splitName (item.propDef.gnue_type)
+ refClass = self.__session.find ('gnue_class',
+ {'gnue_name': refName, 'gnue_module.gnue_name': refMod}, [], [])
+ cDef = ClassDef (self.__session, refClass [0], self.__language, True)
+
+ if len (cDef.properties):
+ item.reference = cDef
+ for refItem in cDef.properties:
+ refItem.fieldName = "%s%s" % (item.dbField, refItem.fieldName)
+
+
+ # ---------------------------------------------------------------------------
+ # Create a sequence of all virtual pages
+ # ---------------------------------------------------------------------------
+
+ def __buildVirtualPages (self):
+ """
+ This function creates a sequence of all virtual pages. A virtual page is
+ tuple with a pagename and a sequence of all properties of the page, already
+ ordered according to their position attribute.
+
+ @return: sequence of page-tuples: (name, [property, property, ...])
+ """
+
+ # First create a dictionary with all properties per page
+ pageDict = {}
+ for item in self.properties:
+ if not pageDict.has_key (item.page):
+ pageDict [item.page] = []
+ pageDict [item.page].append (item)
+
+ # Order all properties per page according to position, where all properties
+ # with a 'None'-position are at the end, ordered by their label
+ for (pageName, items) in pageDict.items ():
+ nullOrder = []
+ posOrder = []
+
+ for item in items:
+ if item.position is None:
+ nullOrder.append ((item.label, item))
+ else:
+ posOrder.append ((item.position, item.label, item))
+
+ nullOrder.sort ()
+ posOrder.sort ()
+
+ pageDict [pageName] = [item [-1] for item in posOrder + nullOrder]
+
+ # now create a sequence of tuples, ordered by the pagename
+ pageNames = pageDict.keys ()
+ pageNames.sort ()
+
+ return [(p, pageDict [p]) for p in pageNames]
+
+
+
+
+# =============================================================================
+# This class implements a single property of a class
+# =============================================================================
+
+class Property:
+
+ # ---------------------------------------------------------------------------
+ # Constructor
+ # ---------------------------------------------------------------------------
+
+ def __init__ (self, parent, propDef, isCalculated = False, isSpecial =
False):
+ """
+ @param parent: class definition instance which holds this property
+ @param propDef: language interface class of the property to encapsulate
+ @param isCalculated: set to True if the property is a calculated field
+ @param isSpecial: set to True if the property is a special property
+ """
+
+ self.parent = parent
+ self.propDef = propDef
+ self.label = propDef.gnue_name
+ self.page = propDef.module.name.title ()
+ self.position = None
+ self.search = None
+ self.info = None
+ self.labelPos = None
+
+ self.fullName = Namespace.createName (propDef.gnue_module.gnue_name,
+ propDef.gnue_name)
+ if isCalculated:
+ self.dbField = Namespace.createName (propDef.gnue_module.gnue_name,
+ propDef.gnue_name [3:])
+ else:
+ self.dbField = self.fullName
+
+ self.fieldName = "fld%s" % self.dbField.title ().replace ('_', '')
+ self.typecast = None
+ self.inputmask = None
+ self.displaymask = None
+ self.style = isSpecial and 'label' or None
+
+ masks = ['%x', '%X', '%x %X']
+
+ if propDef.gnue_type in ['date', 'time', 'datetime']:
+ typeId = ['date','time', 'datetime'].index (propDef.gnue_type)
+
+ self.typecast = 'date'
+ self.inputmask = masks [typeId]
+ self.displaymask = masks [typeId]
+ self.fieldLength = len (mx.DateTime.now ().strftime (self.displaymask))
+
+ elif propDef.gnue_type == 'number':
+ self.typecast = 'number'
+ self.fieldLength = (propDef.gnue_length or 0) + \
+ (propDef.gnue_scale or 0) + 1
+
+ elif propDef.gnue_type == 'boolean':
+ self.fieldLength = 1
+ self.style = 'checkbox'
+
+ else:
+ self.fieldLength = propDef.gnue_length or 32
+
+ self.stretchable = propDef.gnue_type == 'string' and \
+ propDef.gnue_length is None
+
+ if self.stretchable:
+ self.minHeight = None
+ else:
+ self.minHeight = 1
+ self.isSpecial = isSpecial
+ self.reference = None
+
+
+
+ # ---------------------------------------------------------------------------
+ # Update the label information for the property
+ # ---------------------------------------------------------------------------
+
+ def updateLabel (self, labelDef):
+ """
+ This function updates the label information for the encapsulated property
+
+ @param labelDef: language interface object with the lable information
+ """
+
+ self.label = labelDef.label
+ self.page = labelDef.page and labelDef.page or self.page
+ self.position = labelDef.position
+ self.search = labelDef.search
+ self.info = labelDef.info
+
+
+ # ---------------------------------------------------------------------------
+ # Update the property style depending on reference information
+ # ---------------------------------------------------------------------------
+
+ def updateStyle (self):
+ """
+ This function set's the style for reference properties.
+ """
+
+ if self.parent.isReference:
+ # if we're part of a lookup use either a dropdown or a label depending
+ # wether we're a search- or info-property
+ if self.parent.isLookup:
+ self.style = self.search and 'dropdown' or 'label'
+
+ # in a search-reference all properties except the first one are labels
+ else:
+ if self.parent.properties [0] != self:
+ self.style = 'label'
+
+
+
+ # ---------------------------------------------------------------------------
+ # Get the width for all widgets of a property
+ # ---------------------------------------------------------------------------
+
+ def widgetWidth (self, maxSpace = None):
+ """
+ This function calculates the width (in character) for all widgets needed by
+ a property. This includes any reference properties if available.
+
+ @param maxSpace: maximum available space for the property
+ @return: horizontal space needed for the property
+ """
+
+ # make sure we have a minimum length of 7 for dropdown properties
+ result = max (self.fieldLength, self.style == 'dropdown' and 7 or None)
+
+ if self.reference is None:
+ # stretchable properties are allowed to consume all space
+ if self.stretchable:
+ result = maxSpace
+
+ else:
+ # if we have a space limit given use the minimum value
+ if maxSpace is not None:
+ result = min (maxSpace, result)
+
+ else:
+ # the widgetWidth for lookup properties is the sum of all reference
+ # elements plus a space between every reference element
+ if self.reference.isLookup:
+ result = len (self.reference.properties) - 1
+
+ for item in self.reference.properties:
+ result += item.widgetWidth (maxSpace)
+
+
+ # the width for a search property would be the length of the first
+ # property and the length of the lookup-button
+ else:
+ result = self.reference.properties [0].widgetWidth (maxSpace) + 6
+
+ return result
+
Property changes on: trunk/gnue-appserver/src/generator/classdef.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: trunk/gnue-appserver/src/generator/form.py
===================================================================
--- trunk/gnue-appserver/src/generator/form.py 2004-10-30 22:01:35 UTC (rev
6589)
+++ trunk/gnue-appserver/src/generator/form.py 2004-11-01 08:43:14 UTC (rev
6590)
@@ -0,0 +1,448 @@
+# GNU Enterprise Application Server - Generators - Form Generator
+#
+# Copyright 2001-2004 Free Software Foundation
+#
+# This file is part of GNU Enterprise
+#
+# GNU Enterprise is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+
+import string
+import classdef
+import layout
+
+# =============================================================================
+# This class implements the form generator
+# =============================================================================
+
+class FormGenerator:
+
+ # ---------------------------------------------------------------------------
+ # Constructor
+ # ---------------------------------------------------------------------------
+
+ def __init__ (self, sess, klass, lang, connection, formWidth, formHeight):
+ """
+ Create a new instance of a form generator.
+
+ @param sess: language interface Session instance
+ @param klass: language interface object of the class to generate a form for
+ @param lang: language to generate the form for, i.e. 'de_AT'
+ @param connection: name of the connection to use for datasources
+ @param formWidth: maximum width of the generated form
+ @param formHeight: maximum height of the generated form
+ """
+
+ self.__session = sess
+ self.__class = klass
+ self.__language = lang
+ self.__connection = connection
+ self.__maxWidth = formWidth
+ self.__maxHeight = formHeight
+
+ self.__classDef = classdef.ClassDef (sess, klass, lang)
+
+ self.__updateLogic ()
+
+ self.layoutManager = self.__createManager ()
+
+ self.__options = self.__xml ('options',
+ {None: self.__xml ('author',
+ {None: [u_("GNU Enterprise Application Server")]}) + \
+ self.__xml ('version', {None: ['1.0']}) + \
+ self.__xml ('description',
+ {None: [u_('Generated form for class "%s"') \
+ % self.__classDef.classname]})})
+
+
+ # ---------------------------------------------------------------------------
+ # Run the generator
+ # ---------------------------------------------------------------------------
+
+ def run (self):
+ """
+ This function executes the generator and returns a string with the form's
+ XML code.
+
+ @return: string with XML code of the generated form
+ """
+
+ code = [u'<?xml version="1.0" encoding="utf-8"?>']
+ code.extend (self.__xml ('form', {'title': self.__classDef.classLabel,
+ None: self.__options}, "", True))
+
+ for item in self.__sources.values ():
+ code.extend (self.__xml ('datasource', item, " "))
+
+ code.extend (self.__xml ('logic', {None: self.__blocksToXML ()}, " "))
+
+ tabPos = len (self.layoutManager.visualPages) > 1 and 'top' or 'none'
+ code.extend (self.__xml ('layout', {'xmlns:c': 'GNUe:Layout:Char ',
+ 'c:height': self.layoutManager.maxPageHeight,
+ 'c:width' : self.layoutManager.maxPageWidth,
+ 'tabbed' : tabPos,
+ None: self.__pagesToXML ()}, " "))
+
+ code.append ('</form>')
+
+ return string.join (code, "\n")
+
+
+ # ---------------------------------------------------------------------------
+ # Update the logic of the form (blocks and datasources)
+ # ---------------------------------------------------------------------------
+
+ def __updateLogic (self):
+ """
+ This function updates both dictionaries __sources and __blocks based on the
+ class definition.
+ """
+
+ self.__sources = {}
+ self.__blocks = {}
+
+ attrs = {}
+ order = self.__classDef.sortColumn ()
+ if order is not None:
+ attrs ['order_by'] = order
+
+ self.__addToSources ('dtsMaster', self.__classDef.classname, attrs)
+
+ for item in self.__classDef.properties + self.__classDef.specials:
+ # First process the property
+ #if item.reference: # is None or item.reference.isLookup:
+ self.__addToBlocks ('blkMaster', 'dtsMaster', item)
+ item.block = 'blkMaster'
+
+ # and if it is a reference all parts of the reference
+ if item.reference is not None:
+ for refItem in item.reference.properties:
+ table = item.reference.classname
+
+ # dropdown widgets need an additional datasource for their values
+ if refItem.style == 'dropdown' or refItem.style is None:
+ source = "dts%s" % item.reference.classname
+ refItem.block = 'blkMaster'
+ refItem.source = source
+
+ self.__addToSources (source, table, {'prequery': 'Y'})
+
+ # label widgets need a detail-source connected to the master as well
+ # as an additional block bound to the detail-source
+ elif refItem.style == 'label':
+ source = "dtsLookup%s%s" % (item.dbField, table)
+ block = "blkLookup%s%s" % (item.dbField, table)
+
+ refItem.block = block
+
+ self.__addToBlocks (block, source, refItem)
+ self.__addToSources (source, table, {'master': 'dtsMaster',
+ 'masterlink': item.dbField, 'detaillink': 'gnue_id'})
+
+
+
+ # ---------------------------------------------------------------------------
+ # Add/Update a datasource
+ # ---------------------------------------------------------------------------
+
+ def __addToSources (self, name, table, attributes = {}):
+ """
+ This function adds or updates the given datasource in the datasource
+ dictionary.
+
+ @param name: name of the datasource
+ @param table: name of the table the datasource is bound to
+ @param attributes: dictionary with additional tags for the datasource
+ """
+
+ if not self.__sources.has_key (name):
+ self.__sources [name] = {}
+
+ self.__sources [name].update (attributes)
+ self.__sources [name] ['name'] = name
+ self.__sources [name] ['table'] = table
+ self.__sources [name] ['connection'] = self.__connection
+
+
+ # ---------------------------------------------------------------------------
+ # Add a property to the given block
+ # ---------------------------------------------------------------------------
+
+ def __addToBlocks (self, name, source, field):
+ """
+ This function appends the given field to the blocks dictionary
+
+ @param name: name of the block to be extended
+ @param source: name of the datasource the block is bound to
+ @param field: property instance of the field to be added
+ """
+
+ if not self.__blocks.has_key (name):
+ self.__blocks [name] = {'source': source, 'fields': []}
+
+ self.__blocks [name] ['fields'].append (field)
+
+
+ # ---------------------------------------------------------------------------
+ # Create an apropriate layout manager
+ # ---------------------------------------------------------------------------
+
+ def __createManager (self):
+ """
+ """
+
+ result = layout.Vertical
+
+ if len (self.__classDef.virtualPages) == 1:
+ width = []
+
+ for item in self.__classDef.properties:
+ width.append (max (len (item.label), item.widgetWidth ()))
+
+ if sum (width) + len (width) - 1 <= self.__maxWidth:
+ result = layout.Tabular
+
+ return result (self.__classDef, self.__maxWidth, self.__maxHeight)
+
+
+ # ---------------------------------------------------------------------------
+ # Get an XML representation of all blocks and their fields
+ # ---------------------------------------------------------------------------
+
+ def __blocksToXML (self):
+ """
+ This function returns a XML sequence describing the blocks and their
+ fields.
+
+ @return: sequence with XML code for the blocks
+ """
+
+ code = []
+
+ for (blockName, block) in self.__blocks.items ():
+ fCode = []
+
+ for field in block ['fields']:
+ if field.reference is None:
+ fDef = {'name': field.fieldName, 'field': field.dbField}
+ if field.typecast is not None:
+ fDef ['typecast'] = field.typecast
+ if field.propDef.gnue_length:
+ fDef ['maxLength'] = field.propDef.gnue_length
+
+ fCode.extend (self.__xml ('field', fDef))
+
+ else:
+ for refItem in field.reference.properties:
+ if refItem.style == 'dropdown' or refItem.style is None:
+ fDef = {'name' : refItem.fieldName,
+ 'field' : field.dbField,
+ 'fk_key' : 'gnue_id',
+ 'fk_source' : refItem.source,
+ 'fk_description': refItem.dbField}
+ fCode.extend (self.__xml ('field', fDef))
+
+ bDef = {'name' : blockName,
+ 'datasource': block ['source'],
+ None : fCode}
+
+ code.extend (self.__xml ('block', bDef))
+
+ return code
+
+
+ # ---------------------------------------------------------------------------
+ #
+ # ---------------------------------------------------------------------------
+
+ def __pagesToXML (self):
+ """
+ """
+
+ code = []
+ setFocus = True
+
+ for (page, properties) in self.layoutManager.visualPages:
+ pageCode = []
+
+ # add the labels first
+ for item in properties + self.__classDef.specials:
+ if item.isSpecial:
+ pData = self.layoutManager.getSpecialLocation (page, item)
+
+ item.labelPos = pData ['labelPos']
+
+ if item.labelPos is not None:
+ pageCode.extend (self.__xml ('label', \
+ {'c:width' : len (item.label) + 1,
+ 'c:height': 1,
+ 'c:x' : item.labelPos [0],
+ 'c:y' : item.labelPos [1],
+ 'text' : "%s:" % item.label}))
+
+ # add the entries
+ for item in properties + self.__classDef.specials:
+ if item.isSpecial:
+ pData = self.layoutManager.getSpecialLocation (page, item)
+ item.left = pData ['left']
+ item.row = pData ['row']
+
+ if item.reference is None:
+ pageCode.extend (self.__xml ('entry',
+ self.__entryAttributes (item, setFocus)))
+
+ else:
+ for refItem in item.reference.properties:
+ pageCode.extend (self.__xml ('entry',
+ self.__entryAttributes (refItem, setFocus)))
+
+ if not item.reference.isLookup:
+ first = item.reference.properties [0]
+ button = {'c:height': 1,
+ 'c:width' : 3,
+ 'c:x': first.left + first.width,
+ 'c:y': item.row,
+ 'label': '...',
+ None: self.__getSearchTriggerCode (first)}
+ pageCode.extend (self.__xml ('button', button))
+
+ setFocus = False
+
+ code.extend (self.__xml ('page', {'name': page, None: pageCode}))
+
+ return code
+
+
+ # ---------------------------------------------------------------------------
+ # Create a dictionary describing an entry
+ # ---------------------------------------------------------------------------
+
+ def __entryAttributes (self, item, setFocusOrder):
+ """
+ This function creates a dictionary with attributes describing the given
+ item.
+
+ @param item: property instance with the item to get a dictionary for
+ @param setFocusOrder: if True the result will get a key 'focusOrder'
+ @return: dictionary with all needed keys for creating a form-entry
+ """
+
+ result = {'c:width' : item.width,
+ 'c:height': item.height,
+ 'c:x' : item.left,
+ 'c:y' : item.row,
+ 'field' : item.fieldName,
+ 'block' : item.block}
+
+ if item.displaymask is not None:
+ result ['displaymask'] = item.displaymask
+
+ if item.inputmask is not None:
+ result ['inputmask'] = item.inputmask
+
+ if item.style is not None:
+ result ['style'] = item.style
+
+ if setFocusOrder:
+ result ['focusorder'] = 1
+
+ if hasattr (item, 'rows') and item.rows:
+ result ['rows'] = item.rows
+
+ return result
+
+
+ # ---------------------------------------------------------------------------
+ # create a trigger code for calling a search dialog
+ # ---------------------------------------------------------------------------
+
+ def __getSearchTriggerCode (self, item):
+ """
+ This function generates a button trigger for calling a search-dialog.
+ @param item: the search item
+ @return: XML code sequence for the trigger
+ """
+
+ return self.__xml ('trigger', {'type': 'ON-ACTION',
+ None: ["params = {'result': None, 'OK': False}",
+ 'runForm ("appserver://appserver/search/%s", params)' % \
+ item.parent.classname,
+ "if params.get ('OK'):",
+ " %s.%s.set (params ['result'])" % (item.block, item.fieldName)]})
+
+
+
+ # ---------------------------------------------------------------------------
+ # Create a porition of XML code
+ # ---------------------------------------------------------------------------
+
+ def __xml (self, tag, attrs, indent = "", keep = False):
+ """
+ This function create a sequence of XML code. If the attribute dictionary
+ has a None-key, this sequence will be treated as contents of the tag. Such
+ contents will be indented by another level.
+
+ @param tag: name of the XML tag
+ @param attrs: dictionary with attributes of the tag
+ @param indent: indentation for each line
+ @param keep: if True the tag is not closed, although attrs has no contents.
+ """
+
+ result = []
+ parts = []
+ gap = " "
+
+ if attrs.has_key (None):
+ contents = []
+ for element in attrs [None]:
+ contents.extend (element.splitlines ())
+ del attrs [None]
+
+ else:
+ contents = None
+
+ keys = attrs.keys ()
+ keys.sort ()
+ if 'name' in keys:
+ keys.remove ('name')
+ keys.insert (0, 'name')
+
+ close = (contents is None and not keep) and "/" or ""
+
+ xmlString = "%s<%s" % (indent, tag)
+ nextIndent = len (xmlString)
+
+ for key in keys:
+ add = '%s="%s"' % (key, attrs [key])
+ if len (xmlString) + len (add) > 76:
+ result.append (xmlString)
+ xmlString = " " * nextIndent
+
+ xmlString = "%s %s" % (xmlString, add)
+
+ xmlString = "%s%s>" % (xmlString, close)
+ result.append (xmlString)
+
+ if contents is not None:
+ iLen = len (indent) + len (gap)
+ cString = string.join (["%s%s" % (" " * iLen, i) for i in contents],
"\n")
+
+ result.append (cString)
+ if not keep:
+ result.append ("%s</%s>" % (indent, tag))
+
+ return result
Property changes on: trunk/gnue-appserver/src/generator/form.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: trunk/gnue-appserver/src/generator/layout.py
===================================================================
--- trunk/gnue-appserver/src/generator/layout.py 2004-10-30 22:01:35 UTC
(rev 6589)
+++ trunk/gnue-appserver/src/generator/layout.py 2004-11-01 08:43:14 UTC
(rev 6590)
@@ -0,0 +1,487 @@
+# GNU Enterprise Application Server - Generators - Layout manager
+#
+# Copyright 2001-2004 Free Software Foundation
+#
+# This file is part of GNU Enterprise
+#
+# GNU Enterprise is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2, or (at your option) any later version.
+#
+# GNU Enterprise is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+
+import math
+
+# =============================================================================
+# This is the base class for layout managers
+# =============================================================================
+
+class Manager:
+
+ _SPECIALS = {'gnue_createdate': {'Label': u_("Created"),
+ 'Buddy': 'gnue_createuser'},
+ 'gnue_modifydate': {'Label': u_("Last modified"),
+ 'Buddy': 'gnue_modifyuser'}}
+
+ # ---------------------------------------------------------------------------
+ # Constructor
+ # ---------------------------------------------------------------------------
+
+ def __init__ (self, classdef, maxWidth, maxHeight):
+ """
+ @param classdef: class definition to create a layout for
+ @param maxWidth: maximum width for a form
+ @param maxHeight: maximum height for a form
+ """
+
+ self._maxWidth = maxWidth
+ self._maxHeight = maxHeight
+ self._classdef = classdef
+ self._specials = self._prepareSpecials ()
+ self._specialLoc = {}
+
+ self.arrangeItems ()
+
+
+ # ---------------------------------------------------------------------------
+ # Create the visual pages and arrange all items
+ # ---------------------------------------------------------------------------
+
+ def arrangeItems (self):
+ """
+ This function creates the visual pages and arranges all properties on them.
+ As a side effect after this function the properties 'maxPageHeight' and
+ 'maxPageWidth' are set.
+ """
+
+ (self.visualPages, self.maxPageHeight) = self._createVisualPages ()
+
+ if len (self._specials):
+ self._addSpecials ()
+
+ pgSpace = []
+
+ for (page, properties) in self.visualPages:
+ pgSpace.append (self._arrangePage (page, properties))
+
+ # arrange all specials
+ for item in self._specials:
+ location = self.getSpecialLocation (page, item)
+ location ['labelPos'] = (1, location ['row'])
+ location ['left'] = item.left
+
+ if item.buddy is not None:
+ buddyLocation = self.getSpecialLocation (page, item.buddy)
+ buddyLocation ['labelPos'] = None
+ buddyLocation ['left'] = item.buddy.left #maxLabel+1+item.width
+
+ # make sure we have a bit empty room at the right side, but not too much
+ self.maxPageWidth = min (max (pgSpace) + 2, self._maxWidth)
+
+
+ # ---------------------------------------------------------------------------
+ # Horizontally arrange all widgets of a single property
+ # ---------------------------------------------------------------------------
+
+ def arrangeWidgets (self, item, left, maxSpace = None):
+ """
+ This function arranges all widgets of a property by lining them up starting
+ at the given position. If an item is a reference all reference items are
+ positioned as well, where the reference-property get's an overall-width
+ set.
+
+ After this function is done, the 'left'- and 'width'-members of an item
+ (and all it's references/buddies) are set.
+
+ @param item: the property to arrange
+ @param left: the x position of the item
+ @param maxSpace: the maximum space left for the widget
+ """
+
+ item.left = left
+ # make sure a dropdown-style item has at least a width of 7 characters
+ width = max (item.fieldLength, item.style == 'dropdown' and 7 or None)
+
+ if item.reference is None:
+ # stretchabel items try to expand as most as possible
+ if item.stretchable:
+ width = maxSpace - 2
+
+ else:
+ # do not exceed the available space
+ if maxSpace is not None:
+ width = min (maxSpace, width)
+
+ item.width = width
+
+ # if we have a buddy, make sure it get's arranged too
+ if hasattr (item, 'buddy') and item.buddy:
+ self.arrangeWidgets (item.buddy, left, maxSpace)
+
+
+ else:
+ item.width = 0
+
+ for refItem in item.reference.properties:
+ # for search-rerefences make sure to have a gap for the search-button
+ # after the first reference field
+ if not item.reference.isLookup and \
+ refItem != item.reference.properties [0]:
+ left += 3
+ item.width += 3
+
+ self.arrangeWidgets (refItem, left, maxSpace)
+ left += (refItem.width + 1)
+ width = refItem.width
+
+ item.width += width
+
+ return left + width
+
+
+ # ---------------------------------------------------------------------------
+ # Get the location dictionary for a special property on a given page
+ # ---------------------------------------------------------------------------
+
+ def getSpecialLocation (self, page, item):
+ """
+ This function returns the location-dictionary for a special property on a
+ given page. Such a dictionary has a 'labelPos'-, a 'left'- and a 'row'-key.
+
+ @param page: the visual page to get the location record for
+ @param item: the item to get the location record for
+ @return: dictionary with location information for the special property
+ """
+
+ return self._specialLoc [page][item.fullName]
+
+
+ # ---------------------------------------------------------------------------
+ # Prepare the special properties
+ # ---------------------------------------------------------------------------
+
+ def _prepareSpecials (self):
+ """
+ This function creates a sequence of special properties. Bound properties
+ are removed from the sequence, so it only contains those properties having
+ a label.
+
+ @return: sequence with special property instances
+ """
+
+ result = []
+ spec = {}
+
+ # First we build a dictionary of all special properties
+ for item in self._classdef.specials:
+ spec [item.dbField] = item
+ item.buddy = None
+ item.height = 1
+
+ # now update property information based on _SPECIALS
+ for (name, item) in self._SPECIALS.items ():
+ entry = spec.get (name)
+ if entry is not None:
+ entry.label = item ['Label']
+
+ # if the property has buddy (a property without it's own label) connect
+ # it and remove it from the dictionary
+ if spec.has_key (item ['Buddy']):
+ entry.buddy = spec [item ['Buddy']]
+ del spec [item ['Buddy']]
+
+ # at the end we create a sequence of special properties, keeping the same
+ # order as before
+ for item in self._classdef.specials:
+ if spec.has_key (item.dbField):
+ result.append (item)
+
+ return result
+
+
+ # ---------------------------------------------------------------------------
+ # Add special properties to a visual page
+ # ---------------------------------------------------------------------------
+
+ def _addSpecials (self):
+ """
+ This function adds all special properties at the bottom of every visual
+ page by creating a location record per property/page. Addidionally the
+ maximum page height will be incremented by the number of lines needed to
+ fit all special properties.
+ """
+
+ self.maxPageHeight += 1
+
+ for (page, props) in self.visualPages:
+ row = self.maxPageHeight
+
+ for item in self._specials:
+ if not self._specialLoc.has_key (page):
+ self._specialLoc [page] = {}
+
+ self._specialLoc [page] [item.fullName] = {'labelPos': None,
+ 'row' : row,
+ 'left' : 0}
+ if item.buddy is not None:
+ self._specialLoc [page] [item.buddy.fullName] = {'labelPos': None,
+ 'row' : row,
+ 'left' : 0}
+ row += 1
+
+ self.maxPageHeight = row
+
+
+
+# =============================================================================
+# This class implements a layout manager which arranges items vertically
+# =============================================================================
+
+class Vertical (Manager):
+
+ _START_ROW = 1
+ _MIN_HEIGHT = 2
+
+
+ # ---------------------------------------------------------------------------
+ # Create all visual pages
+ # ---------------------------------------------------------------------------
+
+ def _createVisualPages (self):
+ """
+ This function transforms the virtual pages into visual pages. All available
+ space will be distributed to stretchable widgets. Every item gets it's
+ height and row attributes set. Additionaly the maximum height of the
+ largest page will be determined.
+
+ @return: tuple with the visual page sequence and the height of the largest
+ page. The page sequence is a sequence of tuples with the page name and
+ a list of all properties in the page.
+ """
+
+ result = []
+
+ # available space without specials and first row
+ userSpace = self.__getUserSpace ()
+ maxPageH = userSpace + 1
+
+ for (page, properties) in self._classdef.virtualPages:
+ work = properties [:]
+ name = page
+ pnum = 1
+
+ while len (work):
+ cPage = self.__nextPageSet (name, work, userSpace)
+ pnum += 1
+ name = "%s-%d" % (page, pnum)
+
+ work = work [len (cPage [1]):]
+ result.append (cPage)
+
+ return (result, maxPageH)
+
+
+ # ---------------------------------------------------------------------------
+ # Arrange all properties on a single page
+ # ---------------------------------------------------------------------------
+
+ def _arrangePage (self, page, properties):
+ """
+ This function arranges all properties on the given page. All labels are
+ lined up at the left margin and all entries are set into a second column.
+
+ @param page: the name of the visual page
+ @param properties: a sequence of properties to arrange in the page
+
+ @return: outermost position on the right side (max. page width)
+ """
+
+ # first get the widest label (including the colon at the end)
+ maxLabel = max ([len (p.label) + 1 for p in properties + self._specials])
+ maxSpace = self._maxWidth - maxLabel - 1
+
+ # determine label position and starting positions for all widgets
+ widths = []
+ for item in properties + self._specials:
+ if not item.isSpecial:
+ item.labelPos = (1, item.row)
+
+ self.arrangeWidgets (item, maxLabel + 1, maxSpace)
+ widths.append (item.left + item.width)
+
+ # return the outermost right position on the page
+ return max (widths)
+
+
+ # ---------------------------------------------------------------------------
+ # Calculate the maximum space to be filled with widgets for all pages
+ # ---------------------------------------------------------------------------
+
+ def __getUserSpace (self):
+ """
+ This function determines the number of rows available to place widgets in.
+
+ @return: size of user space
+ """
+
+ # maximum page height minus special rows, minus starting row offset
+ maxSpace = self._maxHeight - len (self._specials) - 1 - self._START_ROW
+ result = 0
+
+ for (page, properties) in self._classdef.virtualPages:
+ need = sum ([item.minHeight or self._MIN_HEIGHT for item in properties])
+
+ # if the needed space exceeds the longest page possible, or a page
+ # contains stretchable items, use the maximum available space
+ if need >= maxSpace or True in [item.stretchable for item in properties]:
+ return maxSpace
+
+ result = max (result, need)
+
+ return result
+
+
+ # ---------------------------------------------------------------------------
+ # Get the next set of properties for a given page
+ # ---------------------------------------------------------------------------
+
+ def __nextPageSet (self, page, properties, userSpace):
+ """
+ This function creates a set of visual properties to fit into a visual page.
+ If there is space left on a page it will be distributed to the stretchable
+ controls on the page. After this function is done all selected properties
+ have their height- and row-members set.
+
+ @param page: name of the visual page to use
+ @param properties: sequence of available properties to arrange
+ @param userSpace: number of available rows to fill
+
+ @return: tuple with (pagename, propertysequence)
+ """
+
+ taken = []
+ stretch = []
+ need = 0
+
+ for item in properties:
+ item.height = item.minHeight or self._MIN_HEIGHT
+
+ if need + item.height > userSpace:
+ break
+
+ need += item.height
+ taken.append (item)
+
+ if item.stretchable:
+ stretch.append (item)
+
+ # if there was space left, distribute it to all stretchable controls
+ if userSpace - need > 0 and len (stretch):
+ available = userSpace - need
+
+ for item in stretch [:]:
+ avg = int (math.ceil (float (available) / len (stretch)))
+ if not avg:
+ break
+
+ item.height += avg
+ available -= avg
+ stretch.remove (item)
+
+ # at last we set the row members for all properties on the page
+ row = self._START_ROW
+ for item in taken:
+ item.row = row
+ row += item.height
+
+ if item.reference is not None:
+ for refItem in item.reference.properties:
+ refItem.height = item.height
+ refItem.row = item.row
+
+ return (page, taken)
+
+
+
+# =============================================================================
+# This class implements a layout manager which arranges items in a table
+# =============================================================================
+
+class Tabular (Manager):
+
+ _MIN_HEIGHT = 1
+
+ # ---------------------------------------------------------------------------
+ # Create the visual pages
+ # ---------------------------------------------------------------------------
+
+ def _createVisualPages (self):
+ """
+ This function transform the virtual page into a visual page. Visual pages
+ use all available vertical space leaving room for a title row and the
+ special properties at the bottom.
+ """
+
+ result = []
+ maxPageHeight = self._maxHeight - len (self._specials) - 2
+ maxRowHeight = 0
+
+ for (page, properties) in self._classdef.virtualPages:
+
+ for item in properties:
+ item.row = 1
+ item.height = item.minHeight or self._MIN_HEIGHT
+ item.rows = maxPageHeight
+ maxRowHeight = max (maxRowHeight, item.height)
+
+ result.append ((page, properties))
+
+ return (result, maxPageHeight + 1)
+
+
+ # ---------------------------------------------------------------------------
+ # Arrange all properties on a single page
+ # ---------------------------------------------------------------------------
+
+ def _arrangePage (self, page, properties):
+ """
+ This function arranges all properties on the given page. All properties are
+ lined up in a grid.
+
+ @param page: the name of the visual page
+ @param properties: a sequence of properties to arrange in the page
+
+ @return: outermost position on the right side (max. page width)
+ """
+
+ left = 1
+ widths = []
+ maxLabel = max ([len (s.label) + 1 for s in self._specials])
+
+ for item in properties + self._specials:
+ # special properties are located at the bottom of the page
+ if item.isSpecial:
+ maxSpace = self._maxWidth - maxLabel - 1
+ self.arrangeWidgets (item, maxLabel + 1, maxSpace)
+ widths.append (item.left + item.width)
+
+ else:
+ item.labelPos = (left, 0)
+
+ self.arrangeWidgets (item, left, self._maxWidth - left)
+ left += max (item.width, len (item.label) + 1) + 1
+
+ widths.append (left + 1)
+
+ return max (widths)
Property changes on: trunk/gnue-appserver/src/generator/layout.py
___________________________________________________________________
Name: svn:keywords
+ Id
Deleted: trunk/gnue-appserver/src/labels.py
===================================================================
--- trunk/gnue-appserver/src/labels.py 2004-10-30 22:01:35 UTC (rev 6589)
+++ trunk/gnue-appserver/src/labels.py 2004-11-01 08:43:14 UTC (rev 6590)
@@ -1,1084 +0,0 @@
-# GNU Enterprise Appserver - Dynamic Forms Support
-#
-# Copyright 2001-2004 Free Software Foundation
-#
-# This file is part of GNU Enterprise
-#
-# GNU Enterprise is free software; you can redistribute it
-# and/or modify it under the terms of the GNU General Public
-# License as published by the Free Software Foundation; either
-# version 2, or (at your option) any later version.
-#
-# GNU Enterprise is distributed in the hope that it will be
-# useful, but WITHOUT ANY WARRANTY; without even the implied
-# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-# PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public
-# License along with program; see the file COPYING. If not,
-# write to the Free Software Foundation, Inc., 59 Temple Place
-# - Suite 330, Boston, MA 02111-1307, USA.
-#
-# $Id$
-
-import string
-import math
-import mx.DateTime
-import copy
-
-from xml.sax import saxutils
-from gnue.appserver.classrep import Namespace
-from gnue.common.apps import errors
-
-
-# =============================================================================
-# Exceptions
-# =============================================================================
-
-class SystemClassError (errors.UserError):
- def __init__ (self, classname):
- msg = u_("'%s' is a system class and cannot be edited.") % classname
- errors.UserError.__init__ (self, msg)
-
-# =============================================================================
-# This class encapsulates the property of a business object class
-# =============================================================================
-
-class Property:
-
- # ---------------------------------------------------------------------------
- # Construct a new instance with some serious defaults
- # ---------------------------------------------------------------------------
-
- def __init__ (self, pObject, isCalculated = False):
- fullName = Namespace.createName (pObject.module.name, pObject.name)
- fieldName = fullName
-
- if isCalculated:
- fieldName = Namespace.createName (pObject.module.name, pObject.name [3:])
-
- self.fullName = fullName
- self.fieldName = "fld%s" % fieldName.title ().replace ('_', '')
- self.dbField = fieldName
- self.label = pObject.gnue_name
- self.type = pObject.gnue_type
- self.length = pObject.gnue_length
- self.scale = pObject.gnue_scale
- self.page = pObject.module.name.title ()
- self.pos = None
- self.search = None
- self.info = None
- self.ref = None
- self.refOrder = None
- self.refName = self.type.title ().replace ('_', '')
- self.typecast = None
- self.inputMask = None
- self.displayMask = None
- self.buddy = None
- self.triggers = {}
- self.isSpecial = False
-
- masks = ['%x', '%X', '%x %X']
-
- if self.type in ['date', 'time', 'datetime']:
- typeId = ['date','time', 'datetime'].index (self.type)
-
- self.typecast = 'date'
- self.inputMask = masks [typeId]
- self.displayMask = masks [typeId]
- self.fieldLength = len (mx.DateTime.now ().strftime (self.displayMask))
-
- elif self.type == 'number':
- self.typecast = 'number'
- self.fieldLength = (self.length or 0) + (self.scale or 0) + 1
-
- elif self.type == 'boolean':
- self.fieldLength = 1
-
- else:
- self.fieldLength = self.length or 32
-
-
- # ---------------------------------------------------------------------------
- # Update label information from a gnue-label object
- # ---------------------------------------------------------------------------
-
- def updateLabel (self, label):
- """
- This function updates the instance with all label information
- """
-
- self.label = label.label
- if label.page is not None:
- self.page = label.page
- self.pos = label.position
- self.search = label.search
- self.info = label.info
-
-
- # ---------------------------------------------------------------------------
- # Order reference items by their search- and info-order
- # ---------------------------------------------------------------------------
-
- def orderReferences (self):
- """
- If a property is a reference to another class, this function orders all
- parts of the reference given by their search- and info-order.
- """
- if self.ref is None:
- return
-
- order = []
- for refItem in self.ref.values ():
- refItem.fieldName = "%s%s" % (self.dbField, refItem.fieldName)
- if refItem.search is not None:
- order.append ((refItem.search, refItem))
- else:
- order.append ((refItem.info, refItem))
-
- order.sort ()
- self.refOrder = [item [1] for item in order]
-
-
- # ---------------------------------------------------------------------------
- # Return TRUE if a property is a lookup-reference
- # ---------------------------------------------------------------------------
-
- def isLookup (self):
- """
- This function returns TRUE if a reference-property is a lookup reference,
- which means all search-fields will get dropdowns.
- """
- if self.refOrder is None or not len (self.refOrder):
- return False
-
- first = self.refOrder [0]
- return first.search is not None and first.search != 0
-
-
- # ---------------------------------------------------------------------------
- # Get all reference fields which need to be added to a block
- # ---------------------------------------------------------------------------
-
- def getRefBlockFields (self):
- """
- This function returns an ordered sequence of all reference-fields, which
- has to be added to a detail-block.
- """
- result = []
- lookup = self.isLookup ()
-
- for item in self.refOrder:
- # for search-dialogs, we need only the field with search-order 0, since
- # all other fields will be handled by the dialog
- if (not lookup and item.search != 0) or item.info is not None:
- continue
-
- result.append (item)
-
- return result
-
-
- # ---------------------------------------------------------------------------
- # Place all widgets in a row
- # ---------------------------------------------------------------------------
-
- def placeWidgets (self, maxWidth):
- """
- This function places all visible widgets in a form row. After this function
- is finished the following properties are set:
- width - the width of the corresponding widget
- left - the left position (x) of the widget
- widgetSpace - the number of characters used for all widgets of the property
-
- If a property is a reference, 'width' and 'left' is set for all
- reference-items.
- """
- startX = 1 + self.labelWidth + 1
- self.left = startX
- maxWidth -= startX + 1
- if self.ref is None and self.buddy is None:
- if self.type == 'string' and self.length is None:
- self.width = maxWidth
- else:
- self.width = min (maxWidth, self.fieldLength)
-
- self.widgetSpace = self.width
-
- elif self.buddy is not None:
- self.width = self.fieldLength
- self.buddy.left = startX + self.width + 1
- self.buddy.width = self.buddy.left + self.buddy.fieldLength
- self.widgetSpace = self.width + self.buddy.width + 1
-
- else:
- refLength = 0
- refStart = startX
-
- for refItem in self.refOrder:
- if refItem.style == 'dropdown':
- refItem.minWidth = 7
- refItem.fieldLength = max (refItem.fieldLength, refItem.minWidth)
- else:
- refItem.minWidth = None
-
- refItem.width = refItem.fieldLength
- refItem.left = refStart
-
- refStart += refItem.width
- refLength += refItem.fieldLength
-
- self.widgetSpace = refLength
-
- # search-fields exceed the available space, so try to distribute the
- # available space
- if refLength > maxWidth:
- aliqLength = 0
- refStart = startX
- for refItem in self.refOrder:
- pWidth = int (maxWidth * refItem.fieldLength / refLength)
- if pWidth + aliqLength <= maxWidth:
- refItem.width = max (pWidth, refItem.minWidth)
- aliqLength += pWidth
- else:
- refItem.width = None
-
- self.widgetSpace = aliqLength
-
-
-
-# =============================================================================
-# This class generates GNUe Forms based on appserver's class repository
-# =============================================================================
-
-class FormGenerator:
-
- _START_ROW = 1 # starting row for widgets
- _MIN_HEIGHT = 2 # default minimum height of stretchable widgets
-
- _SPECIALS = {'gnue_createdate': {'Label': u_("Created"),
- 'Buddy': 'gnue_createuser'},
- 'gnue_modifydate': {'Label': u_("Last modified"),
- 'Buddy': 'gnue_modifyuser'}}
-
- # ---------------------------------------------------------------------------
- # Constructor
- # ---------------------------------------------------------------------------
-
- def __init__ (self, aClass, language, connection, formWidth, formHeight):
- self.aClass = aClass
- self.languages = ['C']
- self.connection = connection
- self.fullName = Namespace.createName (aClass.module.name, aClass.name)
- self.formTitle = "%s %s" % (aClass.module.name.title (),
- aClass.name.title ())
-
- self.maxWidth = formWidth
- self.maxHeight = formHeight
-
- self.properties = {}
- self.sources = {}
- self.pages = {}
- self.visPages = {}
- self.blocks = {}
-
- # if language is a full locale like 'de_AT' add 'de' and 'de_AT' as well
- if '_' in language:
- self.languages.append (language.split ('_') [0])
- self.languages.append (language)
-
- (self.properties, self.specials) = self.__getPropertyDict (self.fullName)
-
- if not len (self.properties.keys ()):
- raise SystemClassError, self.fullName
-
- self.__loadLabels (self.fullName, self.properties)
- self.__fillupReferences ()
- self.__removeHiddenProperties ()
- self.__updateEntryStyle ()
- self.__updateSources ()
- self.__updateSpecials ()
- self.pages = self.__buildVirtualPages ()
- self.visPages = self.__buildVisualPages ()
- self.__arangePages ()
-
-
-
- # ---------------------------------------------------------------------------
- # Get all properties and labels for a given class
- # ---------------------------------------------------------------------------
-
- def __getPropertyDict (self, classname):
- """
- This function retrieves all properties of the requested class,
- including calculated fields.
-
- @param classname: fully qualified name of the requested class
-
- @return: tuple of two dictionaries. The first dictionary holds all
- properties and calculated fields and the second dictionary holds all
- special properties. In both dictionaries the keys are fieldnames and
- the values are Property instances
- """
- result = {}
- specials = {}
-
- (module, klass) = Namespace.splitName (classname)
-
- cond = ['and', ['eq', ['field', 'gnue_class.gnue_name'], ['const', klass]],
- ['eq', ['field', 'gnue_class.gnue_module.gnue_name'],
- ['const', module]]]
-
- pList = ['gnue_name', 'gnue_length', 'gnue_type', 'gnue_scale']
- for prop in find ('gnue_property', cond, [], pList):
- if prop.gnue_module.gnue_name == 'gnue' or prop.gnue_type == 'id':
- if prop.gnue_name in ['createdate', 'modifydate', 'createuser',
- 'modifyuser']:
- record = Property (prop)
- record.isSpecial = True
- specials [record.fullName] = record
-
- continue
-
- # Do not include the filter
- filter = prop.gnue_class.gnue_filter
- if filter is not None:
- if prop.gnue_name == filter.gnue_name and \
- prop.gnue_module.gnue_name == filter.gnue_module.gnue_name:
- continue
-
- record = Property (prop)
- result [record.fullName] = record
-
- # Add all calculated properties
- cond = ['and', ['eq', ['field', 'gnue_class.gnue_name'], ['const', klass]],
- ['eq', ['field', 'gnue_class.gnue_module.gnue_name'],
- ['const', module]],
- ['like', ['field', 'gnue_name'], ['const', 'get%']],
- ['notnull', ['field', 'gnue_type']]]
-
- for proc in find ('gnue_procedure', cond, [], pList):
- # a calculated field must not have parameters
- if len (find ('gnue_parameter', ['eq', ['field', 'gnue_procedure'],
- ['const', proc.gnue_id]], [], [])):
- continue
-
- record = Property (proc, True)
- result [record.fullName] = record
-
- return (result, specials)
-
-
- # ---------------------------------------------------------------------------
- # Update a property dictionary with labels information
- # ---------------------------------------------------------------------------
-
- def __loadLabels (self, classname, pDict, refsOnly = False):
- """
- This function updates the given property dictionary with all available
- labels of a given class.
- @param classname: fully qualified name of the class
- @param pDict: dictionary with property instances
- @param refsOnly: if TRUE, all non-reference properties will be removed from
- the property dictionary pDict after loading the labels.
- """
- (module, klass) = Namespace.splitName (classname)
- pList = ['gnue_label', 'gnue_position', 'gnue_search', 'gnue_info',
- 'gnue_page']
-
- for locale in self.languages:
- cond = ['and', ['eq', ['field', 'gnue_language'], ['const', locale]],
- ['eq', ['field', 'gnue_property.gnue_class.gnue_name'],
- ['const', klass]],
- ['eq', ['field', 'gnue_property.gnue_class.gnue_module.gnue_name'],
- ['const', module]]]
-
- if refsOnly:
- cond.append (['or', ['notnull', ['field', 'gnue_search']],
- ['notnull', ['field', 'gnue_info']]])
-
- for label in find ('gnue_label', cond, [], pList):
-
- full = Namespace.createName (label.gnue_property.module.name,
- label.gnue_property.name)
- if full == 'gnue_id' and len (label.label):
- self.formTitle = label.label
- continue
-
- pDict [full].updateLabel (label)
-
- # Add labels for calculated properties
- cond = ['and', ['eq', ['field', 'gnue_language'], ['const', locale]],
- ['eq', ['field', 'gnue_procedure.gnue_class.gnue_name'],
- ['const', klass]],
- ['eq', ['field',
'gnue_procedure.gnue_class.gnue_module.gnue_name'],
- ['const', module]]]
-
- if refsOnly:
- cond.append (['or', ['notnull', ['field', 'gnue_search']],
- ['notnull', ['field', 'gnue_info']]])
-
- for label in find ('gnue_label', cond, [], pList):
- full = Namespace.createName (label.gnue_procedure.module.name,
- label.gnue_procedure.name)
-
- pDict [full].updateLabel (label)
-
- if refsOnly:
- for (key, item) in pDict.items ():
- if item.search is None and item.info is None:
- del pDict [key]
-
-
- # ---------------------------------------------------------------------------
- # Make sure all references have a valid set of reference items
- # ---------------------------------------------------------------------------
-
- def __fillupReferences (self):
- """
- This function populates all reference properties. Afterwards the member
- 'ref' is set to a property-dictionary with all reference-parts. The member
- 'refOrder' is an ordered sequence with all reference-parts.
- """
- for item in self.properties.values ():
- if '_' in item.type:
- (result, dummy) = self.__getPropertyDict (item.type)
- self.__loadLabels (item.type, result, True)
-
- if len (result.keys ()):
- item.ref = result
- item.orderReferences ()
-
- if item.isLookup ():
- drops = []
- hasInfo = False
- for refItem in item.refOrder:
- if refItem.search is not None and refItem.search:
- drops.append (refItem)
- elif refItem.info is not None:
- hasInfo = True
-
- for dropdown in drops:
- dropdown.needTrigger = hasInfo
-
-
- # ---------------------------------------------------------------------------
- # Hide away all properties with position 0
- # ---------------------------------------------------------------------------
-
- def __removeHiddenProperties (self):
- """
- This function removes all properties with an explicit zero-position. We
- treat them as 'hidden'.
- """
-
- for (key, item) in self.properties.items ():
- if item.pos == 0:
- del self.properties [key]
-
-
- # ---------------------------------------------------------------------------
- # Update the property-dictionary with entry-style information
- # ---------------------------------------------------------------------------
-
- def __updateEntryStyle (self):
- """
- This function iterates over all properties of a class and determines their
- entry-style. A style 'None' means default. All items of a reference
- properties are set as well. Lookup-references are treated as dropdowns, if
- they are flagged as searchable, otherwise they're labels. For
- search-dialogs the first field get's an entry all others are labels.
- After this function is finished all properties have a valid member 'style'
- """
-
- for prop in self.properties.values ():
- prop.style = None
-
- if prop.ref is None:
- if prop.type == 'boolean':
- prop.style = 'checkbox'
-
- else:
- if prop.isLookup ():
- for refItem in prop.refOrder:
- if refItem.search is not None:
- refItem.style = 'dropdown'
- else:
- refItem.style = 'label'
- else:
- prop.refOrder [0].style = None
-
- for refItem in prop.refOrder [1:]:
- refItem.style = 'label'
-
- # all special items (like stamps) will become labels
- for item in self.specials.values ():
- item.style = 'label'
-
-
- # ---------------------------------------------------------------------------
- # Update the sources- and blocks-dictionary and their field sequences
- # ---------------------------------------------------------------------------
-
- def __updateSources (self):
- """
- This function updates the datasource- and blocks-dictionaries.
- """
-
- attrs = {}
- orderBy = self.__getSortColumn ()
- if orderBy is not None:
- attrs ['order_by'] = orderBy
-
- self.__addToSources ('dtsMaster', self.fullName, attrs)
-
- for prop in self.properties.values () + self.specials.values ():
- if prop.ref is None:
- dtsName = "dtsMaster"
- blkName = "blkMaster"
- prop.block = blkName
-
- self.__addToBlocks (blkName, dtsName, prop)
-
- else:
- table = prop.type
- if prop.isLookup ():
- self.__addToBlocks ('blkMaster', 'dtsMaster', prop)
- prop.block = 'blkMaster'
-
-
- for refItem in prop.refOrder:
- if refItem.style == 'dropdown':
- dtsName = "dts%s" % prop.refName
- refItem.block = 'blkMaster'
- self.__addToSources (dtsName, prop.type, {'prequery': 'Y'})
-
- if refItem.needTrigger:
- trigger = self.__addToTriggers ('POST-CHANGE', refItem)
- co = [saxutils.escape ("fId = %s.%s.get ()" \
- % (refItem.block, refItem.fieldName))]
- co.append (saxutils.escape ("%s.simpleQuery ({'gnue_id': fId})" %
- "dtsLookup%s%s" % (prop.dbField, prop.refName)))
- attrs = {'type': 'POST-CHANGE',
- 'contents': co}
-
- trigger.extend (self._getXMLTag ('trigger', attrs))
-
- else:
- dtsName = "dtsLookup%s%s" % (prop.dbField, prop.refName)
- blkName = "blkLookup%s%s" % (prop.dbField, prop.refName)
- refItem.block = blkName
-
- self.__addToBlocks (blkName, dtsName, refItem)
- self.__addToSources (dtsName, prop.type, {'master': 'dtsMaster',
- 'masterlink': prop.dbField, 'detaillink': 'gnue_id'})
-
-
-
- # ---------------------------------------------------------------------------
- # Update the list of special properties
- # ---------------------------------------------------------------------------
-
- def __updateSpecials (self):
- """
- This function iterates over the available special properties and join them
- according to the buddy-parts given in the _SPECIALS dictionary.
- """
-
- for (name, item) in self.specials.items ():
- if self._SPECIALS.has_key (name):
- spec = self._SPECIALS [name]
- buddy = spec ['Buddy']
-
- item.label = spec ['Label']
- if self.specials.has_key (buddy):
- item.buddy = self.specials [buddy]
- del self.specials [buddy]
-
-
- # ---------------------------------------------------------------------------
- # Get the name of the first search property
- # ---------------------------------------------------------------------------
-
- def __getSortColumn (self):
- """
- This function get's the name of the search property with the lowest search
- index or None if no search property is available.
- """
-
- search = []
- for item in self.properties.values ():
- if item.search is not None:
- search.append ((item.search, item.fullName))
-
- search.sort ()
-
- return len (search) and search [0] [1] or None
-
- # ---------------------------------------------------------------------------
- # Add a property to the given block dictionary
- # ---------------------------------------------------------------------------
-
- def __addToBlocks (self, blockName, datasource, item):
- """
- This function appends the given property (item) to the requested block's
- fieldlist.
- @param blockName: the name of the block to be extended
- @param datasource: the name of the datasource the block is bound to
- @param item: the property to be added to the block
- """
- if not self.blocks.has_key (blockName):
- self.blocks [blockName] = {'source': datasource,
- 'fields': []}
- self.blocks [blockName]['fields'].append (item)
-
-
- # ---------------------------------------------------------------------------
- # Add a datasource to the datasource dictionary
- # ---------------------------------------------------------------------------
-
- def __addToSources (self, sourceName, tableName, attrs = {}):
- """
- Add a datasource to the datasource-dictionary or update it.
- @param sourceName: name of the datasource
- @param tableName: name of the table the datasource is bound to
- @param attrs: dictionary with additional attributes for the datasource
- """
- if not self.sources.has_key (sourceName):
- self.sources [sourceName] = {}
-
- self.sources [sourceName].update (attrs)
- self.sources [sourceName]['name'] = sourceName
- self.sources [sourceName]['table'] = tableName
- self.sources [sourceName]['connection'] = self.connection
-
-
- # ---------------------------------------------------------------------------
- # Add a trigger to a propertie's trigger dictionary
- # ---------------------------------------------------------------------------
-
- def __addToTriggers (self, name, item):
- """
- This function makes sure a properties trigger dictionary has a given key
- @param name: name of the trigger
- @param item: the property to add the trigger to
- @return: code-sequence of the requested trigger
- """
- if not item.triggers.has_key (name):
- item.triggers [name] = []
- return item.triggers [name]
-
-
- # ---------------------------------------------------------------------------
- # Build up the virtual pages
- # ---------------------------------------------------------------------------
-
- def __buildVirtualPages (self):
- """
- This function returns a dictionary of virtual pages. Such a page contains
- all fields in the proper order as requested by gnue_lables. Additionally
- all items get a property 'minHeight' set, which determines the minimum
- height needed by a field. If minHeight is None, a field can be stretched
- vertically to consume the available space left.
-
- @return: dictionary with all virtual pages, where the page-names act as
- keys and the values are sequences with the properties per page. The
- property sequences are already ordered.
- """
- result = {}
-
- # add fields to their virtual pages
- for item in self.properties.values ():
- item.addHeight = 0
- # specify a minimum height required for a field
- if item.type == 'string' and item.length is None:
- item.minHeight = None
- else:
- item.minHeight = 1
-
- if not result.has_key (item.page):
- result [item.page] = []
-
- result [item.page].append (item)
-
- # now order all fields per virtual page
- for page in result.keys ():
- pOrder = []
- nOrder = []
-
- for item in result [page]:
- if item.pos is None:
- nOrder.append ((item.label, item))
- else:
- pOrder.append ((item.pos, item))
-
- nOrder.sort ()
- pOrder.sort ()
-
- result [page] = [p [1] for p in pOrder] + [n [1] for n in nOrder]
-
- # Add the special fields at the bottom of every page
- for item in self.specials.values ():
- item.addHeight = 0
- item.minHeight = 1
-
- for plist in result.values ():
- plist.extend ([copy.deepcopy (p) for p in self.specials.values ()])
-
- return result
-
-
- # ---------------------------------------------------------------------------
- # Create the visual pages
- # ---------------------------------------------------------------------------
-
- def __buildVisualPages (self):
- """
- This function transforms the virtual pages into visible pages. Available
- space is distributed to all stretchable widgets. After this function is
- finished all properties have their row- and height-member set. This
- function also set's the maximum page height for the form.
-
- @return: dictionary with the visible pages, where page-names act as keys
- and the values are the ordered properties per page.
- """
- result = {}
- self.maxPageHeight = 0
-
- for (pageName, virtPage) in self.pages.items ():
- needed = self._START_ROW
- stretchable = []
- for item in virtPage:
- if item.minHeight is None:
- needed += self._MIN_HEIGHT
- stretchable.append (item)
- else:
- needed += item.minHeight
-
- if needed <= self.maxHeight:
- nPages = 1
- else:
- nPages = int (math.ceil (float (needed) / self.maxHeight))
- availLines = nPages * self.maxHeight - needed
-
- if len (stretchable) and availLines / len (stretchable):
- avgAdd = availLines / len (stretchable)
-
- for sIndex in range (len (stretchable)):
- sItem = stretchable [sIndex]
- sItem.addHeight = avgAdd
-
- if sIndex == len (stretchable) - 1:
- avgAdd = availLines
- availLines = 0
- else:
- availLines -= avgAdd
- avgAdd = availLines / len (stretchable) - sIndex - 1
-
-
- # create the visual page(s)
- row = self._START_ROW
- pageNum = 1
- cPage = []
-
- firstSpecial = True
- result [pageName] = cPage
-
- for item in virtPage:
- # Insert a blank line before the first special property
- if item.isSpecial and firstSpecial:
- row += 1
- firstSpecial = False
-
- item.height = item.minHeight or self._MIN_HEIGHT + item.addHeight
-
- if row + item.height - 1 > self.maxHeight:
- pageNum += 1
- cPage = []
- result ["%s-%d" % (pageName, pageNum)] = cPage
- row = self._START_ROW
-
- item.row = row
- if item.buddy is not None:
- item.buddy.row = item.row
- item.buddy.height = item.height
-
- cPage.append (item)
-
- row += item.height
- self.maxPageHeight = max (self.maxPageHeight, row)
-
- self.maxPageHeight += 1
- return result
-
-
-
- # ---------------------------------------------------------------------------
- # Horizontally arrange all widgets on their visual pages
- # ---------------------------------------------------------------------------
-
- def __arangePages (self):
- """
- This function horizontally arranges all widgets on their visual page. After
- this function is finished all properties have their left-, labelWidth- and
- widgetSpace-members set. This function also sets the maximum page width for
- the form.
- """
- self.maxPageWidth = 0
-
- for page in self.visPages.values ():
- maxLabel = 0
- for item in page:
- maxLabel = max (maxLabel, len (item.label))
-
- for item in page:
- item.labelWidth = maxLabel + 1
- item.placeWidgets (self.maxWidth)
-
- size = item.left + item.widgetSpace + 1
- self.maxPageWidth = max (self.maxPageWidth, size)
-
-
- # ---------------------------------------------------------------------------
- # Generate the form
- # ---------------------------------------------------------------------------
-
- def generateForm (self):
- """
- This function creates the XML-code for the form.
- @return: string containing the XML-code of the form
- """
- self.code = [u'<?xml version="1.0" encoding="utf-8"?>']
- self.code.extend (self._getXMLTag ('form',
- {'title': self.formTitle}, "", True))
-
- cont = []
- cont.extend (self._getXMLTag ('author',
- {'contents': [u_("GNU Enterprise Application Server")]}, "
"))
- cont.extend (self._getXMLTag ('version', {'contents': ['1.0']}, " "))
- cont.extend (self._getXMLTag ('description',
- {'contents': [u_('Generated form for class "%s"') % self.fullName]},
- " "))
-
- self.code.extend (self._getXMLTag ('options', {'contents': cont}, " "))
-
-
- # datasources and blocks
- indent = " "
- for source in self.sources.values ():
- self.code.extend (self._getXMLTag ('datasource', source, indent))
-
- self.__addBlocks ()
-
- # layout
- attrs = {'xmlns:c' : 'GNUe:Layout:Char',
- 'c:width' : self.maxPageWidth,
- 'c:height': self.maxPageHeight}
-
- if len (self.visPages.keys ()) > 1:
- attrs ['tabbed'] = 'top'
-
- self.code.extend (self._getXMLTag ('layout', attrs, indent, True))
-
- focusOrder = 1
- pageList = self.visPages.keys ()
- pageList.sort ()
- for page in pageList:
- ind = indent + " "
- attrs = {'name': page}
- self.code.extend (self._getXMLTag ('page', attrs, ind, True))
- find = ind + " "
-
- for item in self.visPages [page]:
- # labels
- attrs = {'c:x' : 1,
- 'c:y' : item.row,
- 'c:width' : item.labelWidth,
- 'c:height': 1,
- 'text' : "%s:" % item.label}
- self.code.extend (self._getXMLTag ('label', attrs, find))
-
- for item in self.visPages [page]:
- if item.ref is None:
- self.__addField (item, focusOrder, find)
- focusOrder += 1
-
- if item.buddy is not None:
- self.__addField (item.buddy, focusOrder, find)
- focusOrder += 1
-
- else:
- for refItem in item.refOrder:
- if refItem.width is None:
- continue
-
- attrs = {'c:x' : refItem.left,
- 'c:y' : item.row,
- 'c:width' : refItem.width,
- 'c:height': item.height,
- 'block' : refItem.block,
- 'field' : refItem.fieldName}
- if focusOrder == 1:
- attrs ['focusorder'] = 1
-
- focusOrder += 1
-
- if refItem.style is not None:
- attrs ['style'] = refItem.style
-
- self.code.extend (self._getXMLTag ('entry', attrs, find))
-
- self.code.append ('%s</page>' % ind)
-
- self.code.append ('%s</layout>' % indent)
- self.code.append ('</form>')
-
- return string.join (self.code, "\n")
-
-
- # ---------------------------------------------------------------------------
- # add an entry to the page
- # ---------------------------------------------------------------------------
-
- def __addField (self, item, focusOrder, find):
- attrs = {'c:x' : item.left,
- 'c:y' : item.row,
- 'c:width' : item.width,
- 'c:height': item.height,
- 'block' : item.block,
- 'field' : item.fieldName}
-
- if focusOrder == 1:
- attrs ['focusorder'] = 1
-
- if item.displayMask is not None:
- attrs ['displaymask'] = item.displayMask
-
- if item.inputMask is not None:
- attrs ['inputmask'] = item.inputMask
-
- if item.style is not None:
- attrs ['style'] = item.style
-
- self.code.extend (self._getXMLTag ('entry', attrs, find))
-
-
- # ---------------------------------------------------------------------------
- # Add blocks to the form code
- # ---------------------------------------------------------------------------
-
- def __addBlocks (self):
- """
- This function adds the logic-section to the forms code sequence
- """
- indLogic = " "
- indBlock = indLogic + " "
-
- self.code.append ("%s<logic>" % indLogic)
-
- for (blockName, block) in self.blocks.items ():
- attrs = {'name' : blockName,
- 'datasource': block ['source']}
- self.code.extend (self._getXMLTag ('block', attrs, indBlock, True))
-
- self.__addFields (block, indBlock)
-
- self.code.append ("%s</block>" % indBlock)
-
- self.code.append ("%s</logic>" % indLogic)
-
-
- # ---------------------------------------------------------------------------
- # Add all fields of a block to the code sequence
- # ---------------------------------------------------------------------------
-
- def __addFields (self, block, indent):
- """
- This function adds all fields of a block to the code sequence
- """
- indent += " "
- for field in block ['fields']:
- if field.dbField == 'gnue_id':
- continue
-
- if field.ref is not None:
- for refItem in field.getRefBlockFields ():
- attr = {'name' : refItem.fieldName,
- 'field' : field.dbField,
- 'fk_key': 'gnue_id',
- 'fk_description': refItem.dbField,
- 'fk_source': 'dts%s' % field.refName}
-
- if len (refItem.triggers.keys ()):
- attr ['contents'] = []
- for trigger in refItem.triggers.values ():
- attr ['contents'].extend (trigger)
-
- self.code.extend (self._getXMLTag ('field', attr, indent))
- else:
- attr = {'name' : field.fieldName,
- 'field': field.dbField}
- if field.typecast is not None:
- attr ['typecast'] = field.typecast
- if field.typecast != 'number':
- if field.length:
- attr ['maxLength'] = field.length
-
- self.code.extend (self._getXMLTag ('field', attr, indent))
-
-
- # ---------------------------------------------------------------------------
- # Create an XML sequence
- # ---------------------------------------------------------------------------
-
- def _getXMLTag (self, tag, attrs, indent = "", keep = False):
- """
- This function creates a code-sequence for the given XML tag.
- @param tag: name of the XML tag
- @param attrs: dictionary with attributes
- @param indent: indentation for each line
- @param keep: if TRUE the tag is not closed, although attrs has no contents
- key.
- """
- result = []
- parts = []
- gap = " "
-
- if attrs.has_key ('contents'):
- contents = []
- for element in attrs ['contents']:
- contents.extend (element.splitlines ())
- del attrs ['contents']
- else:
- contents = None
-
- keys = attrs.keys ()
- keys.sort ()
- if 'name' in keys:
- keys.remove ('name')
- keys.insert (0, 'name')
-
- close = (contents is None and not keep) and "/" or ""
-
- xmlString = "%s<%s" % (indent, tag)
- nextIndent = len (xmlString)
-
- for key in keys:
- add = '%s="%s"' % (key, attrs [key])
- if len (xmlString) + len (add) > 76:
- result.append (xmlString)
- xmlString = " " * nextIndent
-
- xmlString = "%s %s" % (xmlString, add)
-
- xmlString = "%s%s>" % (xmlString, close)
- result.append (xmlString)
-
- if contents is not None:
- iLen = len (indent) + len (gap)
- cString = string.join (["%s%s" % (" " * iLen, i) for i in contents],
"\n")
-
- result.append (cString)
- result.append ("%s</%s>" % (indent, tag))
-
- return result
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- r6590 - in trunk/gnue-appserver: share src src/generator,
johannes <=