Example #1
0
	def __init__(self, wave, id, options):
		"""
		Called on instantiation. Documented for internal purposes.
		@constructor {private} initialize
		@param {WaveModel} wave Parent WaveModel object
		@param {String} id Wavelet ID
		@param {Object} options Information about the Wavelet. Possible values:
		@... {Participant} creator Creator of this Wavelet
		@... {Boolean} is_root True if this is the root Wavelet; if this value
		     is set and the parent WaveModel does not have a root Wavelet yet,
		     this Wavelet is set as the Wave's root Wavelet
		@... {Date} created Date of creation
		@... {Date} last_modified Date of last modification
		@... {String} title Title of the Wavelet
		@... {int} version Version of the Wavelet
		@... {String} status Status of the Wavelet; can be 'clean', 'dirty' or 'invalid'
		"""
		self.setOptions(options)
		self._wave = wave
		if self.options["is_root"]:
			if self._wave.rootWavelet() == None:
				self._wave._setRootWavelet(self)
			else:
				self.options["is_root"] = False
		self._id = id
		self._participants = Hash()
		self._blips = []
		self._rootBlip = None
Example #2
0
	def __init__(self, waveId, viewerId):
		"""
		Called on instantiation.
		@constructor {public} initialize
		@param {String} waveId ID of the Wave
		@param {String} viewerId ID of the viewer
		"""
		self._rootWavelet = None
		self._waveId = waveId
		self._viewerId = viewerId
		self._wavelets = Hash()
Example #3
0
	def __init__(self, waveId, viewerId, participantProvider):
		"""
		Called on instantiation.
		@constructor {public} initialize
		@param {String} waveId ID of the Wave
		@param {String} viewerId ID of the viewer
		@param {Object} participantProvider A ParticipantProvider object.
			it must have a method "participant(id)" to get Participant objects.
		"""
		self._rootWavelet = None
		self._waveId = waveId
		self._viewerId = viewerId
		self._wavelets = Hash()
		self._pp = participantProvider
Example #4
0
	def loadBlipsFromSnapshot(self, blips, rootBlipId):
		"""
		Load the blips from a snapshot.
		@function {public} loadBlipsFromSnapshot
		@param {Object} blips The JSON-serialized snapshot to load
		@param {String} rootBlipId ID to identify the root Blip
		"""
		
		pp = self._wave.participantProvider()
		
		# Ordering
		created = Hash()
		for blip_id, blip in blips.iteritems():
			created.set(blip["creationTime"], blip_id)
		order = created.getKeys()
		order.sort()
		
		for timestamp in order:
			blip_id = created[timestamp]
			blip = blips[blip_id]
			contributors = Array()
			for cid in blip["contributors"]:
				contributors.append(pp.participant(cid))
			blip_options = {
				"is_root": blip_id == rootBlipId,
				"last_modified": blip["lastModifiedTime"],
				"version": blip["version"],
				"submitted": blip["submitted"]
			}
			blip_elements = []
			for serialelement in blip["elements"]:
				if serialelement["type"] == ELEMENT_TYPE["GADGET"]:
					blip_elements.append(GadgetElement(None, serialelement["id"], serialelement["index"], serialelement["properties"]))
				else:
					blip_elements.append(Element(None, serialelement["id"], serialelement["index"], serialelement["type"], serialelement["properties"]))
			blipObj = self.appendBlip(blip_id, blip_options, blip["content"], blip_elements, pp.participant(blip["creator"]), contributors)
Example #5
0
	def __init__(self, wavelet, id, options, content = "", elements = None, parent = None, creator = None, contributors = None):
		"""
		Called on instantiation. Documented for internal purposes.
		@constructor {private} initialize
		@param {Wavelet} wavelet Parent Wavelet object
		@param {String} id ID of this Blip, setting this to an empty string will
			assign a new temporary ID
		@param {Object} options Information about the Blip. Possible values:
		@... {Boolean} is_root True if this is the root Blip; if this value
		     is set and the parent Wavelet does not have a root Blip yet,
		     this Blip is set as the Wavelet's root Blip
		@... {Date} last_modified Date of last modification
		@... {int} version Version of the Blip
		@... {Boolean} submitted True if this Blip is submitted
		@param {options String} content Content of the Blip
		@param {optional Element[]} elements Element objects which initially
		       reside in this Blip
		@param {optional Blip} parent Parent Blip if this is a nested Blip
		@param {optional Participant} creator Creator of this Blip
		@param {optional Participant[]} contributors Contributors of this Blip
		"""
		self.setOptions(options)
		self._wavelet = wavelet
		self._creator = creator
		self._contributors = Hash()
		if contributors == None:
			if self._creator != None:
				self._contributors.set(self._creator.id(), self._creator)
		else:
			for c in contributors:
				self._contributors.set(c.id(), c)
		if id == "":
			self._id = Blip.newTempId()
		else:
			self._id = id
		self._parent = parent
		
		self._content = content
		if elements == None:
			elements = Array()
		self._elements = elements
		for element in self._elements:
			element.setBlip(self)
		
		self._annotations = Array()
		
		self._outofsync = False
