/[papo]/gnue/common/src/GTrigger.py
ViewVC logotype

Diff of /gnue/common/src/GTrigger.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.5 by styxman, Thu Sep 26 19:42:05 2002 UTC revision 1.6 by styxman, Fri Nov 15 15:32:54 2002 UTC
# Line 1  Line 1 
1  #  #
2  # This file is part of GNU Enterprise.  # This file is part of GNU Enterprise.
3  #  #
4  # GNU Enterprise is free software; you can redistribute it  # GNU Enterprise is free software; you can redistribute it
5  # and/or modify it under the terms of the GNU General Public  # and/or modify it under the terms of the GNU General Public
6  # License as published by the Free Software Foundation; either  # License as published by the Free Software Foundation; either
7  # version 2, or (at your option) any later version.  # version 2, or (at your option) any later version.
8  #  #
9  # GNU Enterprise is distributed in the hope that it will be  # GNU Enterprise is distributed in the hope that it will be
10  # useful, but WITHOUT ANY WARRANTY; without even the implied  # useful, but WITHOUT ANY WARRANTY; without even the implied
11  # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  # PURPOSE. See the GNU General Public License for more details.  # PURPOSE. See the GNU General Public License for more details.
13  #  #
14  # You should have received a copy of the GNU General Public  # You should have received a copy of the GNU General Public
15  # License along with program; see the file COPYING. If not,  # License along with program; see the file COPYING. If not,
16  # write to the Free Software Foundation, Inc., 59 Temple Place  # write to the Free Software Foundation, Inc., 59 Temple Place
17  # - Suite 330, Boston, MA 02111-1307, USA.  # - Suite 330, Boston, MA 02111-1307, USA.
18  #  #
19  # Copyright 2000-2002 Free Software Foundation  # Copyright 2000-2002 Free Software Foundation
# Line 30  Line 30 
30  import sys  import sys
31  import types  import types
32  import string  import string
33    import copy
34  from gnue.common.GObjects import GObj  from gnue.common.GObjects import GObj
35  from gnue.common import GDebug  from gnue.common import GDebug
36    
37  from gnue.common import GTypecast  from gnue.common import GTypecast
38  from xml.sax import saxutils  from xml.sax import saxutils
39  from gnue.common.GParser import GContent  from gnue.common.GParserHelpers import GContent
40    
41  class TriggerError:  class TriggerError:
42    def __init__(self, msg):    def __init__(self, msg):
# Line 50  class TriggerSuccess: Line 51  class TriggerSuccess:
51    pass    pass
52    
53    
54            
55    
56  #######################################################################  #######################################################################
57  #  #
# Line 66  class TriggerSuccess: Line 67  class TriggerSuccess:
67  # GTriggerNSObject based tree  # GTriggerNSObject based tree
68  #  #
69  class GTriggerNamespace(GObj):  class GTriggerNamespace(GObj):
70    def __init__(self,objectTree = None):    def __init__(self,objectTree = None, rootName="root"):
71      self._globalNamespace = {'True' : 1,      self._globalNamespace = {'True' : 1,
72                               'False': 0,                               'False': 0,
73                               }                               }
74    
75        self._rname = rootName
76    
77      if objectTree:      if objectTree:
78        self._globalNamespace['form'] = self.constructTriggerObject(objectTree)        self._globalNamespace[self._rname] = self.constructTriggerObject(objectTree)
79      else:      else:
80        GDebug.printMesg(0,'GTriggerNamespace was passed an empty object tree')        GDebug.printMesg(0,'GTriggerNamespace was passed an empty object tree')
81    
82      
83    #    #
84    # constructTriggerObject    # constructTriggerObject
85    #    #
86    # Travels down thru a GObj based tree and builds a set    # Travels down thru a GObj based tree and builds a set
87    # of GTriggerNSObjects that will implement the namespace    # of GTriggerNSObjects that will implement the namespace
88    # inside triggers.    # inside triggers.
89    #    #
90    def constructTriggerObject(self, gobjObject, triggerParent=None):    def constructTriggerObject(self, gobjObject, triggerParent=None):
91      triggerObject = None      triggerObject = None
92    
93      # Some items in a GObj tree may not be GObj based (GContent for instance)      # Some items in a GObj tree may not be GObj based (GContent for instance)
94        
95      if isinstance(gobjObject,GObj) and hasattr(gobjObject,'name'):      if isinstance(gobjObject,GObj) and hasattr(gobjObject,'name'):
96        triggerObject = GTriggerNSObject(triggerParent)        triggerObject = GTriggerNSObject(triggerParent)
97        triggerObject._object = gobjObject        triggerObject._object = gobjObject
98    
# Line 98  class GTriggerNamespace(GObj): Line 103  class GTriggerNamespace(GObj):
103        # setup get and set functions when they exist in the GObj        # setup get and set functions when they exist in the GObj
104        triggerObject._triggerSet = gobjObject._triggerSet        triggerObject._triggerSet = gobjObject._triggerSet
105        triggerObject._triggerGet = gobjObject._triggerGet        triggerObject._triggerGet = gobjObject._triggerGet
106          
107        # Add any trigger methods defined by GObj        # Add any trigger methods defined by GObj
108        if len(gobjObject._triggerFunctions):        if len(gobjObject._triggerFunctions):
109          for item in gobjObject._triggerFunctions.keys():          for item in gobjObject._triggerFunctions.keys():
110              
111            if type(gobjObject._triggerFunctions[item]['function']) == types.MethodType:            if type(gobjObject._triggerFunctions[item]['function']) == types.MethodType:
112              object = GTriggerNSFunction(item,gobjObject._triggerFunctions[item]['function'])                                      object = GTriggerNSFunction(item,gobjObject._triggerFunctions[item]['function'])
113              triggerObject.__dict__[item] = object              triggerObject.__dict__[item] = object
114              # Add this function to global namespace if the GObj requests it              # Add this function to global namespace if the GObj requests it
115              if gobjObject._triggerFunctions[item].has_key('global') and \              if gobjObject._triggerFunctions[item].has_key('global') and \
# Line 113  class GTriggerNamespace(GObj): Line 118  class GTriggerNamespace(GObj):
118    
119            else:            else:
120              GDebug.printMesg(0,'Only functions are supported in an objects _triggerFunctions %s %s' % (gobjObject,item))              GDebug.printMesg(0,'Only functions are supported in an objects _triggerFunctions %s %s' % (gobjObject,item))
121                
122              sys.exit()              sys.exit()
123    
124        # Load the defined __properties__ into this object's        # Load the defined __properties__ into this object's
# Line 126  class GTriggerNamespace(GObj): Line 131  class GTriggerNamespace(GObj):
131              setFunc = None              setFunc = None
132            triggerObject._triggerProperties.addProperty(item,gobjObject._triggerProperties[item]['get'], setFunc)            triggerObject._triggerProperties.addProperty(item,gobjObject._triggerProperties[item]['get'], setFunc)
133    
134        # Process the children of this Gobj        # Process the children of this Gobj
135        if len(gobjObject._children):        if len(gobjObject._children):
136          for child in gobjObject._children:          for child in gobjObject._children:
137            object = self.constructTriggerObject(child, triggerObject)            object = self.constructTriggerObject(child, triggerObject)
138              
139            # Add this objects children to it's namespace by their name            # Add this objects children to it's namespace by their name
140            if object:            if object:
141              triggerObject.__dict__[child.name] = object              triggerObject.__dict__[child.name] = object
# Line 146  class GTriggerNamespace(GObj): Line 151  class GTriggerNamespace(GObj):
151  #  #
152  # GTriggerNSObject  # GTriggerNSObject
153  #  #
154  # Inherrits GObj to gain it's parent/child system  # Inherits GObj to gain it's parent/child system
155  #  #
156  class GTriggerNSObject(GObj):  class GTriggerNSObject(GObj):
157    def __init__(self, parent):    def __init__(self, parent):
# Line 155  class GTriggerNSObject(GObj): Line 160  class GTriggerNSObject(GObj):
160      self._triggerSet = None      self._triggerSet = None
161      self._triggerGet = None      self._triggerGet = None
162      self._object = None      self._object = None
163        
164    #    #
165    # showTree    # showTree
166    #    #
# Line 197  class GTriggerNSObject(GObj): Line 202  class GTriggerNSObject(GObj):
202    # __getattr__    # __getattr__
203    #    #
204    # Only needed to return the GTriggerNSObjectProperties    # Only needed to return the GTriggerNSObjectProperties
205    # object    # object
206    #    #
207    def __getattr__(self,name):    def __getattr__(self,name):
208      if name == '__properties__':      if name == '__properties__':
209          return self._triggerProperties          return self._triggerProperties
210      else:      else:
211        GDebug.printMesg(1,"AttributeError: %s" % name)  #      GDebug.printMesg(1,"AttributeError: %s" % name)
212  #      print self.__dict__  #      print self.__dict__
213        raise AttributeError        raise AttributeError, '%s' % (name)
214              
215    #    #
216    # __str__    # __str__
217    #    #
# Line 304  class GTriggerNSObjectProperties: Line 309  class GTriggerNSObjectProperties:
309      # Hack to ensure that self._properties exists      # Hack to ensure that self._properties exists
310      if not self.__dict__.has_key('_properties'):      if not self.__dict__.has_key('_properties'):
311        self.__dict__['_properties'] = {}        self.__dict__['_properties'] = {}
312          
313      if self._properties.has_key(name):      if self._properties.has_key(name):
314        # If none the it's readonly        # If none the it's readonly
315        if self._properties[name]['set']:        if self._properties[name]['set']:
316          self._properties[name]['set'](value)          self._properties[name]['set'](value)
317        else:        else:
318          GDebug.printMesg(0,'Attempt to set readonly property :%s' %(name))          GDebug.printMesg(0,'Attempt to set readonly property :%s' %(name))
# Line 337  class GTriggerNSObjectProperties: Line 342  class GTriggerNSObjectProperties:
342  #       only here so that the new namespace code could be  #       only here so that the new namespace code could be
343  #       put to use right away  #       put to use right away
344    
 #  
 # A list of all valid triggers, and their "pretty" names  
 #  
 VALIDTRIGGERS = { 'PRE-FOCUSOUT':   'Pre-FocusOut',  
                   'POST-FOCUSOUT':  'Post-FocusOut',  
                   'PRE-FOCUSIN':    'Pre-FocusIn',  
                   'POST-FOCUSIN':   'Post-FocusIn',  
                   'PRE-COMMIT':     'Pre-Commit',  
                   'POST-COMMIT':    'Post-Commit',  
                   'POST-QUERY':     'Post-Query',  
                   'ON-SWITCH':      'On-Switch',  
                   'PRE-CHANGE':     'Pre-Change',  
                   'POST-CHANGE':    'Post-Change',  
                   'ON-NEWRECORD':   'On-NewRecord' }  
   
   
   
