| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | # VRML node prototype class (SGbuilder) | 
					
						
							|  |  |  | # Wed Oct 31 16:18:35 CET 2001 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | '''Prototype2 -- VRML 97 sceneGraph/Node/Script/ROUTE/IS implementations''' | 
					
						
							| 
									
										
										
										
											2003-01-06 17:27:43 +00:00
										 |  |  | #import copy, types # extern | 
					
						
							|  |  |  | import types # extern | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | import strop as string # builtin | 
					
						
							|  |  |  | from utils import typeclasses, err, namespace # XXX | 
					
						
							|  |  |  | ## TODO: namespace must go | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class baseProto: | 
					
						
							|  |  |  | 	def __vrmlStr__( self, **namedargs ): | 
					
						
							|  |  |  | 		'''Generate a VRML 97-syntax string representing this Prototype
 | 
					
						
							|  |  |  | 		**namedargs -- key:value | 
					
						
							|  |  |  | 			passed arguments for the linearisation object | 
					
						
							|  |  |  | 		see lineariser4.Lineariser | 
					
						
							|  |  |  | 		'''
 | 
					
						
							| 
									
										
										
										
											2003-01-06 17:27:43 +00:00
										 |  |  | #		import lineariser4  | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | 		lineariser = apply( lineariser4.Lineariser, (), namedargs ) | 
					
						
							|  |  |  | 		return apply( lineariser.linear, ( self, ), namedargs ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	toString = __vrmlStr__  | 
					
						
							|  |  |  | 	# added stuff for linking support for target scenegraph | 
					
						
							|  |  |  | 	def setTargetnode(self, node): | 
					
						
							|  |  |  | 		self.__dict__['_targetnode'] = node | 
					
						
							|  |  |  | 	def getTargetnode(self): | 
					
						
							|  |  |  | 		try: | 
					
						
							|  |  |  | 			return self.__dict__['_targetnode'] | 
					
						
							|  |  |  | 		except: | 
					
						
							|  |  |  | 			return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Prototype(baseProto): | 
					
						
							|  |  |  | 	''' A VRML 97 Prototype object
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	A Prototype is a callable object which produces Node instances | 
					
						
							|  |  |  | 	the Node uses a pointer to its Prototype to provide much of the | 
					
						
							|  |  |  | 	Node's standard functionality. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Prototype's are often stored in a sceneGraph's protoTypes namespace, | 
					
						
							|  |  |  | 	where you can access them as sceneGraph.protoTypes.nodeGI . They are | 
					
						
							|  |  |  | 	also commonly found in Nodes' PROTO attributes. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Attributes: | 
					
						
							|  |  |  | 		__gi__ -- constant string "PROTO" | 
					
						
							|  |  |  | 		nodeGI -- string gi | 
					
						
							|  |  |  | 			The "generic identifier" of the node type, i.e. the name of the node | 
					
						
							|  |  |  | 		fieldDictionary -- string name: (string name, string dataType, boolean exposed) | 
					
						
							|  |  |  | 		defaultDictionary -- string name: object defaultValue | 
					
						
							|  |  |  | 			Will be blank for EXTERNPROTO's and Script prototypes | 
					
						
							|  |  |  | 		eventDictionary -- string name: (string name, string dataType, boolean eventOut) | 
					
						
							|  |  |  | 		sceneGraph -- object sceneGraph | 
					
						
							|  |  |  | 		MFNodeNames -- list of field name strings | 
					
						
							|  |  |  | 			Allows for easy calculation of "children" nodes | 
					
						
							|  |  |  | 		SFNodeNames -- list of field name strings | 
					
						
							|  |  |  | 			Allows for easy calculation of "children" nodes | 
					
						
							|  |  |  | 	'''
 | 
					
						
							|  |  |  | 	__gi__ = "PROTO" | 
					
						
							|  |  |  | 	def __init__(self, gi, fieldDict=None, defaultDict=None, eventDict=None, sGraph=None): | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		gi -- string gi | 
					
						
							|  |  |  | 			see attribute nodeGI | 
					
						
							|  |  |  | 		fieldDict -- string name: (string name, string dataType, boolean exposed) | 
					
						
							|  |  |  | 			see attribute fieldDictionary | 
					
						
							|  |  |  | 		defaultDict -- string name: object defaultValue | 
					
						
							|  |  |  | 			see attribute defaultDictionary | 
					
						
							|  |  |  | 		eventDict -- string name: (string name, string dataType, boolean eventOut) | 
					
						
							|  |  |  | 			see attribute eventDictionary | 
					
						
							|  |  |  | 		sceneGraph -- object sceneGraph | 
					
						
							|  |  |  | 			see attribute sceneGraph | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		self.nodeGI = checkName( gi ) | 
					
						
							|  |  |  | 		self.fieldDictionary = {} | 
					
						
							|  |  |  | 		self.defaultDictionary = {} | 
					
						
							|  |  |  | 		self.eventDictionary = {} | 
					
						
							|  |  |  | 		self.SFNodeNames = [] | 
					
						
							|  |  |  | 		self.MFNodeNames = [] | 
					
						
							|  |  |  | 		self.sceneGraph = sGraph | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		# setup the fields/events | 
					
						
							|  |  |  | 		for definition in (fieldDict or {}).values(): | 
					
						
							|  |  |  | 			self.addField( definition, (defaultDict or {}).get( definition[0])) | 
					
						
							|  |  |  | 		for definition in (eventDict or {}).values(): | 
					
						
							|  |  |  | 			self.addEvent( definition ) | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 	def getSceneGraph( self ): | 
					
						
							|  |  |  | 		''' Retrieve the sceneGraph object (may be None object)
 | 
					
						
							|  |  |  | 		see attribute sceneGraph'''
 | 
					
						
							|  |  |  | 		return self.sceneGraph | 
					
						
							|  |  |  | 	def setSceneGraph( self, sceneGraph ): | 
					
						
							|  |  |  | 		''' Set the sceneGraph object (may be None object)
 | 
					
						
							|  |  |  | 		see attribute sceneGraph'''
 | 
					
						
							|  |  |  | 		self.sceneGraph = sceneGraph | 
					
						
							|  |  |  | 	def getChildren(self, includeSceneGraph=None, includeDefaults=1, *args, **namedargs): | 
					
						
							|  |  |  | 		''' Calculate the current children of the PROTO and return as a list of nodes
 | 
					
						
							|  |  |  | 		if includeDefaults: | 
					
						
							|  |  |  | 			include those default values which are node values | 
					
						
							|  |  |  | 		if includeSceneGraph: | 
					
						
							|  |  |  | 			include the sceneGraph object if it is not None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		see attribute MFNodeNames | 
					
						
							|  |  |  | 		see attribute SFNodeNames | 
					
						
							|  |  |  | 		see attribute sceneGraph | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		temp = [] | 
					
						
							|  |  |  | 		if includeDefaults: | 
					
						
							|  |  |  | 			for attrname in self.SFNodeNames: | 
					
						
							|  |  |  | 				try: | 
					
						
							|  |  |  | 					temp.append( self.defaultDictionary[attrname] ) | 
					
						
							|  |  |  | 				except KeyError: # sceneGraph object is not copied... | 
					
						
							|  |  |  | 					pass | 
					
						
							|  |  |  | 			for attrname in self.MFNodeNames: | 
					
						
							|  |  |  | 				try: | 
					
						
							|  |  |  | 					temp[len(temp):] = self.defaultDictionary[attrname] | 
					
						
							|  |  |  | 				except KeyError: | 
					
						
							|  |  |  | 					pass | 
					
						
							|  |  |  | 		if includeSceneGraph and self.sceneGraph: | 
					
						
							|  |  |  | 			temp.append( self.getSceneGraph() ) | 
					
						
							|  |  |  | 		return temp | 
					
						
							|  |  |  | 	def addField (self, definition, default = None): | 
					
						
							|  |  |  | 		''' Add a single field definition to the Prototype
 | 
					
						
							|  |  |  | 		definition -- (string name, string dataType, boolean exposed) | 
					
						
							|  |  |  | 		default -- object defaultValue | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		see attribute fieldDictionary | 
					
						
							|  |  |  | 		see attribute defaultDictionary | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if type (definition) == types.InstanceType: | 
					
						
							|  |  |  | 			definition = definition.getDefinition() | 
					
						
							|  |  |  | 			default = definition.getDefault () | 
					
						
							|  |  |  | 		self.removeField( definition[0] ) | 
					
						
							|  |  |  | 		self.fieldDictionary[definition [0]] = definition | 
					
						
							|  |  |  | 		if default is not None: | 
					
						
							|  |  |  | 			default = fieldcoercian.FieldCoercian()( default, definition[1] ) | 
					
						
							|  |  |  | 			self.defaultDictionary [definition [0]] = default | 
					
						
							|  |  |  | 		if definition[1] == 'SFNode': | 
					
						
							|  |  |  | 			self.SFNodeNames.append(definition[0]) | 
					
						
							|  |  |  | 		elif definition[1] == 'MFNode': | 
					
						
							|  |  |  | 			self.MFNodeNames.append(definition[0]) | 
					
						
							|  |  |  | 	def removeField (self, key): | 
					
						
							|  |  |  | 		''' Remove a single field from the Prototype
 | 
					
						
							|  |  |  | 		key -- string fieldName | 
					
						
							|  |  |  | 			The name of the field to remove | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if self.fieldDictionary.has_key (key): | 
					
						
							|  |  |  | 			del self.fieldDictionary [key] | 
					
						
							|  |  |  | 		if self.defaultDictionary.has_key (key): | 
					
						
							|  |  |  | 			del self.defaultDictionary [key] | 
					
						
							|  |  |  | 		for attribute in (self.SFNodeNames, self.MFNodeNames): | 
					
						
							|  |  |  | 			while key in attribute: | 
					
						
							|  |  |  | 				attribute.remove(key) | 
					
						
							|  |  |  | 	def addEvent(self, definition): | 
					
						
							|  |  |  | 		''' Add a single event definition to the Prototype
 | 
					
						
							|  |  |  | 		definition -- (string name, string dataType, boolean eventOut) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		see attribute eventDictionary | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if type (definition) == types.InstanceType: | 
					
						
							|  |  |  | 			definition = definition.getDefinition() | 
					
						
							|  |  |  | 		self.eventDictionary[definition [0]] = definition | 
					
						
							|  |  |  | 	def removeEvent(self, key): | 
					
						
							|  |  |  | 		''' Remove a single event from the Prototype
 | 
					
						
							|  |  |  | 		key -- string eventName | 
					
						
							|  |  |  | 			The name of the event to remove | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if self.eventDictionary.has_key (key): | 
					
						
							|  |  |  | 			del self.eventDictionary [key] | 
					
						
							|  |  |  | 	def getField( self, key ): | 
					
						
							|  |  |  | 		'''Return a Field or Event object representing a given name
 | 
					
						
							|  |  |  | 		key -- string name | 
					
						
							|  |  |  | 			The name of the field or event to retrieve | 
					
						
							|  |  |  | 			will attempt to match key, key[4:], and key [:-8] | 
					
						
							|  |  |  | 			corresponding to key, set_key and key_changed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		see class Field | 
					
						
							|  |  |  | 		see class Event | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | #		print self.fieldDictionary, self.eventDictionary | 
					
						
							|  |  |  | 		for tempkey in (key, key[4:], key[:-8]): | 
					
						
							|  |  |  | 			if self.fieldDictionary.has_key( tempkey ): | 
					
						
							|  |  |  | 				return Field( self.fieldDictionary[tempkey], self.defaultDictionary.get(tempkey) ) | 
					
						
							|  |  |  | 			elif self.eventDictionary.has_key( tempkey ): | 
					
						
							|  |  |  | 				return Event( self.eventDictionary[tempkey] ) | 
					
						
							|  |  |  | 		raise AttributeError, key | 
					
						
							|  |  |  | 	def getDefault( self, key ): | 
					
						
							|  |  |  | 		'''Return the default value for the given field
 | 
					
						
							|  |  |  | 		key -- string name | 
					
						
							|  |  |  | 			The name of the field | 
					
						
							|  |  |  | 			Will attempt to match key, key[4:], and key [:-8] | 
					
						
							|  |  |  | 			corresponding to key, set_key and key_changed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		see attribute defaultDictionary | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		for key in (key, key[4:], key[:-8]): | 
					
						
							|  |  |  | 			if self.defaultDictionary.has_key( key ): | 
					
						
							|  |  |  | 				val = self.defaultDictionary[key] | 
					
						
							|  |  |  | 				if type(val) in typeclasses.MutableTypes: | 
					
						
							|  |  |  | 					val = copy.deepcopy( val ) | 
					
						
							|  |  |  | 				return val | 
					
						
							|  |  |  | 			elif self.fieldDictionary.has_key( key ): | 
					
						
							|  |  |  | 				'''We have the field, but we don't have a default, we are likely an EXTERNPROTO''' | 
					
						
							|  |  |  | 				return None | 
					
						
							|  |  |  | 		raise AttributeError, key | 
					
						
							|  |  |  | 	def setDefault (self, key, value): | 
					
						
							|  |  |  | 		'''Set the default value for the given field
 | 
					
						
							|  |  |  | 		key -- string name | 
					
						
							|  |  |  | 			The name of the field to set | 
					
						
							|  |  |  | 		value -- object defaultValue | 
					
						
							|  |  |  | 			The default value, will be checked for type and coerced if necessary | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		field = self.getField (key) | 
					
						
							|  |  |  | 		self.defaultDictionary [field.name]= field.coerce (value) | 
					
						
							|  |  |  | 	def clone( self, children = 1, sceneGraph = 1 ): | 
					
						
							|  |  |  | 		'''Return a copy of this Prototype
 | 
					
						
							|  |  |  | 		children -- boolean | 
					
						
							|  |  |  | 			if true, copy the children of the Prototype, otherwise include them | 
					
						
							|  |  |  | 		sceneGraph -- boolean | 
					
						
							|  |  |  | 			if true, copy the sceneGraph of the Prototype | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if sceneGraph: | 
					
						
							|  |  |  | 			sceneGraph = self.sceneGraph | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			sceneGraph = None | 
					
						
							|  |  |  | 		# defaults should always be copied before modification, but this is still dangerous... | 
					
						
							|  |  |  | 		defaultDictionary = self.defaultDictionary.copy() | 
					
						
							|  |  |  | 		if not children: | 
					
						
							|  |  |  | 			for attrname in self.SFNodeNames+self.MFNodeNames: | 
					
						
							|  |  |  | 				try: | 
					
						
							|  |  |  | 					del defaultDictionary[attrname] | 
					
						
							|  |  |  | 				except KeyError: # sceneGraph object is not copied... | 
					
						
							|  |  |  | 					pass | 
					
						
							|  |  |  | 		# now make a copy | 
					
						
							|  |  |  | 		if self.__gi__ == "PROTO": | 
					
						
							|  |  |  | 			newNode = self.__class__( | 
					
						
							|  |  |  | 				self.nodeGI, | 
					
						
							|  |  |  | 				self.fieldDictionary, | 
					
						
							|  |  |  | 				defaultDictionary, | 
					
						
							|  |  |  | 				self.eventDictionary, | 
					
						
							|  |  |  | 				sceneGraph, | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			newNode = self.__class__( | 
					
						
							|  |  |  | 				self.nodeGI, | 
					
						
							|  |  |  | 				self.url, | 
					
						
							|  |  |  | 				self.fieldDictionary, | 
					
						
							|  |  |  | 				self.eventDictionary, | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		return newNode | 
					
						
							|  |  |  | 	def __call__(self, *args, **namedargs): | 
					
						
							|  |  |  | 		'''Create a new Node instance associated with this Prototype
 | 
					
						
							|  |  |  | 		*args, **namedargs -- passed to the Node.__init__ | 
					
						
							|  |  |  | 		see class Node | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		node = apply( Node, (self, )+args, namedargs ) | 
					
						
							|  |  |  | 		return node | 
					
						
							|  |  |  | 	def __repr__ ( self ): | 
					
						
							|  |  |  | 		'''Create a simple Python representation''' | 
					
						
							|  |  |  | 		return '''%s( %s )'''%( self.__class__.__name__, self.nodeGI ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ExternalPrototype( Prototype ): | 
					
						
							|  |  |  | 	'''Sub-class of Prototype
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	The ExternalPrototype is a minor sub-classing of the Prototype | 
					
						
							|  |  |  | 	it does not have any defaults, nor a sceneGraph | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Attributes: | 
					
						
							|  |  |  | 		__gi__ -- constant string "EXTERNPROTO" | 
					
						
							|  |  |  | 		url -- string list urls | 
					
						
							|  |  |  | 			implementation source for the ExternalPrototype | 
					
						
							|  |  |  | 	'''
 | 
					
						
							|  |  |  | 	__gi__ = "EXTERNPROTO" | 
					
						
							|  |  |  | 	def __init__(self, gi, url=None, fieldDict=None, eventDict=None): | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		gi -- string gi | 
					
						
							|  |  |  | 			see attribute nodeGI | 
					
						
							|  |  |  | 		url -- string list url | 
					
						
							|  |  |  | 			MFString-compatible list of url's for EXTERNPROTO | 
					
						
							|  |  |  | 		fieldDict -- string name: (string name, string dataType, boolean exposed) | 
					
						
							|  |  |  | 			see attribute fieldDictionary | 
					
						
							|  |  |  | 		eventDict -- string name: (string name, string dataType, boolean eventOut) | 
					
						
							|  |  |  | 			see attribute eventDictionary | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if url is None: | 
					
						
							|  |  |  | 			url = [] | 
					
						
							|  |  |  | 		self.url = url | 
					
						
							|  |  |  | 		Prototype.__init__( self, gi, fieldDict=fieldDict, eventDict=eventDict) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from vrml import fieldcoercian # XXX | 
					
						
							|  |  |  | class Field: | 
					
						
							|  |  |  | 	''' Representation of a Prototype Field
 | 
					
						
							|  |  |  | 	The Field object is a simple wrapper to provide convenient | 
					
						
							|  |  |  | 	access to field coercian and meta- information | 
					
						
							|  |  |  | 	'''
 | 
					
						
							|  |  |  | 	def __init__( self, specification, default=None ): | 
					
						
							|  |  |  | 		self.name, self.type, self.exposure = specification | 
					
						
							|  |  |  | 		self.default = default | 
					
						
							|  |  |  | 	def getDefinition (self): | 
					
						
							|  |  |  | 		return self.name, self.type, self.exposure | 
					
						
							|  |  |  | 	def getDefault (self): | 
					
						
							|  |  |  | 		return self.default | 
					
						
							|  |  |  | 	def coerce( self, value ): | 
					
						
							|  |  |  | 		''' Coerce value to the appropriate dataType for this Field ''' | 
					
						
							|  |  |  | 		return fieldcoercian.FieldCoercian()( value,self.type,  ) | 
					
						
							|  |  |  | 	def __repr__( self ): | 
					
						
							|  |  |  | 		if hasattr (self, "default"): | 
					
						
							|  |  |  | 			return '%s( (%s,%s,%s), %s)'%( self.__class__.__name__, self.name, self.type, self.exposure, self.default) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			return '%s( (%s,%s,%s),)'%( self.__class__.__name__, self.name, self.type, self.exposure) | 
					
						
							|  |  |  | 	def __str__( self ): | 
					
						
							|  |  |  | 		if self.exposure: | 
					
						
							|  |  |  | 			exposed = "exposedField" | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			exposed = field | 
					
						
							|  |  |  | 		if hasattr (self, "default"): | 
					
						
							|  |  |  | 			default = ' ' + str( self.default) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			default = "" | 
					
						
							|  |  |  | 		return '%s %s %s%s'%(exposed, self.type, self.name, default) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Event (Field): | 
					
						
							|  |  |  | 	def __str__( self ): | 
					
						
							|  |  |  | 		if self.exposure: | 
					
						
							|  |  |  | 			exposed = "eventOut" | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			exposed = "eventIn" | 
					
						
							|  |  |  | 		return '%s %s %s'%(exposed, self.type, self.name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Translation strings for VRML node names... | 
					
						
							|  |  |  | translationstring = '''][0123456789{}"'#,.\\ \000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023''' | 
					
						
							|  |  |  | NAMEFIRSTCHARTRANSLATOR = string.maketrans( translationstring, '_'*len(translationstring) ) | 
					
						
							|  |  |  | translationstring = '''][{}"'#,.\\ \000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023''' | 
					
						
							|  |  |  | NAMERESTCHARTRANSLATOR = string.maketrans( translationstring, '_'*len(translationstring) ) | 
					
						
							|  |  |  | del translationstring | 
					
						
							|  |  |  | def checkName( name ): | 
					
						
							|  |  |  | 	'''Convert arbitrary string to a valid VRML id''' | 
					
						
							|  |  |  | 	if type(name) is types.StringType: | 
					
						
							|  |  |  | 		if not name: | 
					
						
							|  |  |  | 			return name | 
					
						
							|  |  |  | 		return string.translate( name[:1], NAMEFIRSTCHARTRANSLATOR) + string.translate( name[1:], NAMERESTCHARTRANSLATOR) | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		raise TypeError, "VRML Node Name must be a string, was a %s: %s"%(type(name), name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Node(baseProto): | 
					
						
							|  |  |  | 	''' A VRML 97 Node object
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	A Node object represents a VRML 97 node.  Attributes of the Node | 
					
						
							|  |  |  | 	can be set/retrieved with standard python setattr/getattr syntax. | 
					
						
							|  |  |  | 	VRML 97 attributes may be passed to the constructor as named | 
					
						
							|  |  |  | 	arguments. | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	Attributes: | 
					
						
							|  |  |  | 		__gi__ -- string PROTOname | 
					
						
							|  |  |  | 		DEF -- string DEFName | 
					
						
							|  |  |  | 			The DEF name of the node, will be coerced to be a valid | 
					
						
							|  |  |  | 			identifier (with "" being considered valid) | 
					
						
							|  |  |  | 		PROTO -- Prototype PROTO | 
					
						
							|  |  |  | 			The node's Prototype object | 
					
						
							|  |  |  | 		attributeDictionary -- string name: object value | 
					
						
							|  |  |  | 			Dictionary in which VRML 97 attributes are stored | 
					
						
							|  |  |  | 	'''
 | 
					
						
							|  |  |  | 	DEF = '' # the default name for all nodes (arbitrary) | 
					
						
							|  |  |  | 	def __init__(self, PROTO, name='', attrDict=None, *args, **namedargs): | 
					
						
							|  |  |  | 		'''Normally this method is only called indirectly via the Prototype() interface
 | 
					
						
							|  |  |  | 		PROTO -- Prototype PROTO | 
					
						
							|  |  |  | 			see attribute PROTO | 
					
						
							|  |  |  | 		name -- string DEFName | 
					
						
							|  |  |  | 			see attribute DEF | 
					
						
							|  |  |  | 		attrDict -- string name: object value | 
					
						
							|  |  |  | 			see attribute attributeDictionary | 
					
						
							|  |  |  | 		**namedargs -- string name: object value | 
					
						
							|  |  |  | 			added to attrDict to create attributeDictionary | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		self.__dict__["PROTO"] = PROTO | 
					
						
							|  |  |  | 		self.DEF = name | 
					
						
							|  |  |  | 		self.__dict__["attributeDictionary"] = {} | 
					
						
							|  |  |  | ##		print attrDict, namedargs | 
					
						
							|  |  |  | 		for dict in (attrDict or {}), namedargs: | 
					
						
							|  |  |  | 			if dict: | 
					
						
							|  |  |  | 				for key, value in dict.items (): | 
					
						
							|  |  |  | 					self.__setattr__( key, value, check=1 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	def __setattr__( self, key, value, check=1, raw=0 ): | 
					
						
							|  |  |  | 		'''Set attribute on Node
 | 
					
						
							|  |  |  | 		key -- string attributeName | 
					
						
							|  |  |  | 		value -- object attributeValue | 
					
						
							|  |  |  | 		check -- boolean check | 
					
						
							|  |  |  | 			if false, put values for unrecognized keys into __dict__ | 
					
						
							|  |  |  | 			otherwise, raise an  AttributeError | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if key == "DEF": | 
					
						
							|  |  |  | 			self.__dict__["DEF"] = checkName( value ) | 
					
						
							|  |  |  | 			return None | 
					
						
							|  |  |  | 		elif key == "PROTO": | 
					
						
							|  |  |  | 			self.__dict__["PROTO"] = value | 
					
						
							|  |  |  | 		try: | 
					
						
							|  |  |  | 			field = self.PROTO.getField( key ) | 
					
						
							|  |  |  | 			if (hasattr( value, "__gi__") and value.__gi__ == "IS") or raw: | 
					
						
							|  |  |  | 				self.attributeDictionary[ field.name] = value | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				self.attributeDictionary[ field.name] = field.coerce( value ) | 
					
						
							|  |  |  | 		except ValueError, x: | 
					
						
							|  |  |  | 			raise ValueError( "Could not coerce value %s into value of VRML type %s for %s node %s's field %s"%( value, field.type, self.__gi__, self.DEF, key), x.args) | 
					
						
							|  |  |  | 		except (AttributeError), x: | 
					
						
							|  |  |  | 			if check: | 
					
						
							|  |  |  | 				raise AttributeError("%s is not a known field for node %s"%(key, repr(self))) | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				self.__dict__[key] = value | 
					
						
							|  |  |  | 	def __getattr__( self, key, default = 1 ): | 
					
						
							|  |  |  | 		''' Retrieve an attribute when standard lookup fails
 | 
					
						
							|  |  |  | 		key -- string attributeName | 
					
						
							|  |  |  | 		default -- boolean default | 
					
						
							|  |  |  | 			if true, return the default value if the node does not have local value | 
					
						
							|  |  |  | 			otherwise, raise AttributeError | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if key != "attributeDictionary": | 
					
						
							|  |  |  | 			if self.__dict__.has_key( key): | 
					
						
							|  |  |  | 				return self.__dict__[ key ] | 
					
						
							|  |  |  | 			elif self.attributeDictionary.has_key( key): | 
					
						
							|  |  |  | 				return self.attributeDictionary[key] | 
					
						
							|  |  |  | 			if key != "PROTO": | 
					
						
							|  |  |  | 				if key == "__gi__": | 
					
						
							|  |  |  | 					return self.PROTO.nodeGI | 
					
						
							|  |  |  | 				elif default: | 
					
						
							|  |  |  | 					try: | 
					
						
							|  |  |  | 						default = self.PROTO.getDefault( key ) | 
					
						
							|  |  |  | 						if type( default ) in typeclasses.MutableTypes: | 
					
						
							|  |  |  | 							# we need a copy, not the original | 
					
						
							|  |  |  | 							default = copy.deepcopy( default ) | 
					
						
							|  |  |  | 							self.__setattr__( key, default, check=0, raw=1 ) | 
					
						
							|  |  |  | 						return default | 
					
						
							|  |  |  | 					except AttributeError: | 
					
						
							|  |  |  | 						pass | 
					
						
							|  |  |  | 		raise AttributeError, key | 
					
						
							|  |  |  | 	def __delattr__( self, key ): | 
					
						
							|  |  |  | 		''' Delete an attribute from the Node
 | 
					
						
							|  |  |  | 		key -- string attributeName | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if key != "attributeDictionary": | 
					
						
							|  |  |  | 			if self.attributeDictionary.has_key( key): | 
					
						
							|  |  |  | 				del self.attributeDictionary[key] | 
					
						
							|  |  |  | 			elif self.__dict__.has_key( key): | 
					
						
							|  |  |  | 				del self.__dict__[ key ] | 
					
						
							|  |  |  | 		raise AttributeError, key | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 	def __repr__(self): | 
					
						
							|  |  |  | 		''' Create simple python representation ''' | 
					
						
							|  |  |  | 		return '<%s(%s): %s>'%(self.__gi__, `self.DEF`, self.attributeDictionary.keys() ) | 
					
						
							|  |  |  | 	def getChildrenNames( self, current = 1, *args, **namedargs ): | 
					
						
							|  |  |  | 		''' Get the (current) children of Node
 | 
					
						
							|  |  |  | 		returns two lists:  MFNode children, SFNode children | 
					
						
							|  |  |  | 		current -- boolean currentOnly | 
					
						
							|  |  |  | 			if true, only return current children | 
					
						
							|  |  |  | 			otherwise, include all potential children | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		MFNODES, SFNODES = self.PROTO.MFNodeNames, self.PROTO.SFNodeNames | 
					
						
							|  |  |  | 		mns, sns = [],[] | 
					
						
							|  |  |  | 		for key in MFNODES: | 
					
						
							|  |  |  | 			if current and self.attributeDictionary.has_key(key): | 
					
						
							|  |  |  | 				mns.append(key) | 
					
						
							|  |  |  | 			elif not current: | 
					
						
							|  |  |  | 				mns.append(key) | 
					
						
							|  |  |  | 		for key in SFNODES: | 
					
						
							|  |  |  | 			if self.attributeDictionary.has_key(key): | 
					
						
							|  |  |  | 				sns.append(key) | 
					
						
							|  |  |  | 			elif not current: | 
					
						
							|  |  |  | 				sns.append(key) | 
					
						
							|  |  |  | 		return mns,sns | 
					
						
							|  |  |  | 	def calculateChildren(self, *args, **namedargs): | 
					
						
							|  |  |  | 		'''Calculate the current children of the Node as list of Nodes
 | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		MFNODES, SFNODES = self.getChildrenNames( ) | 
					
						
							|  |  |  | 		temp = [] | 
					
						
							|  |  |  | 		for key in MFNODES: | 
					
						
							|  |  |  | 			try: | 
					
						
							|  |  |  | 				temp.extend( self.__getattr__( key, default=0 ) ) | 
					
						
							|  |  |  | 			except AttributeError: | 
					
						
							|  |  |  | 				pass | 
					
						
							|  |  |  | 		for key in SFNODES: | 
					
						
							|  |  |  | 			try: | 
					
						
							|  |  |  | 				temp.append( self.__getattr__(key, default = 0 ) ) | 
					
						
							|  |  |  | 			except AttributeError: | 
					
						
							|  |  |  | 				pass | 
					
						
							|  |  |  | 		return temp | 
					
						
							|  |  |  | 	def clone(self, newclass=None, name=None, children=None, attrDeepCopy=1, *args, **namedargs): | 
					
						
							|  |  |  | 		'''Return a copy of this Node
 | 
					
						
							|  |  |  | 		newclass -- object newClass  or None | 
					
						
							|  |  |  | 			optionally use a different Prototype as base | 
					
						
							|  |  |  | 		name -- string DEFName or None or 1 | 
					
						
							|  |  |  | 			if 1, copy from current | 
					
						
							|  |  |  | 			elif None, set to "" | 
					
						
							|  |  |  | 			else, set to passed value | 
					
						
							|  |  |  | 		children -- boolean copyChildren | 
					
						
							|  |  |  | 			if true, copy the children of this node | 
					
						
							|  |  |  | 			otherwise, skip children | 
					
						
							|  |  |  | 		attrDeepCopy -- boolean deepCopy | 
					
						
							|  |  |  | 			if true, use deepcopy | 
					
						
							|  |  |  | 			otherwise, use copy | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if attrDeepCopy: | 
					
						
							|  |  |  | 			cpy = copy.deepcopy | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			cpy = copy.copy | 
					
						
							|  |  |  | 		newattrs = self.attributeDictionary.copy() | 
					
						
							|  |  |  | 		if not children: | 
					
						
							|  |  |  | 			mnames,snames = self.getChildrenNames( ) | 
					
						
							|  |  |  | 			for key in mnames+snames: | 
					
						
							|  |  |  | 				try: | 
					
						
							|  |  |  | 					del(newattrs[key]) | 
					
						
							|  |  |  | 				except KeyError: | 
					
						
							|  |  |  | 					pass | 
					
						
							|  |  |  | 		for key, val in newattrs.items(): | 
					
						
							|  |  |  | 			if type(val) in typeclasses.MutableTypes: | 
					
						
							|  |  |  | 				newattrs[key] = cpy(val) | 
					
						
							|  |  |  | 		# following is Node specific, won't work for sceneGraphs, scripts, etceteras | 
					
						
							|  |  |  | 		if name == 1: # asked to copy the name | 
					
						
							|  |  |  | 			name = self.DEF | 
					
						
							|  |  |  | 		elif name is None: # asked to clear the name | 
					
						
							|  |  |  | 			name = '' | 
					
						
							|  |  |  | 		if not newclass: | 
					
						
							|  |  |  | 			newclass = self.PROTO | 
					
						
							|  |  |  | 		return newclass( name, newattrs ) | 
					
						
							|  |  |  | 	def __cmp__( self, other, stop=None ): | 
					
						
							|  |  |  | 		''' Compare this node to another object/node
 | 
					
						
							|  |  |  | 		other -- object otherNode | 
					
						
							|  |  |  | 		stop -- boolean stopIfFailure | 
					
						
							|  |  |  | 			if true, failure to find comparison causes match failure (i.e. considered unequal) | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 		if hasattr( other, '__gi__') and other.__gi__ == self.__gi__: | 
					
						
							|  |  |  | 			try: | 
					
						
							|  |  |  | 				return cmp( self.DEF, other.DEF) or cmp( self.attributeDictionary, other.attributeDictionary ) | 
					
						
							|  |  |  | 			except: | 
					
						
							|  |  |  | 				if not stop: | 
					
						
							|  |  |  | 					try: | 
					
						
							|  |  |  | 						return other.__cmp__( self , 1) # 1 being stop... | 
					
						
							|  |  |  | 					except: | 
					
						
							|  |  |  | 						pass | 
					
						
							|  |  |  | 		return -1 # could be one, doesn't really matter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def Script( name="", attrDict=None, fieldDict=None, defaultDict=None, eventDict=None, **namedarguments): | 
					
						
							|  |  |  | 	''' Create a script node (and associated prototype)
 | 
					
						
							|  |  |  | 	name -- string DEFName | 
					
						
							|  |  |  | 	attrDict -- string name: object value | 
					
						
							|  |  |  | 		see class Node.attributeDictionary | 
					
						
							|  |  |  | 	fieldDict -- string name: (string name, string dataType,  boolean exposure) | 
					
						
							|  |  |  | 		see class Prototype.fieldDictionary | 
					
						
							|  |  |  | 	defaultDict -- string name: object value | 
					
						
							|  |  |  | 		see class Prototype.defaultDictionary | 
					
						
							|  |  |  | 	eventDict -- string name: (string name, string dataType, boolean eventOut) | 
					
						
							|  |  |  | 	'''
 | 
					
						
							|  |  |  | 	fieldDictionary = { | 
					
						
							|  |  |  | 		'directOutput':('directOutput', 'SFBool',0), | 
					
						
							|  |  |  | 		'url':('url',"MFString",0), | 
					
						
							|  |  |  | 		'mustEvaluate':('mustEvaluate', 'SFBool',0), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fieldDictionary.update( fieldDict or {}) | 
					
						
							|  |  |  | 	defaultDictionary = { | 
					
						
							|  |  |  | 		"directOutput":0, | 
					
						
							|  |  |  | 		"url":[], | 
					
						
							|  |  |  | 		"mustEvaluate":0, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defaultDictionary.update( defaultDict or {}) | 
					
						
							|  |  |  | 	PROTO = Prototype( | 
					
						
							|  |  |  | 		"Script", | 
					
						
							|  |  |  | 		fieldDictionary, | 
					
						
							|  |  |  | 		defaultDictionary , | 
					
						
							|  |  |  | 		eventDict = eventDict, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if attrDict is not None: | 
					
						
							|  |  |  | 		attrDict.update( namedarguments ) | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		attrDict = namedarguments | 
					
						
							|  |  |  | 	return PROTO( name, attrDict ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class NullNode: | 
					
						
							|  |  |  | 	'''NULL SFNode value
 | 
					
						
							|  |  |  | 	There should only be a single NULL instance for | 
					
						
							|  |  |  | 	any particular system.  It should, for all intents and | 
					
						
							|  |  |  | 	purposes just sit there inertly | 
					
						
							|  |  |  | 	'''
 | 
					
						
							|  |  |  | 	__gi__ = 'NULL' | 
					
						
							|  |  |  | 	DEF = '' | 
					
						
							|  |  |  | 	__walker_is_temporary_item__ = 1 # hacky signal to walking engine not to reject this node as already processed | 
					
						
							|  |  |  | 	def __repr__(self): | 
					
						
							|  |  |  | 		return '<NULL vrml SFNode>' | 
					
						
							|  |  |  | 	def __vrmlStr__(self,*args,**namedargs): | 
					
						
							|  |  |  | 		return ' NULL ' | 
					
						
							|  |  |  | 	toString = __vrmlStr__ | 
					
						
							|  |  |  | 	def __nonzero__(self ): | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	def __call__(self, *args, **namedargs): | 
					
						
							|  |  |  | 		return self | 
					
						
							|  |  |  | 	def __cmp__( self, other ): | 
					
						
							|  |  |  | 		if hasattr( other, '__gi__') and other.__gi__ == self.__gi__: | 
					
						
							|  |  |  | 			return 0 | 
					
						
							|  |  |  | 		return -1 # could be one, doesn't really matter | 
					
						
							|  |  |  | 	def clone( self ): | 
					
						
							|  |  |  | 		return self | 
					
						
							|  |  |  | NULL = NullNode() | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | class fieldRef: | 
					
						
							|  |  |  | 	'''IS Prototype field reference
 | 
					
						
							|  |  |  | 	'''
 | 
					
						
							|  |  |  | 	__gi__ = 'IS' | 
					
						
							|  |  |  | 	DEF = '' | 
					
						
							|  |  |  | 	def __init__(self, declaredName): | 
					
						
							|  |  |  | 		self.declaredName = declaredName | 
					
						
							|  |  |  | 	def __repr__(self): | 
					
						
							|  |  |  | 		return 'IS %s'%self.declaredName | 
					
						
							|  |  |  | 	def __vrmlStr__(self,*args,**namedargs): | 
					
						
							|  |  |  | 		return 'IS %s'%self.declaredName | 
					
						
							|  |  |  | 	toString = __vrmlStr__ | 
					
						
							|  |  |  | 	def __cmp__( self, other ): | 
					
						
							|  |  |  | 		if hasattr( other, '__gi__') and other.__gi__ == self.__gi__: | 
					
						
							|  |  |  | 			return cmp( self.declaredName, other.declaredName ) | 
					
						
							|  |  |  | 		return -1 # could be one, doesn't really matter | 
					
						
							|  |  |  | 	def clone( self ): | 
					
						
							|  |  |  | 		return self.__class__( self.declaredName ) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | IS = fieldRef | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ROUTE: | 
					
						
							|  |  |  | 	''' VRML 97 ROUTE object
 | 
					
						
							|  |  |  | 	The ROUTE object keeps track of its source and destination nodes and attributes | 
					
						
							|  |  |  | 	It generally lives in a sceneGraph's "routes" collection | 
					
						
							|  |  |  | 	'''
 | 
					
						
							|  |  |  | 	__gi__ = 'ROUTE' | 
					
						
							|  |  |  | 	def __init__( self, fromNode, fromField, toNode, toField ): | 
					
						
							|  |  |  | 		if type(fromNode) is types.StringType: | 
					
						
							|  |  |  | 			raise TypeError( "String value for ROUTE fromNode",fromNode) | 
					
						
							|  |  |  | 		if type(toNode) is types.StringType: | 
					
						
							|  |  |  | 			raise TypeError( "String value for ROUTE toNode",toNode) | 
					
						
							|  |  |  | 		self.fromNode = fromNode | 
					
						
							|  |  |  | 		self.fromField = fromField | 
					
						
							|  |  |  | 		self.toNode = toNode | 
					
						
							|  |  |  | 		self.toField = toField | 
					
						
							|  |  |  | 	def __getitem__( self, index ): | 
					
						
							|  |  |  | 		return (self.fromNode, self.fromField, self.toNode, self.toField)[index] | 
					
						
							|  |  |  | 	def __setitem__( self, index, value ): | 
					
						
							|  |  |  | 		attribute = ("fromNode","fromField","toNode", "toField")[index] | 
					
						
							|  |  |  | 		setattr( self, attribute, value ) | 
					
						
							|  |  |  | 	def __repr__( self ): | 
					
						
							|  |  |  | 		return 'ROUTE %s.%s TO %s.%s'%( self.fromNode.DEF, self.fromField, self.toNode.DEF, self.toField ) | 
					
						
							|  |  |  | 	def clone( self ): | 
					
						
							|  |  |  | 		return self.__class__(  | 
					
						
							|  |  |  | 			self.fromNode, | 
					
						
							|  |  |  | 			self.fromField, | 
					
						
							|  |  |  | 			self.toNode, | 
					
						
							|  |  |  | 			self.toField, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class sceneGraph(baseProto): | 
					
						
							|  |  |  | 	''' A VRML 97 sceneGraph
 | 
					
						
							|  |  |  | 	Attributes: | 
					
						
							|  |  |  | 		__gi__ -- constant string "sceneGraph" | 
					
						
							|  |  |  | 		DEF -- constant string "" | 
					
						
							|  |  |  | 		children -- Node list | 
					
						
							|  |  |  | 			List of the root children of the sceneGraph, nodes/scripts only | 
					
						
							|  |  |  | 		routes -- ROUTE list | 
					
						
							|  |  |  | 			List of the routes within the sceneGraph | 
					
						
							|  |  |  | 		defNames -- string DEFName: Node node | 
					
						
							|  |  |  | 			Mapping of DEF names to their respective nodes | 
					
						
							|  |  |  | 		protoTypes -- Namespace prototypes | 
					
						
							|  |  |  | 			Namespace (with chaining lookup) collection of prototypes | 
					
						
							|  |  |  | 			getattr( sceneGraph.protoTypes, 'nodeGI' ) retrieves a prototype | 
					
						
							|  |  |  | 	'''
 | 
					
						
							|  |  |  | 	__gi__ = 'sceneGraph' | 
					
						
							|  |  |  | 	DEF = '' | 
					
						
							|  |  |  | 	def __init__(self, root=None, protoTypes=None, routes=None, defNames=None, children=None, *args, **namedargs): | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		root -- sceneGraph root or Dictionary root or Module root or None | 
					
						
							|  |  |  | 			Base object for root of protoType namespace hierarchy | 
					
						
							|  |  |  | 		protoTypes -- string nodeGI: Prototype PROTO | 
					
						
							|  |  |  | 			Dictionary of prototype definitions | 
					
						
							|  |  |  | 		routes -- ROUTE list or (string sourcenode, string sourceeventOut, string destinationnode, string destinationeventOut) list | 
					
						
							|  |  |  | 			List of route objects or tuples to be added to the sceneGraph | 
					
						
							|  |  |  | 			see attribute routes | 
					
						
							|  |  |  | 		defNames -- string DEFName: Node node | 
					
						
							|  |  |  | 			see attribute defNames | 
					
						
							|  |  |  | 		children -- Node list | 
					
						
							|  |  |  | 			see attribute children | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		if children is None: | 
					
						
							|  |  |  | 			self.children = [] | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			self.children = children | 
					
						
							|  |  |  | 		if routes is None: | 
					
						
							|  |  |  | 			self.routes = [] # how will we efficiently handle routes? | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			self.routes = routes | 
					
						
							|  |  |  | 		if defNames == None: | 
					
						
							|  |  |  | 			self.defNames = {} # maps 'defName':Node | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			self.defNames = defNames | 
					
						
							|  |  |  | 		if protoTypes is None: | 
					
						
							|  |  |  | 			protoTypes = {} | 
					
						
							|  |  |  | 		if root is None: | 
					
						
							|  |  |  | 			from vrml import basenodes # XXX | 
					
						
							|  |  |  | 			self.protoTypes = namespace.NameSpace( | 
					
						
							|  |  |  | 				protoTypes, | 
					
						
							|  |  |  | 				children = [namespace.NameSpace(basenodes)] | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		else: # there is a root file, so need to use it as the children instead of basenodes... | 
					
						
							|  |  |  | 			if hasattr( root, "protoTypes"): | 
					
						
							|  |  |  | 				self.protoTypes = namespace.NameSpace( | 
					
						
							|  |  |  | 					protoTypes, | 
					
						
							|  |  |  | 					children = [root.protoTypes] | 
					
						
							|  |  |  | 				) | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				self.protoTypes = namespace.NameSpace( | 
					
						
							|  |  |  | 					protoTypes, | 
					
						
							|  |  |  | 					children = [ namespace.NameSpace(root) ] | 
					
						
							|  |  |  | 				) | 
					
						
							|  |  |  | 	def __getinitargs__( self ): | 
					
						
							|  |  |  | 		# we only copy our explicit protos, our routes, our defNames, and our children | 
					
						
							|  |  |  | 		# inherited protos will be pulled along by their nodes... | 
					
						
							|  |  |  | 		return None, self.protoTypes._base, self.routes, self.defNames, self.children | 
					
						
							|  |  |  | 	def __getstate__( self ): | 
					
						
							|  |  |  | 		return {} | 
					
						
							|  |  |  | 	def __setstate__( self, dict ): | 
					
						
							|  |  |  | 		pass | 
					
						
							|  |  |  | 	def __del__( self, id=id ): | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		Need to clean up the namespace's mutual references, | 
					
						
							|  |  |  | 		this can be done without affecting the cascade by just | 
					
						
							|  |  |  | 		eliminating the key/value pairs.  The namespaces will | 
					
						
							|  |  |  | 		no longer contain the prototypes, but they will still | 
					
						
							|  |  |  | 		chain up to the higher-level namespaces, and the nodes | 
					
						
							|  |  |  | 		will have those prototypes still in use. | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | ##		print 'del sceneGraph', id(self ) | 
					
						
							|  |  |  | 		try: | 
					
						
							|  |  |  | ##			import pdb | 
					
						
							|  |  |  | ##			pdb.set_trace() | 
					
						
							|  |  |  | ##			self.protoTypes.__dict__.clear() | 
					
						
							|  |  |  | 			self.protoTypes._base.clear() | 
					
						
							|  |  |  | 			del self.protoTypes.__namespace_cascade__[:] | 
					
						
							|  |  |  | 		except: | 
					
						
							|  |  |  | 			print 'unable to free references' | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	def addRoute(self, routeTuple, getNewNodes=0): | 
					
						
							|  |  |  | 		''' Add a single route to the sceneGraph
 | 
					
						
							|  |  |  | 		routeTuple -- ROUTE route or (string sourcenode, string sourceeventOut, string destinationnode, string destinationeventOut) | 
					
						
							|  |  |  | 		getNewNodes -- boolean getNewNodes | 
					
						
							|  |  |  | 			if true, look up sourcenode and destinationnode within the current defNames to determine source/destination nodes | 
					
						
							|  |  |  | 			otherwise, just use current if available | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		# create and wire together the Routes here, | 
					
						
							|  |  |  | 		# should just be a matter of pulling the events and passing the nodes... | 
					
						
							|  |  |  | ##		import pdb | 
					
						
							|  |  |  | ##		pdb.set_trace() | 
					
						
							|  |  |  | 		if type( routeTuple) in ( types.TupleType, types.ListType): | 
					
						
							|  |  |  | 			(fromNode, fromField, toNode, toField ) = routeTuple | 
					
						
							|  |  |  | 			if type(fromNode) is types.StringType: | 
					
						
							|  |  |  | 				# get the node instead of the string... | 
					
						
							|  |  |  | 				if self.defNames.has_key( fromNode ): | 
					
						
							|  |  |  | 					fromNode = self.defNames[fromNode] | 
					
						
							|  |  |  | 				else: | 
					
						
							|  |  |  | 					err.err( "ROUTE from an unknown node %s "%(routeTuple) ) | 
					
						
							|  |  |  | 					return 0 | 
					
						
							|  |  |  | 			if type(toNode) is types.StringType: | 
					
						
							|  |  |  | 				# get the node instead of the string... | 
					
						
							|  |  |  | 				if self.defNames.has_key( toNode ): | 
					
						
							|  |  |  | 					toNode = self.defNames[toNode] | 
					
						
							|  |  |  | 				else: | 
					
						
							|  |  |  | 					err.err( "ROUTE to an unknown node %s "%(routeTuple) ) | 
					
						
							|  |  |  | 					return 0 | 
					
						
							|  |  |  | 			routeTuple = ROUTE( fromNode, fromField, toNode, toField) | 
					
						
							|  |  |  | 		elif getNewNodes: | 
					
						
							|  |  |  | 			# get the nodes with the same names... | 
					
						
							|  |  |  | 			if self.defNames.has_key( routeTuple[0].DEF ): | 
					
						
							|  |  |  | 				routeTuple[0] = self.defNames[routeTuple[0].DEF] | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				err.err( "ROUTE from an unknown node %s "%(routeTuple) ) | 
					
						
							|  |  |  | 				return 0 | 
					
						
							|  |  |  | 			if self.defNames.has_key( routeTuple[2].DEF ): | 
					
						
							|  |  |  | 				routeTuple[2] = self.defNames[routeTuple[2].DEF] | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				err.err( "ROUTE to an unknown node %s "%(routeTuple) ) | 
					
						
							|  |  |  | 				return 0 | 
					
						
							|  |  |  | 		# should be a Route node now, append to our ROUTE list... | 
					
						
							|  |  |  | 		self.routes.append(routeTuple) | 
					
						
							|  |  |  | 		return 1 | 
					
						
							|  |  |  | 	def regDefName(self, defName, object): | 
					
						
							|  |  |  | 		''' Register a DEF name for a particular object
 | 
					
						
							|  |  |  | 		defName -- string DEFName | 
					
						
							|  |  |  | 		object -- Node node | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		object.DEF = defName | 
					
						
							|  |  |  | 		self.defNames[defName] = object | 
					
						
							|  |  |  | 	def addProto(self, proto): | 
					
						
							|  |  |  | 		'''Register a Prototype for this sceneGraph
 | 
					
						
							|  |  |  | 		proto -- Prototype PROTO | 
					
						
							|  |  |  | 		'''
 | 
					
						
							|  |  |  | 		setattr( self.protoTypes, proto.__gi__, proto ) | 
					
						
							|  |  |  | 	#toString = __vrmlStr__  | 
					
						
							|  |  |  | 	#__vrmlStr__ = toString | 
					
						
							|  |  |  | ##	def __setattr__( self, key, value ): | 
					
						
							|  |  |  | ##		if key == 'protoTypes' and type( value) is types.ListType: | 
					
						
							|  |  |  | ##			import pdb | 
					
						
							|  |  |  | ##			pdb.set_trace() | 
					
						
							|  |  |  | ##			raise TypeError( "Invalid type for protoTypes attribute of sceneGraph %s"%(`value`) ) | 
					
						
							|  |  |  | ##		else: | 
					
						
							|  |  |  | ##			self.__dict__[key] = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEFAULTFIELDVALUES ={ | 
					
						
							|  |  |  | 	"SFBool": 0, | 
					
						
							|  |  |  | 	"SFString": "", | 
					
						
							|  |  |  | 	"SFFloat": 0, | 
					
						
							|  |  |  | 	"SFTime": 0, | 
					
						
							|  |  |  | 	"SFVec3f": (0, 0,0), | 
					
						
							|  |  |  | 	"SFVec2f": (0,0), | 
					
						
							|  |  |  | 	"SFRotation": (0, 1,0, 0), | 
					
						
							|  |  |  | 	"SFInt32": 0, | 
					
						
							|  |  |  | 	"SFImage": (0,0,0), | 
					
						
							|  |  |  | 	"SFColor": (0,0, 0), | 
					
						
							|  |  |  | 	"SFNode": NULL, | 
					
						
							|  |  |  | 	"MFString": [], | 
					
						
							|  |  |  | 	"MFFloat": [], | 
					
						
							|  |  |  | 	"MFTime": [], | 
					
						
							|  |  |  | 	"MFVec3f": [], | 
					
						
							|  |  |  | 	"MFVec2f": [], | 
					
						
							|  |  |  | 	"MFRotation": [], | 
					
						
							|  |  |  | 	"MFInt32": [], | 
					
						
							|  |  |  | 	"MFColor": [], | 
					
						
							|  |  |  | 	"MFNode": [], | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 |