Example #6
0
class Wavelet(object):
	"""
	Models a Wavelet on a Wave.<br/>
	This is a private class and cannot be instanitated directly. Please
	use {@link pygowave.model.WaveModel.createWavelet WaveModel.createWavelet}.
	@class {private} pygowave.model.Wavelet
	"""

	options = {
		"creator": None,
		"is_root": False,
		"created": None,
		"last_modified": None,
		"title": "",
		"version": 0,
		"status": "clean"
	}
	
	# --- Event documentation ---
	"""
	Fired if a participant joins or leaves.
	@event onParticipantsChanged
	"""
	
	"""
	Fired if a Blip was inserted.
	@event onBlipInserted
	@param {int} index Index of the inserted Blip
	@param {String} blip_id ID of the inserted Blip
	"""
	
	"""
	Fired when the Wavelet's status changed.
	
	@event onStatusChange
	@param {String} status The new status; can be 'clean', 'dirty' or 'invalid'
	"""
	
	"""
	Fired when the Wavelet's title changed.
	@event onTitleChanged
	@param {String} title The Wavelet's new title
	"""
	
	"""
	Fired when the Wavelet's last modification date/time changed.
	@event onLastModifiedChanged
	@param {Date} datetime New date of last modification
	"""
	# ---------------------------
	
	def __init__(self, wave, id, options):
		"""
		Called on instantiation. Documented for internal purposes.
		@constructor {private} initialize
		@param {WaveModel} wave Parent WaveModel object
		@param {String} id Wavelet ID
		@param {Object} options Information about the Wavelet. Possible values:
		@... {Participant} creator Creator of this Wavelet
		@... {Boolean} is_root True if this is the root Wavelet; if this value
		     is set and the parent WaveModel does not have a root Wavelet yet,
		     this Wavelet is set as the Wave's root Wavelet
		@... {Date} created Date of creation
		@... {Date} last_modified Date of last modification
		@... {String} title Title of the Wavelet
		@... {int} version Version of the Wavelet
		@... {String} status Status of the Wavelet; can be 'clean', 'dirty' or 'invalid'
		"""
		self.setOptions(options)
		self._wave = wave
		if self.options["is_root"]:
			if self._wave.rootWavelet() == None:
				self._wave._setRootWavelet(self)
			else:
				self.options["is_root"] = False
		self._id = id
		self._participants = Hash()
		self._blips = []
		self._rootBlip = None
	
	def title(self):
		"""
		Returns the title of this Wavelet
		@function {public String} title
		"""
		return self.options["title"]
	
	def setTitle(self, title):
		"""
		Sets the title of this Wavelet
		@function {public} setTitle
		@param {String} title The new title
		"""
		if self.options["title"] != title:
			self.options["title"] = title
			self.fireEvent('titleChanged', title)
	
	def isRoot(self):
		"""
		Returns true, if this Wavelet is the Wave's root Wavelet.
		@function {public Boolean} isRoot
		"""
		return self.options["is_root"]
	
	def id(self):
		"""
		Returns the ID of this Wavelet.
		@function {public String} id
		"""
		return self._id
	
	def waveId(self):
		"""
		Returns the ID of this Wavelet's Wave.
		@function {public String} waveId
		"""
		return self._wave.id()
	
	def waveModel(self):
		"""
		Returns the parent WaveModel object.
		@function {public WaveModel} waveModel
		"""
		return self._wave

	def participantCount(self):
		"""
		Returns the number of participants on this Wavelet.
		@function {public int} participantCount
		"""
		return self._participants.getLength()

	def addParticipant(self, participant):
		"""
		Add a participant to this Wavelet.<br/>
		Note: Fires {@link pygowave.model.Wavelet.onParticipantsChanged onParticipantsChanged}
		
		@function {public} addParticipant
		@param {Participant} participant Participant to be added
		"""
		if not self._participants.has(participant.id()):
			self._participants.set(participant.id(), participant)
			self.fireEvent('participantsChanged', self._id)
	
	def removeParticipant(self, participantId):
		"""
		Removes a participant from this Wavelet.<br/>
		Note: Fires {@link pygowave.model.Wavelet.onParticipantsChanged onParticipantsChanged}
		
		@function {public} removeParticipant
		@param {String} participantId ID of the participant to remove
		"""
		if self._participants.has(participantId):
			del self._participants[participantId]
			self.fireEvent('participantsChanged', self._id)
	
	def participant(self, id):
		"""
		Returns the Participant object with the given id, if the participant
		resides on this Wavelet. Returns null otherwise.
		@function {Participant} participant
		@param {String} id ID of the Participant
		"""
		if self._participants.has(id):
			return self._participants.get(id)
		else:
			return None
	
	def allParticipants(self):
		"""
		Returns a list of all participants on this Wavelet.
		@function {public Participant[]} allParticipants
		"""
		return self._participants.getValues()
	
	def allParticipantIDs(self):
		"""
		Returns a list of all IDs of the participants on this Wavelet.
		@function {public String[]} allParticipantIDs
		"""
		return self._participants.getKeys()

	def allParticipantsForGadget(self):
		"""
		Convenience function to serialize all participants into the Wave
		Gadget API format.
		@function {public Object} allParticipantsForGadget
		"""
		ret = {}
		for id, participant in self._participants.iteritems():
			ret[id] = participant.toGadgetFormat()
		return ret
	
	def appendBlip(self, id, options, content = "", elements = []):
		"""
		Convenience function for inserting a new Blip at the end.
		For options see the {@link pygowave.model.Blip.initialize Blip constructor}.<br/>
		Note: Fires {@link pygowave.model.Wavelet.onBlipInserted onBlipInserted}
		
		@function {public Blip} appendBlip
		@param {String} id ID of the new Blip
		@param {Object} options Information about the Blip
		@param {optional String} content Content of the Blip
		@param {optional Element[]} elements Element objects which initially
		    reside in this Blip
		"""
		return self.insertBlip(len(self._blips), id, options, content, elements)

	def insertBlip(self, index, id, options, content = "", elements = []):
		"""
		Insert a new Blip at the specified index.
		For options see the {@link pygowave.model.Blip.initialize Blip constructor}.<br/>
		Note: Fires {@link pygowave.model.Wavelet.onBlipInserted onBlipInserted}
		
		@function {public Blip} insertBlip
		@param {int} index Index where to insert the Blip
		@param {String} id ID of the new Blip
		@param {Object} options Information about the Blip
		@param {optional String} content Content of the Blip
		@param {optional Element[]} elements Element objects which initially
		    reside in this Blip
		"""
		blip = Blip(self, id, options, content, elements)
		self._blips.insert(index, blip)
		self.fireEvent('blipInserted', [index, id])
		return blip
	
	def blipByIndex(self, index):
		"""
		Returns the Blip object at the given index.
		
		@function {Blip} blipByIndex
		@param {int} index Index of the Blip
		"""
		return self._blips[index]

	def blipById(self, id):
		"""
		Returns the Blip object with the given id, if the Blip resides on this
		Wavelet. Returns null otherwise.
		
		@function {Blip} blipById
		@param {String} id ID of the Blip
		"""
		
		for blip in self._blips:
			if blip.id() == id:
				return blip
		
		return None

	def allBlips(self):
		"""
		Returns a list of all Blips on this Wavelet, starting with the root Blip.
		
		@function {Blip[]} allBlips
		"""
		return self._blips
	
	def allBlipIDs(self):
		"""
		Returns a list of all IDs of the Blips on this Wavelet, starting with
		the root Blip.
		
		@function {public String[]} allBlipIDs
		"""
		ids = []
		for blip in self._blips:
			ids.append(blip.id())
		return ids

	def _setRootBlip(self, blip):
		"""
		Internal method to set the root Blip. Not intended to be called
		outside of this implementation.
		
		@function {private} _setRootBlip
		@param {Blip} blip Blip to be set as root Blip
		"""
		self._rootBlip = blip
	
	def _setStatus(self, status):
		"""
		Internal method to set the status. Fires
		{@link pygowave.model.Wavelet.onStatusChange onStatusChange} if the
		status changed.
		
		@function {private} _setStatus
		@param {String} status The status to set
		"""
		if self.options["status"] != status:
			self.options["status"] = status
			self.fireEvent("statusChange", status)
	
	def status(self):
		"""
		Returns the Wavelet's current status. Can be "clean", "dirty" or "invalid".
		@function {public String} status
		"""
		return self.options["status"]
	
	def created(self):
		"""
		Returns the creation date/time of this Wavelet.
		@function {public Date} created
		"""
		return self.options["created"]
	
	def lastModified(self):
		"""
		Returns the date/time of the last modification of this Wavelet.
		@function {public Date} lastModified
		"""
		return self.options["last_modified"]
	
	def setLastModified(self, value):
		"""
		Sets the date/time of the last modification of this Wavelet.
		@function {public} setLastModified
		@param {Date} value The new date/time of the last modification
		"""
		if value != self.options["last_modified"]:
			self.options["last_modified"] = value
			self.fireEvent('lastModifiedChanged', value)
	
	def checkSync(self, blipsums):
		"""
		Calculate and compare checksums of all Blips to the given map.
		Fires {@link pygowave.model.Wavelet.onStatusChange onStatusChange} if
		the status changes.
		
		@function {public} checkSync
		@param {Object} blipsums Checksums to compare to
		"""
		valid = True
		for blipId, checksum in blipsums.iteritems():
			blip = self.blipById(blipId);
			if blip != None:
				if not blip.checkSync(checksum):
					valid = False
		if valid:
			self._setStatus("clean")
		else:
			self._setStatus("invalid")
	
	def applyOperations(self, ops, participants):
		"""
		Apply the operations on the wavelet.
		
		@function {public} applyOperations
		@param {pygowave.operations.Operation[]} ops List of operations to apply
		"""
		
		for op in ops:
			if op.blipId != "":
				blip = self.blipById(op.blipId)
				if op.type == pygowave.operations.DOCUMENT_DELETE:
					blip.deleteText(op.index, op.property)
				elif op.type == pygowave.operations.DOCUMENT_INSERT:
					blip.insertText(op.index, op.property)
				elif op.type == pygowave.operations.DOCUMENT_ELEMENT_DELETE:
					blip.deleteElement(op.index)
				elif op.type == pygowave.operations.DOCUMENT_ELEMENT_INSERT:
					blip.insertElement(op.index, op.property["type"], op.property["properties"])
				elif op.type == pygowave.operations.DOCUMENT_ELEMENT_DELTA:
					blip.applyElementDelta(op.index, op.property)
				elif op.type == pygowave.operations.DOCUMENT_ELEMENT_SETPREF:
					blip.setElementUserpref(op.index, op.property["key"], op.property["value"])
			else:
				if op.type == pygowave.operations.WAVELET_ADD_PARTICIPANT:
					self.addParticipant(participants[op.property])
				elif op.type == pygowave.operations.WAVELET_REMOVE_PARTICIPANT:
					self.removeParticipant(op.property)
	
	def loadBlipsFromSnapshot(self, blips, rootBlipId, participants):
		"""
		Load the blips from a snapshot.
		@function {public} loadBlipsFromSnapshot
		@param {Object} blips The JSON-serialized snapshot to load
		@param {String} rootBlipId ID to identify the root Blip
		@param {Hash} participants A map of participant objects
		"""
		
		for blip_id, blip in blips.iteritems():
			#TODO: handle Blip contributors
			blip_options = {
				"creator": participants[blip["creator"]],
				"is_root": blip_id == rootBlipId,
				"last_modified": blip["lastModifiedTime"],
				"version": blip["version"],
				"submitted": blip["submitted"]
			}
			blip_elements = []
			for serialelement in blip["elements"]:
				if serialelement["type"] == ELEMENT_TYPE["GADGET"]:
					blip_elements.append(GadgetElement(None, serialelement["id"], serialelement["index"], serialelement["properties"]))
				else:
					blip_elements.append(Element(None, serialelement["id"], serialelement["index"], serialelement["type"], serialelement["properties"]))
			blipObj = self.appendBlip(blip_id, blip_options, blip["content"], blip_elements)