345    
346  #  #
347  # GTrigger  # GTrigger
# Line 362  VALIDTRIGGERS = { 'PRE-FOCUSOUT':   'Pre Line 350  VALIDTRIGGERS = { 'PRE-FOCUSOUT':   'Pre
350  #  #
351  class GTrigger(GObj):  class GTrigger(GObj):
352    def __init__(self, parent=None, type=None, name=None, src=None, text=None, language='python'):    def __init__(self, parent=None, type=None, name=None, src=None, text=None, language='python'):
353      GObj.__init__(self, parent, 'GTrigger')  
354        GObj.__init__(self, parent, 'GCTrigger')
355    
356      self._text=''      self._text=''
357      self._triggerns={}      self._triggerns={}
# Line 377  class GTrigger(GObj): Line 366  class GTrigger(GObj):
366      if self.type != None:      if self.type != None:
367        self._buildObject()        self._buildObject()
368    
369        
370    #    #
371    # Must be at least a phase 2 init    # Must be at least a phase 2 init
372    #    #
# Line 386  class GTrigger(GObj): Line 376  class GTrigger(GObj):
376    # TODO: merge the local namespace of the object that    # TODO: merge the local namespace of the object that
377    # TODO: fired the trigger.    # TODO: fired the trigger.
378    def initialize(self):    def initialize(self):
379      self._form = self.findParentOfType('GFForm')      self._root = self.findParentOfType(None)
380      self._triggerns.update( self._form._triggerns )      self._triggerns.update( self._root._triggerns )
381        self._globalns = self._root._globalRuntimeNamespace
382      self.__call__ = self.dummyFunction      self.__call__ = self.dummyFunction
383    
384      if self.type != "NAMED":      if self.type != "NAMED":
385        if self._parent:        if self._parent:
386          self._parent.addTrigger( self.type, self )          self._parent.associateTrigger( self.type, self )
387          self._triggerns.update(self._parent._localTriggerNamespace)          self._triggerns.update(self._parent._localTriggerNamespace)
388      else:      else:
389        form = self.findParentOfType('GFForm')        self._root._triggerDictionary[self.name] = self
390        form._triggerDictionary[self.name] = self        self._triggerns.update(self._root._localTriggerNamespace)
       self._triggerns.update(form._localTriggerNamespace)  
