commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

r6555 - trunk/gnue-reports/src/client


From: johannes
Subject: r6555 - trunk/gnue-reports/src/client
Date: Sun, 24 Oct 2004 04:14:08 -0500 (CDT)

Author: johannes
Date: 2004-10-24 04:14:07 -0500 (Sun, 24 Oct 2004)
New Revision: 6555

Modified:
   trunk/gnue-reports/src/client/GRRunUI.py
Log:
Added first version of a RunUI implementation


Modified: trunk/gnue-reports/src/client/GRRunUI.py
===================================================================
--- trunk/gnue-reports/src/client/GRRunUI.py    2004-10-23 18:19:25 UTC (rev 
6554)
+++ trunk/gnue-reports/src/client/GRRunUI.py    2004-10-24 09:14:07 UTC (rev 
6555)
@@ -1,6 +1,9 @@
+# GNU Enterprise Reports - Run/create a user interface for starting a report
 #
-# This file is part of GNU Enterprise.
+# 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
@@ -16,96 +19,537 @@
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# Copyright 2000-2004 Free Software Foundation
-#
-# FILE:
-# GRRunUI.py
-#
-# DESCRIPTION:
-# Utilities that present a UI to the reader
-#
-# NOTES:
-#
+# $Id$
 
+import string
+import StringIO
 
-from StringIO import StringIO
+from gnue.common.apps import errors
 from gnue.common.utils.FileUtils import dyn_import
 
+
+# =============================================================================
+# This class handles an UI for a report
+# =============================================================================
+
 class GRRunUI:
 
-  def __init__(self, client, reportInfo,ui='text',
-               userParameters={},destination='-',
-               destinationType='file',filter='raw',
-               sortoption=None):
+  # --------------------------------------------------------------------------
+  # Constructor
+  # --------------------------------------------------------------------------
 
+  def __init__ (self, client, reportInfo, ui = 'text', userParameters = {},
+      destination = '-', destinationType = 'file', filter = 'raw',
+      sortoption = None):
 
     self.client = client
 
     if ui != 'text':
       try:
-        self.uimodule = dyn_import('gnue.forms.uidrivers.%s' % ui)
+        self.uimodule = dyn_import ('gnue.forms.uidrivers.%s' % ui)
 
         # Nasty hackery
         from gnue.forms.GFConfig import ConfigOptions as FormConfigOptions
-        
client.configurationManager.loadApplicationConfig(section="forms",defaults=FormConfigOptions)
-        client.configurationManager.registerAlias('gConfigForms', 'forms')
+        client.configurationManager.loadApplicationConfig (section = "forms",
+                                                  defaults = FormConfigOptions)
+        client.configurationManager.registerAlias ('gConfigForms', 'forms')
 
+        self.gfinstance = dyn_import ('gnue.forms.GFInstance')
+
       except ImportError:
         ui = 'text'
 
 
     if ui == 'text':
-      self.uimodule = None
-      self.loginhandler = LoginHandler()
+      self.uimodule     = None
+      self.loginhandler = LoginHandler ()
     else:
-      self.loginhandler = self.uimodule.UILoginHandler()
+      self.loginhandler = self.uimodule.UILoginHandler ()
 
-    self.reportInfo = reportInfo
-    self.userParameters = userParameters
-    self.ui = ui
-    self.destination = destination
+    self.reportInfo      = reportInfo
+    self.userParameters  = userParameters
+    self.ui              = ui
+    self.destination     = destination
     self.destinationType = destinationType
-    self.filter = filter
-    self.sortoption = sortoption
+    self.filter          = filter
+    self.sortoption      = sortoption
 
 
-  def getLoginHandler(self):
-    return self.loginhandler
+  # ---------------------------------------------------------------------------
+  # create a user interface and run it
+  # ---------------------------------------------------------------------------
 
+  def run (self):
+    """
+    """
 
-  def run(self):
     if self.uimodule:
-      pass
+      # First add some internal parameters to the userparams-dictionary
+      self.userParameters ['filter']          = self.filter
+      self.userParameters ['destination']     = self.destination
+      self.userParameters ['destinationType'] = self.destinationType
+      self.userParameters ['canceled']        = False
 