Example #7
0
class WaveModel(object):
	"""
	Wave model class. Top level model which sends all events.
	
	@class {public} pygowave.model.WaveModel
	"""
	
	# --- Event documentation ---
	"""
	Fired if a Wavelet has been added.
	@event onWaveletAdded
	@param {String} waveletId ID of the Wavelet that has been added
	@param {Boolean} isRoot True if this is the (new) root Wavelet
	"""
	
	"""
	Fired before a wavelet is removed.
	@event onWaveletAboutToBeRemoved
	@param {String} waveletId ID of the Wavelet that will be removed
	"""
	# ---------------------------
	
	def __init__(self, waveId, viewerId):
		"""
		Called on instantiation.
		@constructor {public} initialize
		@param {String} waveId ID of the Wave
		@param {String} viewerId ID of the viewer
		"""
		self._rootWavelet = None
		self._waveId = waveId
		self._viewerId = viewerId
		self._wavelets = Hash()

	def id(self):
		"""
		Returns the ID of this Wave.
		
		@function {public String} id
		"""
		return self._waveId

	def viewerId(self):
		"""
		Returns the ID of the viewer.
		
		@function {public String} viewerId
		"""
		return self._viewerId

	def loadFromSnapshot(self, obj, participants):
		"""
		Load the wave's contents from a JSON-serialized snapshot and a map of
		participant objects.
		
		@function {public} loadFromSnapshot
		@param {Object} obj The JSON-serialized snapshot to load
		@param {Hash} participants A map of participant objects
		"""
		
		rootWavelet = obj["wavelet"]
		
		wvl_options = {
			"creator": participants[rootWavelet["creator"]],
			"is_root": True,
			"created": rootWavelet["creationTime"],
			"last_modified": rootWavelet["lastModifiedTime"],
			"title": rootWavelet["title"],
			"version": rootWavelet["version"]
		}
		
		rootWaveletObj = self.createWavelet(rootWavelet["waveletId"], wvl_options)
		
		for part_id in rootWavelet["participants"]:
			rootWaveletObj.addParticipant(participants[part_id])
		
		rootWaveletObj.loadBlipsFromSnapshot(obj["blips"], rootWavelet["rootBlipId"], participants);

	def createWavelet(self, id, options):
		"""
		Create a Wavelet and add it to this Wave. For options see the
		{@link pygowave.model.Wavelet.initialize Wavelet constructor}.<br/>
		Note: Fires {@link pygowave.model.WaveModel.onWaveletAdded onWaveletAdded}
		
		@function {public Wavelet} createWavelet
		@param {String} id Wavelet ID
		@param {Object} options Information about the Wavelet.
		"""
		w = Wavelet(self, id, options)
		self._wavelets.set(id, w)
		self.fireEvent('waveletAdded', [id, w.isRoot()])
		return w
	
	def wavelet(self, waveletId):
		"""
		Return a Wavelet of this Wave by its ID.
		
		@function {public Wavelet} wavelet
		@param {String} waveletId ID of the Wavelet
		"""
		return self._wavelets.get(waveletId)
	
	def allWavelets(self):
		"""
		Return a list of all Wavelets on this Wave.
		
		@function {public Wavelet[]} allWavelets
		"""
		return self._wavelets.getValues()

	def rootWavelet(self):
		"""
		Returns the root Wavelet of this Wave.
		
		@function {public Wavelet} rootWavelet
		"""
		return self._rootWavelet
	
	def _setRootWavelet(self, wavelet):
		"""
		Internal method to set the root Wavelet. Not intended to be called
		outside of this implementation.
		
		@function {private} _setRootWavelet
		@param {Wavelet} wavelet Wavelet to be set as root Wavelet
		"""
		self._rootWavelet = wavelet
	
	def removeWavelet(self, waveletId):
		"""
		Removes and deletes a wavelet by its id. Fires
		{@link pygowave.model.WaveModel.onWaveletAboutToBeRemoved} beforehand.
		
		@function {public} removeWavelet
		@param {String} waveletId ID of the Wavelet to remove
		"""
		if not self._wavelets.has(waveletId):
			return
		
		self.fireEvent('waveletAboutToBeRemoved', waveletId)
		wavelet = self._wavelets.get(waveletId)
		self._wavelets.erase(waveletId)
		if wavelet == self._rootWavelet:
			self._rootWavelet = None