391    
392      if self.src == None:      if self.src == None:
393        self.setFunction( self.getChildrenAsContent(), self.language )        self.setFunction( self.getChildrenAsContent(), self.language )
394      else:      else:
395        self.setFunctionFrom(self._form._triggerDictionary[self.src])        self.setFunctionFrom(self._root._triggerDictionary[self.src])
396    
397    
398    def setFunctionFrom(self, object):    def setFunctionFrom(self, object):
# Line 422  class GTrigger(GObj): Line 412  class GTrigger(GObj):
412        GDebug.printMesg(0, "The trigger named %s contains a tab character which is not allowed at pos %s"        GDebug.printMesg(0, "The trigger named %s contains a tab character which is not allowed at pos %s"
413                         % ( self.name, string.find('\t', self._text) ))                         % ( self.name, string.find('\t', self._text) ))
414        sys.exit()        sys.exit()
415          
416      # Remove whitespace from last line      # Remove whitespace from last line
417      self._text = string.rstrip(self._text)      self._text = string.rstrip(self._text)
418    
# Line 431  class GTrigger(GObj): Line 421  class GTrigger(GObj):
421      #   syntax errors are spotted during XML parsing rather than      #   syntax errors are spotted during XML parsing rather than
422      #   during execution.      #   during execution.
423    
424      # Get the indentation level of the first line of code so      # Get the indentation level of the first line of code so
425      # we can indent our imports to the same level      # we can indent our imports to the same level
426      indentLevel = 0      indentLevel = 0
427      for line in string.split(string.replace(self._text,'\r',''),'\n'):      for line in string.split(string.replace(self._text,'\r',''),'\n'):
# Line 454  class GTrigger(GObj): Line 444  class GTrigger(GObj):
444        sys.exit()        sys.exit()
445    
446      def thisTrigger(myself, code = self._code,      def thisTrigger(myself, code = self._code,
447                      triggerns = self._triggerns):                      triggerns = self._triggerns,
448                        globalns = self._globalns):
449  #      triggerns['self'] = myself  #      triggerns['self'] = myself
450  #      triggerns['runform'] = myself.findParentOfType('GFForm')._app.getManager().runFormFromTrigger  #      triggerns['runform'] = myself.findParentOfType('GFForm')._app.getManager().runFormFromTrigger
451  #      triggerns.update(  #      triggerns.update(
452    
453          # Merge the trigger's namespace with the runtime global namespace
454          # (Which can be set via the "global myvar" construct)
455          try:
456            del globalns['__builtins__']
457          except KeyError:
458            pass
459        try:        try:
460          locals = {}          localns = copy.copy(triggerns)
461          exec code in triggerns, locals          localns.update(globalns)
462    
463            # And execute our code
464            exec code in globalns, localns
465        except TriggerError:        except TriggerError:
466          raise          raise
467        except:        except:
468          # May be better to deal with this in GFTriggerAware          # May be better to deal with this in GTriggerExtension
469          raise          raise
470          import sys          import sys
471          GDebug.printMesg(0, "%s in trigger code, value: %s" % (sys.exc_type, sys.exc_value))          GDebug.printMesg(0, "%s in trigger code, value: %s" % (sys.exc_type, sys.exc_value))
# Line 481  class GTrigger(GObj): Line 482  class GTrigger(GObj):
482    # for use by designer    # for use by designer
483    #    #
484    def getDescription(self):    def getDescription(self):
485      if self.type == 'NAMED':      if self.type == 'NAMED':
486        return self.name        return self.name
487      else:      else:
488        return VALIDTRIGGERS[string.upper(self.type)]        return string.upper(self.type)
489    
490    #    #
491    # dumpXML    # dumpXML
# Line 493  class GTrigger(GObj): Line 494  class GTrigger(GObj):
494    # used in saving    # used in saving
495    #    #
496    def dumpXML(self, lookupDict, treeDump=None, gap=None,xmlnamespaces={}):    def dumpXML(self, lookupDict, treeDump=None, gap=None,xmlnamespaces={}):
497      escape = not int(gConfig('StoreTriggersAsCDATA'))      try:
498          escape = not int(gConfig('StoreTriggersAsCDATA'))
499        except:
500          escape = 1
501      xmlEntity = "trigger"      xmlEntity = "trigger"
502      xmlString = "%s<%s" % (gap[:-2],xmlEntity)      xmlString = "%s<%s" % (gap[:-2],xmlEntity)
503    
504      indent = len(xmlString)      indent = len(xmlString)
505      pos = indent      pos = indent
506      for attribute in self.__dict__.keys():      for attribute in self.__dict__.keys():
507          
508        # variables beginning with _ are never saved out to file        # variables beginning with _ are never saved out to file
509        # they are internal to the program        # they are internal to the program
510        if attribute[0] == "_":        if attribute[0] == "_":
511          continue          continue
512          
513        val = self.__dict__[attribute]        val = self.__dict__[attribute]
514        if lookupDict[xmlEntity].has_key('Attributes') and \        if lookupDict[xmlEntity].has_key('Attributes') and \
515           lookupDict[xmlEntity]['Attributes'].has_key(attribute):           lookupDict[xmlEntity]['Attributes'].has_key(attribute):
516          if val != None and \          if val != None and \
517             (not lookupDict[xmlEntity]['Attributes'][attribute].has_key('Default') or \             (not lookupDict[xmlEntity]['Attributes'][attribute].has_key('Default') or \
518              (lookupDict[xmlEntity]['Attributes'][attribute]['Default']) != (val)):              (lookupDict[xmlEntity]['Attributes'][attribute]['Default']) != (val)):
519            typecast = lookupDict[xmlEntity]['Attributes'][attribute]['Typecast']            typecast = lookupDict[xmlEntity]['Attributes'][attribute]['Typecast']
520            if typecast == GTypecast.boolean \            if typecast == GTypecast.boolean \
521               and val == 1:               and val == 1:
# Line 519  class GTrigger(GObj): Line 523  class GTrigger(GObj):
523            elif typecast == GTypecast.names:            elif typecast == GTypecast.names:
524              addl = ' %s="%s"' % \              addl = ' %s="%s"' % \
525                  (attribute, string.join(val,','))                  (attribute, string.join(val,','))
526            else:            else:
527              addl = ' %s="%s"' % (attribute, saxutils.escape('%s' % val))              addl = ' %s="%s"' % (attribute, saxutils.escape('%s' % val))
528            if len(addl) + pos > 78:            if len(addl) + pos > 78:
529              xmlString += "\n" + " " * indent + addl              xmlString += "\n" + " " * indent + addl
530              pos = indent              pos = indent
531            else:            else:
532              xmlString = xmlString + addl              xmlString = xmlString + addl
533              pos += len(addl)              pos += len(addl)
534            
535      if len(self._children):      if len(self._children):
536        hasContent = 0        hasContent = 0
537        for child in self._children:        for child in self._children:
538          hasContent = hasContent or isinstance(child,GContent)          hasContent = hasContent or isinstance(child,GContent)
539        if hasContent:        if hasContent:
540          xmlString += ">"          xmlString += ">"
541        else:        else:
542          xmlString += ">\n"          xmlString += ">\n"
543          
544        if treeDump:        if treeDump:
545          if hasContent and not escape:          if hasContent and not escape:
546            xmlString += "<![CDATA["            xmlString += "<![CDATA["
547          for child in self._children:          for child in self._children:
548            xmlString += child.dumpXML(lookupDict, 1,gap+"  ",escape=escape)            xmlString += child.dumpXML(lookupDict, 1,gap+"  ",escape=escape)
549          if hasContent and not escape:          if hasContent and not escape:
550            xmlString += "]]!>"            xmlString += "]]>"
551    
552        if hasContent:        if hasContent:
553          xmlString += "</%s>\n" % (xmlEntity)          xmlString += "</%s>\n" % (xmlEntity)
554        else:        else:
555          xmlString += "%s</%s>\n" % (gap[:-2], xmlEntity)          xmlString += "%s</%s>\n" % (gap[:-2], xmlEntity)
556      else:      else:
557        xmlString += "/>\n"              xmlString += "/>\n"
558      return xmlString      return xmlString
559    
560    
561    
562    
563              
564  #######################################################################  #######################################################################
565  #  #
566  # Trigger processor classes  # Trigger processor classes
# Line 569  class GTrigger(GObj): Line 573  class GTrigger(GObj):
573  class GTriggerExtension:  class GTriggerExtension:
574    def __init__(self):    def __init__(self):
575      self._trigger = {}      self._trigger = {}
576      self._validTriggers = {} # TODO : This probably needs moved into the apps trigger manager.      
577                               # TODO : I'll think about this more after sleep.      #self._validTriggers = validTriggers
578                                            
579    # associateTrigger    # associateTrigger
580    #    #
581    # Associates a trigger with the object.  More than one trigger of a specific type    # Associates a trigger with the object.  More than one trigger of a specific type
# Line 579  class GTriggerExtension: Line 583  class GTriggerExtension:
583    #    #
584    def associateTrigger(self, key, function):    def associateTrigger(self, key, function):
585      key = string.upper(key)      key = string.upper(key)
586      if key in self._validTriggers:      if key in self._validTriggers.keys():
587        if not self._trigger.has_key(key):        if not self._trigger.has_key(key):
588          self._trigger[string.upper(key)] = []          self._trigger[string.upper(key)] = []
589        self._trigger[string.upper(key)].append(function)        self._trigger[string.upper(key)].append(function)
# Line 587  class GTriggerExtension: Line 591  class GTriggerExtension:
591        print _("Invalid trigger "),key        print _("Invalid trigger "),key
592    
593    # processTrigger    # processTrigger
594    #    #
595    # "fires" the trigger    # "fires" the trigger
596    def processTrigger(self, key):    def processTrigger(self, key):
597      key = string.upper(key)      key = string.upper(key)
598      if key in self._validTriggers:      if key in self._validTriggers.keys():
599        if self._trigger.has_key(key):        if self._trigger.has_key(key):
600          for function in self._trigger[key]:          for function in self._trigger[key]:
601            function(self)            function(self)
602        else:        else:
603          GDebug.printMesg(10, "No triggers to fire")          GDebug.printMesg(10, "No triggers to fire")
604      else:      else:
605        print _("Invalid trigger "),key        print self._type,": ",_("Invalid trigger "),key
   
