commit-gnue
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]