+      # Create the form's code on the fly and put it into an instance
+      formBuffer = self.__buildForm ()
+      instance   = self.gfinstance.GFInstance (self, self.client.connections,
+                                      self.uimodule, True, self.userParameters)
+      instance.addFormFromFilehandle (formBuffer)
+      instance.addDialogs ()
+      instance.activate ()
 
-  def getParameters(self):
+      # Now iterate through the parameters dictionary and fetch our 'private'
+      # values, also remove them from userParameters
+      if self.userParameters ['canceled']:
+        raise errors.UserError, u_("Report canceled")
+
+      self.filter          = self.userParameters ['filter']
+      self.destination     = self.userParameters ['destination']
+      self.destinationType = self.userParameters ['destinationType']
+
+      del self.userParameters ['filter']
+      del self.userParameters ['destination']
+      del self.userParameters ['destinationType']
+      del self.userParameters ['canceled']
+
+
+  # ---------------------------------------------------------------------------
+  # Get the current login handler
+  # ---------------------------------------------------------------------------
+
+  def getLoginHandler (self):
+    """
+    """
+
+    return self.loginhandler
+
+
+  # ---------------------------------------------------------------------------
+  # Get the user parameter dictionary
+  # ---------------------------------------------------------------------------
+
+  def getParameters (self):
+    """
+    """
+
     return self.userParameters
 
 
-  def getDestination(self):
+  # ---------------------------------------------------------------------------
+  # Get the current destination
+  # ---------------------------------------------------------------------------
+
+  def getDestination (self):
+    """
+    """
+
     return self.destination
 
 
-  def getDestinationType(self):
+  # ---------------------------------------------------------------------------
+  # Get the destination type
+  # ---------------------------------------------------------------------------
+
+  def getDestinationType (self):
+    """
+    """
+
     return self.destinationType
 
 
-  def getFilter(self):
+  # ---------------------------------------------------------------------------
+  # Get the current filter
+  # ---------------------------------------------------------------------------
+
+  def getFilter (self):
+    """
+    """
+
     return self.filter
 
 
-  def getSortOption(self):
+  # ---------------------------------------------------------------------------
+  # Get the current sort option
+  # ---------------------------------------------------------------------------
+
+  def getSortOption (self):
+    """
+    """
+
     return self.sortoption
 
 
+  # ---------------------------------------------------------------------------
+  # Generate a form for entering parameters and filter/destination
+  # ---------------------------------------------------------------------------
 
+  def __buildForm (self):
+    """
+    This function generates a GNU Enterprise Form Definition for the report as
+    described by our reportInfo property.
 
-def buildForm(reportParameters, userParameters):
-  buffer = StringIO()
+    @return: filehandle to read the form from
+    """
 
+    code = ['<?xml version="1.0" encoding="utf-8"?>', '<form>']
+    fields = self.__translateParameters ()
 
 
+    # Add all parameters as 'user parameters' to the form definition
+    for item in fields:
+      code.extend (self._getXMLTag ('parameter', \
+          {'name': item ['name'], 'default': item ['default']}, "  "))
 