606    
607    
608    #
609    # Return any XML elements associated with
610    # GDataSources.  Bases is a dictionary of tags
611    # whose values are update dictionaries.
612    # For example: bases={'datasource': {'BaseClass':myDataSource}}
613    # sets xmlElements['datasource']['BaseClass'] = myDataSource
614    #
615    def getXMLelements(updates={}):
616    
617      xmlElements = {
618          'trigger': {
619             'BaseClass': GTrigger,
620             'Importable': 1,
621             'Attributes': {
622                'name': {
623                   'Unique': 1,
624                   'Typecast': GTypecast.name },
625                'id': {
626                   'Deprecated': 'Use name="..." instead.',   # DEPRECATED: Use name instead
627                   'Typecast': GTypecast.name },
628                'type': {
629                   'Typecast': GTypecast.uppername },
630                'src': {
631                   'References': (('trigger','name'),),
632                   'Typecast': GTypecast.name },
633                'language': {
634                   'Typecast': GTypecast.name,
635                   'ValueSet': {
636                       'python': {} },
637                   'Default': 'python' } },
638             'MixedContent': 1,
639             'KeepWhitespace': 1,
640             'UsableBySiblings': 1,
641             'ParentTags': None },
642          }
643    
644      for alteration in updates.keys():
645        xmlElements[alteration].update(updates[alteration])
646    
647      return xmlElements
648    

Legend:
Removed from v.1.5  
changed lines
  Added in v.1.6

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26