Example #8
0
print a[1:3]  # Slicing

b = {}  # Empty dictionary

# Dictionary with strings and numbers as indices
b = {"a": 1, "b": 2, 1: "x", 2: "y", "-test-": 1 + 2, "0HAY0": "a" + "B"}

# Accessing subscript (simple string)
print b["a"]

# Accessing subscript (other string; assignment)
b["-test-"] = 3

# Accessing subscript (number)
print b[1]

# Deleting from map
del b["a"]

# Modulo operator on strings, i.e. sprintf
print "Demo %d %s %.2f" % (b["-test-"], "abc", 0.123456)

# Operator precedence test
print(1 > 2) and ((2 * 3) > 8)  # removes all parentheses
print 1 * (2 + 4) * -(1 + 2)  # keeps all parentheses
print(True and True) and False or False

# isinstance
print isinstance([], list)
print isinstance(Hash(), Hash)
Example #9
0
class WaveModel(object):
	"""
	Wave model class. Top level model which sends all events.
	
	@class {public} pygowave.model.WaveModel
	"""
	
	# --- Event documentation ---
	"""
	Fired if a Wavelet has been added.
	@event onWaveletAdded
	@param {String} waveletId ID of the Wavelet that has been added
	@param {Boolean} isRoot True if this is the (new) root Wavelet
	"""
	# ---------------------------
	
	def __init__(self, waveId, viewerId):
		"""
		Called on instantiation.
		@constructor {public} initialize
		@param {String} waveId ID of the Wave
		@param {String} viewerId ID of the viewer
		"""
		self._rootWavelet = None
		self._waveId = waveId
		self._viewerId = viewerId
		self._wavelets = Hash()

	def id(self):
		"""
		Returns the ID of this Wave.
		
		@function {public String} id
		"""
		return self._waveId

	def viewerId(self):
		"""
		Returns the ID of the viewer.
		
		@function {public String} viewerId
		"""
		return self._viewerId

	def loadFromSnapshot(self, obj, participants):
		"""
		Load the wave's contents from a JSON-serialized snapshot and a map of
		participant objects.
		
		@function {public} loadFromSnapshot
		@param {Object} obj The JSON-serialized snapshot to load
		@param {Hash} participants A map of participant objects
		"""
		
		rootWavelet = obj["wavelet"]
		
		wvl_options = {
			"creator": participants[rootWavelet["creator"]],
			"is_root": True,
			"created": rootWavelet["creationTime"],
			"last_modified": rootWavelet["lastModifiedTime"],
			"title": rootWavelet["title"],
			"version": rootWavelet["version"]
		}
		
		rootWaveletObj = self.createWavelet(rootWavelet["waveletId"], wvl_options)
		
		for part_id in rootWavelet["participants"]:
			rootWaveletObj.addParticipant(participants[part_id])
		
		for blip_id, blip in obj["blips"].iteritems():
			#TODO: handle Blip contributors
			blip_options = {
				"creator": participants[blip["creator"]],
				"is_root": blip["blipId"] == rootWavelet["rootBlipId"],
				"last_modified": blip["lastModifiedTime"],
				"version": blip["version"],
				"submitted": blip["submitted"]
			}
			blip_elements = []
			for serialelement in blip["elements"]:
				if serialelement["type"] == ELEMENT_TYPE["GADGET"]:
					blip_elements.append(GadgetElement(None, serialelement["id"], serialelement["index"], serialelement["properties"]))
				else:
					blip_elements.append(Element(None, serialelement["id"], serialelement["index"], serialelement["type"], serialelement["properties"]))
			blipObj = rootWaveletObj.appendBlip(blip_id, blip_options, blip["content"], blip_elements)

	def createWavelet(self, id, options):
		"""
		Create a Wavelet and add it to this Wave. For options see the
		{@link pygowave.model.Wavelet.initialize Wavelet constructor}.<br/>
		Note: Fires {@link pygowave.model.WaveModel.onWaveletAdded onWaveletAdded}
		
		@function {public Wavelet} createWavelet
		@param {String} id Wavelet ID
		@param {Object} options Information about the Wavelet.
		"""
		w = Wavelet(self, id, options)
		self._wavelets.set(id, w)
		self.fireEvent('waveletAdded', [id, w.isRoot()])
		return w
	
	def wavelet(self, waveletId):
		"""
		Return a Wavelet of this Wave by its ID.
		
		@function {public Wavelet} wavelet
		@param {String} waveletId ID of the Wavelet
		"""
		return self._wavelets.get(waveletId)
	
	def rootWavelet(self):
		"""
		Returns the root Wavelet of this Wave.
		
		@function {public Wavelet} rootWavelet
		"""
		return self._rootWavelet
	
	def _setRootWavelet(self, wavelet):
		"""
		Internal method to set the root Wavelet. Not intended to be called
		outside of this implementation.
		
		@function {private} _setRootWavelet
		@param {Wavelet} wavelet Wavelet to be set as root Wavelet
		"""
		self._rootWavelet = wavelet