+    # Add fields for the filter
+    self.__addOtherFields (fields)
+
+    # Get some positioning information from all fields
+    formHeight      = len (fields) + 3
+    self.labelWidth = 0
+    formWidth       = 0
+
+    for item in fields:
+      self.labelWidth = max (self.labelWidth, len (item ['label']))
+      formWidth  = max (formWidth, self.labelWidth + 2 + item ['dLength'])
+
+    # Add datasources and blocks
+    code.extend (self.__addDataSources ())
+    code.extend (self._getXMLTag ('logic', \
+                                {'contents': self.__addBlocks (fields)}, "  "))
+
+    code.extend (self.__addTriggers (fields))
+
+    # Layout
+    code.extend (self._getXMLTag ('layout', \
+        {'xmlns:c' : 'GNUe:Layout:Char',
+         'c:width' : formWidth,
+         'c:height': formHeight,
+         'contents': self.__addLabelsAndEntries (u_("Parameters"), fields)},
+         "  "))
+
+    code.append ("</form>")
+
+    # this is for debugging atm
+    x = open ('test.gfd', 'w')
+    for item in code:
+      x.write ("%s\n" % item)
+    x.close ()
+
+    # Prepare a buffer with the form's code and set it's position to the start
+    result = StringIO.StringIO ()
+    result.writelines (code)
+    result.seek (0, 0)
+
+    return result
+
+
+  # ---------------------------------------------------------------------------
+  # Translate the report parameters dictionary into a sequence
+  # ---------------------------------------------------------------------------
+
+  def __translateParameters (self):
+    """
+    This function maps all report parameters to a sequence of field
+    definitions.
+
+    @return: sequence of dictionaries, one per parameter
+    """
+
+    result = []
+
+    for param in self.reportInfo.getParameters ():
+      name    = param ['name']
+      
+      current = {'name'    : name,
+                 'default' : self.userParameters.get (name, param ['default']),
+                 'style'   : None,
+                 'format'  : None,
+                 'typecast': None,
+                 'dLength' : 35,
+                 'pType'   : param.get ('type', 'char'),
+                 'skip'    : False,
+                 'fieldDef': []}
+
+      pType = current ['pType']
+
+      if pType == ['boolean']:
+        current ['style']   = 'checkbox'
+        current ['dLength'] = 1
+
+      elif pType == ['date', 'time', 'datetime']:
+        current ['typecast'] = 'date'
+        masks = ['%x', '%X', '%x %X']
+        current ['format']  = masks [['date', 'time', 'datetime'].index 
(pType)]
+        current ['dLength'] = len (mx.DateTime.now ().strftime (format))
+
+      current ['label'] = param.get ('description', name)
+      result.append (current)
+
+    return result
+
+
+  # ---------------------------------------------------------------------------
+  # Add all other form fields to the field-sequecnce
+  # ---------------------------------------------------------------------------
+
+  def __addOtherFields (self, fields):
+    """
+    This function extends the given field-sequence with all outstanding fields
+    of the form, which are not given as paramter.
+
+    @param fields: sequence of field dictionaries to be extended.
+    """
+
+    fields.append ({'name'    : 'filter',
+                    'label'   : u_("Output filter"),
+                    'style'   : 'dropdown',
+                    'format'  : None,
+                    'typecast': None,
+                    'dLength' : 35,
+                    'pType'   : 'char',
+                    'skip'    : False,
+                    'fieldDef': [{'fk_source': 'dtsFilters'},
+                                 {'fk_key': 'key'},
+                                 {'fk_description': 'descr'}]})
+
+
+  # ---------------------------------------------------------------------------
+  # Create the XML code for all datasources needed by the form
+  # ---------------------------------------------------------------------------
+
+  def __addDataSources (self):
+    """
+    This function generates a XML code sequence with all datasources needed by
+    the form.
+
+    @return: sequence of XML code lines
+    """
+
+    filters = [('raw', u_("Raw XML"))]
+    for item in self.reportInfo.getFilters ():
+      filters.append ((item [1]['formatter'], item [1]['description']))
+
+    rows = []
+    for (key, descr) in filters:
+      rows.extend (self._getXMLTag ('staticsetrow',
+        {'contents': \
+          self._getXMLTag ('staticsetfield', \
+            {'name': 'key', 'value': key}, "") + \
+          self._getXMLTag ('staticsetfield', \
+            {'name': 'descr', 'value': descr}, "")}, ""))
+
+    return self._getXMLTag ('datasource', {'name': 'dtsFilters',
+        'type': 'static', 'prequery': 'Y',
+        'contents': self._getXMLTag ('staticset', {'fields': 'key,descr',
+          'contents': rows}, "")}, "  ")
+
+
+  # ---------------------------------------------------------------------------
+  # Add the XML code for all blocks needed
+  # ---------------------------------------------------------------------------
+
+  def __addBlocks (self, fields):
+    """
+    This function generates all block definitions.
+
+    @return: XML code sequence with block definitions
+    """
+
+    # First build the block with all input fields
+    inpBlock = []
+
+    for item in fields:
+      attrs = {'name': item ['name']}
+      for additional in item ['fieldDef']:
+        attrs.update (additional)
+      if item ['typecast'] is not None:
+        attrs ['typecast'] = item ['typecast']
+
+      inpBlock.extend (self._getXMLTag ('field', attrs, ""))
+
+    result = self._getXMLTag ('block', {'name': 'blkInput', 'autoCommit': 'Y',
+                                        'contents': inpBlock})
+
+    return result
+
+    
+  # ---------------------------------------------------------------------------
+  # Add the XML code for all triggers
+  # ---------------------------------------------------------------------------
+
+  def __addTriggers (self, fields):
+    """
+    This function creates the global triggers.
+
+    @return: XML code sequence with trigger code
+    """
+
+    onActivate = []
+    onExit     = []
+
+    for item in fields:
+      if item ['skip']:
+        continue
+
+      onActivate.append ("blkInput.%s.set (getParameter ('%s'))" \
+                          % (item ['name'], item ['name']))
+
+      onExit.append ("setParameter ('%s', blkInput.%s.get ())" \
+                     % (item ['name'], item ['name']))
+
+    
+    result = []
+
+    if len (onActivate):
+      result.extend (self._getXMLTag ('trigger', {'type': 'ON-ACTIVATION',
+                                                'contents': onActivate}, "  "))
+    if len (onExit):
+      result.extend (self._getXMLTag ('trigger', {'type': 'ON-EXIT',
+                                                'contents': onExit}, "  "))
+
+    # Button-Triggers
+    result.extend (self._getXMLTag ('trigger', {'type': 'NAMED',
+      'name': 'trgOk', 'contents': ["close ()"]}, "  "))
+
+    result.extend (self._getXMLTag ('trigger', {'type': 'NAMED',
+      'name': 'trgCancel',
+      'contents': ["setParameter ('canceled', True)", "close ()"]}, "  "))
+
+    return result
+
+
+  # ---------------------------------------------------------------------------
+  # Add all entries and labels to the given page
+  # ---------------------------------------------------------------------------
+
+  def __addLabelsAndEntries (self, page, fields):
+    """
+    This function creates a page with all the fields listed.
+
+    @param page: Name of the page to add the fields to
+    @param fields: sequence of field dictionaries to be added to the page
+
+    @return: XML code sequence with all fields including an Ok and Cancel
+        button.
+    """
+
+    result = []
+
+    labels  = []
+    entries = []
+    row     = 0
+
+    for item in fields:
+      row  += 1
+
+      # Label
+      attrs = {'c:x'     : 1,
+               'c:y'     : row,
+               'c:width' : len (item ['label']),
+               'c:height': 1,
+               'text'    : "%s:" % item ['label']}
+      labels.extend (self._getXMLTag ('label', attrs))
+
+      # Entry
+      attrs = {'c:x'     : 1 + self.labelWidth,
+               'c:y'     : row,
+               'c:width' : item ['dLength'],
+               'c:height': 1,
+               'block'   : 'blkInput',
+               'field'   : item ['name']}
+
+      if item ['style'] is not None:
+        attrs ['style'] = item ['style']
+
+      if item ['format'] is not None:
+        attrs ['displaymask'] = item ['format']
+        attrs ['inputmask']   = item ['format']
+
+      entries.extend (self._getXMLTag ('entry', attrs))
+
+    row += 2
+    buttons = [('Ok', u_("Ok")), ('Cancel', u_("Cancel"))]
+    maxbWidth = 0
+    for b in buttons:
+      maxbWidth = max (maxbWidth, len (b [1]) + 4)
+
+    left = self.labelWidth + 1
+
+    for b in buttons:
+      attrs = {'c:x'     : left,
+               'c:y'     : row,
+               'c:width' : maxbWidth,
+               'c:height': 1,
+               'label'   : b [1],
+               'contents': self._getXMLTag ('trigger', {'src': "trg%s" % b [0],
+                                                        'type': 'ON-ACTION'})}
+
+      entries.extend (self._getXMLTag ('button', attrs))
+      left += (maxbWidth + 1)
+
+    return self._getXMLTag ('page', \
+                                  {'name': page, 'contents': labels + entries})
+
+  # ---------------------------------------------------------------------------
+  # 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.
+
+    @return: sequence with XML code, one element per line
+    """
+    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
+
+
 #
 # This is a (temporary?) solution to getting a login
 #


Property changes on: trunk/gnue-reports/src/client/GRRunUI.py
___________________________________________________________________
Name: svn:keywords
   + Id





reply via email to

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