Пример #1
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)
Пример #2
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)