Example #10
0
class Blip(object):
	"""
	Models a Blip in a Wavelet.<br/>
	This is a private class and cannot be instanitated directly. Please
	use {@link pygowave.model.Wavelet.addBlip Wavelet.addBlip}.
	@class {private} pygowave.model.Blip
	"""
	
	options = {
		"is_root": False,
		"last_modified": None,
		"version": 0,
		"submitted": False,
	}
	
	# --- Event documentation ---
	"""
	Fired on text insertion.
	
	@event onInsertedText
	@param {int} index Offset where the text is inserted
	@param {String} text The text to be inserted
	"""
	
	"""
	Fired on text deletion.
	
	@event onDeletedText
	@param {int} index Offset where the text is deleted
	@param {int} length Number of characters to delete
	"""
	
	"""
	Fired on element insertion.
	
	@event onInsertedElement
	@param {int} index Offset where the element is inserted
	"""
	
	"""
	Fired on element deletion.
	
	@event onDeletedElement
	@param {int} index Offset where the element is deleted
	"""
	
	"""
	Fired if the Blip has gone out of sync with the server.
	
	@event onOutOfSync
	"""
	
	"""
	Fired when the Blip's last modification date/time changed.
	
	@event onLastModifiedChanged
	@param {Date} date
	"""
	
	"""
	Fired when the Blip's ID changed; should only happen on temporary Blips.
	
	@event onIdChanged
	@param {String} oldId
	@param {String} newId
	"""
	
	"""
	Fired when a new contributor has been added.
	
	@event onContributorAdded
	@param {String} id His/her/its ID
	"""
	# ---------------------------
	
	def __init__(self, wavelet, id, options, content = "", elements = None, parent = None, creator = None, contributors = None):
		"""
		Called on instantiation. Documented for internal purposes.
		@constructor {private} initialize
		@param {Wavelet} wavelet Parent Wavelet object
		@param {String} id ID of this Blip, setting this to an empty string will
			assign a new temporary ID
		@param {Object} options Information about the Blip. Possible values:
		@... {Boolean} is_root True if this is the root Blip; if this value
		     is set and the parent Wavelet does not have a root Blip yet,
		     this Blip is set as the Wavelet's root Blip
		@... {Date} last_modified Date of last modification
		@... {int} version Version of the Blip
		@... {Boolean} submitted True if this Blip is submitted
		@param {options String} content Content of the Blip
		@param {optional Element[]} elements Element objects which initially
		       reside in this Blip
		@param {optional Blip} parent Parent Blip if this is a nested Blip
		@param {optional Participant} creator Creator of this Blip
		@param {optional Participant[]} contributors Contributors of this Blip
		"""
		self.setOptions(options)
		self._wavelet = wavelet
		self._creator = creator
		self._contributors = Hash()
		if contributors == None:
			if self._creator != None:
				self._contributors.set(self._creator.id(), self._creator)
		else:
			for c in contributors:
				self._contributors.set(c.id(), c)
		if id == "":
			self._id = Blip.newTempId()
		else:
			self._id = id
		self._parent = parent
		
		self._content = content
		if elements == None:
			elements = Array()
		self._elements = elements
		for element in self._elements:
			element.setBlip(self)
		
		self._annotations = Array()
		
		self._outofsync = False
	
	def id(self):
		"""
		Returns the ID of this Blip.
		
		@function {public String} id
		"""
		return self._id
	
	def setId(self, id):
		"""
		Sets the ID of this Blip. Mainly used for temporary Blips.
		
		@function {public} setId
		@param {String} id The new id
		"""
		if id != self._id:
			oldId = self._id
			self._id = id
			self.fireEvent("idChanged", [oldId, id])
	
	def wavelet(self):
		"""
		Returns the parent Wavelet of this Blip.
		
		@function {public Wavelet} wavelet
		"""
		return self._wavelet

	def isRoot(self):
		"""
		Returns true, if this Blip is the Wavelet's root Blip.
		@function {public Boolean} isRoot
		"""
		return self.options["is_root"]

	def creator(self):
		"""
		Returns the creator of this Blip.
		@function {public Participant} creator
		"""
		return self._creator

	def elementById(self, id):
		"""
		Returns an Element by its id.
		@function {public Element} elementById
		@param {int} id ID of the element
		"""
		for i in xrange(len(self._elements)):
			elt = self._elements[i]
			if elt.id() == id:
				return elt
		
		return None

	def elementAt(self, index):
		"""
		Returns the Element object at the given position or null.
		
		@function {public Element} elementAt
		@param {int} index Index of the element to retrieve
		"""
		
		for i in xrange(len(self._elements)):
			elt = self._elements[i]
			if elt.position() == index:
				return elt
		
		return None

	def elementsWithin(self, start, end):
		"""
		Returns the Elements between the start and end index.
		
		@function {public Element[]} elementsWithin
		@param {int} start Start index
		@param {int} end End index
		"""
		
		lst = Array()
		for i in xrange(self._elements.length):
			elt = self._elements[i]
			if elt.position() >= start and elt.position() < end:
				lst.append(elt)
		
		return lst

	def allElements(self):
		"""
		Returns all Elements of this Blip.
		
		@function {public Element[]} allElements
		"""
		
		return self._elements

	def allContributors(self):
		"""
		Returns all contributors to this Blip.
		
		@function {public Participant[]} allContributors
		"""
		return self._contributors.getValues()

	def addContributor(self, contributor):
		"""
		Add a contributor to this Blip if he is not already contributing.
		
		@function {public} addContributor
		@param {Participant} contributor
		"""
		
		if not self._contributors.has(contributor.id()):
			self._contributors.set(contributor.id(), contributor)
			self.fireEvent("contributorAdded", contributor.id())

	def insertText(self, index, text, contributor, noevent = False):
		"""
		Insert a text at the specified index. This moves annotations and
		elements as appropriate.<br/>
		Note: This sets the wavelet status to 'dirty'.
		
		@function {public} insertText
		@param {int} index Index of insertion
		@param {String} text Text to be inserted
		@param {Participant} contributor Participant who contributed this action
		@param {optional Boolean} noevent Set to true if no event should be generated
		"""
		
		self.addContributor(contributor)
		
		self._content = self._content[:index] + text + self._content[index:]
		
		length = len(text)
		
		for elt in self._elements:
			if elt.position() >= index:
				elt.setPosition(elt.position() + length)
		
		for anno in self._annotations:
			if anno.start() >= index:
				anno.setStart(anno.start() + length)
				anno.setEnd(anno.end() + length)
		
		self._wavelet._setStatus("dirty")
		if not noevent:
			self.fireEvent("insertedText", [index, text])
	
	def deleteText(self, index, length, contributor, noevent = False):
		"""
		Delete text at the specified index. This moves annotations and
		elements as appropriate.<br/>
		Note: This sets the wavelet status to 'dirty'.
		
		@function {public} deleteText
		@param {int} index Index of deletion
		@param {int} length Number of characters to delete
		@param {Participant} contributor Participant who contributed this action
		@param {optional Boolean} noevent Set to true if no event should be generated
		"""
		
		self.addContributor(contributor)
		
		self._content = self._content[:index] + self._content[index+length:]
		
		for elt in self._elements:
			if elt.position() >= index:
				elt.setPosition(elt.position() - length)
		
		for anno in self._annotations:
			if anno.start() >= index:
				anno.setStart(anno.start() - length)
				anno.setEnd(anno.end() - length)
		
		self._wavelet._setStatus("dirty")
		if not noevent:
			self.fireEvent("deletedText", [index, length])
	
	def insertElement(self, index, type, properties, contributor, noevent = False):
		"""
		Insert an element at the specified index. This implicitly adds a
		protected newline character at the index.<br/>
		Note: This sets the wavelet status to 'dirty'.
		
		@function {public} insertElement
		@param {int} index Position of the new element
		@param {String} type Element type
		@param {Object} properties Element properties
		@param {Participant} contributor Participant who contributed this action
		@param {optional Boolean} noevent Set to true if no event should be generated
		"""
		
		self.addContributor(contributor)
		
		self.insertText(index, "\n", contributor, True)
		elt = None
		if type == 2:
			elt = GadgetElement(self, None, index, properties)
		else:
			elt = Element(self, None, index, type, properties)
		self._elements.append(elt)
		
		self._wavelet._setStatus("dirty")
		if not noevent:
			self.fireEvent("insertedElement", index)
	
	def deleteElement(self, index, contributor, noevent = False):
		"""
		Delete an element at the specified index. This implicitly deletes the
		protected newline character at the index.<br/>
		Note: This sets the wavelet status to 'dirty'.
		
		@function {public} deleteElement
		@param {int} index Position of the element to delete
		@param {Participant} contributor Participant who contributed this action
		@param {optional Boolean} noevent Set to true if no event should be generated
		"""
		
		self.addContributor(contributor)
		
		for i in xrange(len(self._elements)):
			elt = self._elements[i]
			if elt.position() == index:
				self._elements.pop(i)
				break
		self.deleteText(index, 1, contributor, True)
		if not noevent:
			self.fireEvent("deletedElement", index)
	
	def applyElementDelta(self, index, delta, contributor):
		"""
		Apply an element delta. Currently only for gadget elements.<br/>
		Note: This action always emits stateChange.
		
		@function {public} applyElementDelta
		@param {int} index Position of the element
		@param {Object} delta Delta to apply to the element
		@param {Participant} contributor Participant who contributed this action
		"""
		
		self.addContributor(contributor)
		
		for elt in self._elements:
			if elt.position() == index:
				elt.applyDelta(delta)
				break
	
	def setElementUserpref(self, index, key, value, contributor, noevent = False):
		"""
		Set an UserPref of an element. Currently only for gadget elements.
		
		@function {public} setElementUserpref
		param {int} index Position of the element
		@param {Object} key Name of the UserPref
		@param {Object} value Value of the UserPref
		@param {Participant} contributor Participant who contributed this action
		@param {optional Boolean} noevent Set to true if no event should be generated
		"""
		
		self.addContributor(contributor)
		
		for elt in self._elements:
			if elt.position() == index:
				elt.setUserPref(key, value, noevent)
				break

	def content(self):
		"""
		Returns the text content of this Blip.
		@function {public String} content
		"""
		return self._content
	
	def lastModified(self):
		"""
		Returns the date/time of the last modification of this Blip.
		@function {public Date} lastModified
		"""
		return self.options.last_modified
	
	def setLastModified(self, value):
		"""
		Sets the date/time of the last modification of this Blip.
		@function {public Date} setLastModified
		@param {Date} value
		"""
		if self.options["last_modified"] != value:
			self.options["last_modified"] = value
			self.fireEvent("lastModifiedChanged", value)
	
	def checkSync(self, sum):
		"""
		Calculate a checksum of this Blip and compare it against the given
		checksum. Fires {@link pygowave.model.Blip.onOutOfSync onOutOfSync} if
		the checksum is wrong. Returns true if the checksum is ok.
		
		Note: Currently this only calculates the SHA-1 of the Blip's text. This
		is tentative and subject to change
		
		@function {public Boolean} checkSync
		@param {String} sum Input checksum to compare against
		"""
		if self._outofsync:
			return False
		mysum = sha_constructor(self._content.encode("utf-8")).hexdigest()
		if mysum != sum:
			self.fireEvent("outOfSync")
			self._outofsync = True
			return False
		else:
			return True
	
	@staticmethod
	def newTempId():
		Blip.lastTempId += 1
		return "TBD_%02d" % (Blip.lastTempId,)