示例#1
0
    def UnregisterObserver( self, annoType, annoObserver ):
        "Input: Type annoType, BoardObserver annonObserve.  remove the annObserver from the list of observers for annoType"
        logger.debug("Unregistering annotation %s observer %s" % (annoType, type(annoObserver)))
        annoHash = annoType.__name__
        if annoHash in self.AnnoObservers:
            if annoObserver in self.AnnoObservers[annoHash]:
	            self.AnnoObservers[annoHash].remove(annoObserver)
示例#2
0
    def isType( self, arg):
        "Input: either a classobj, or a list of classobjs.  Return true if this class is one of the classobjs listed"
        if type(arg) == "list":
            clist = arg
        else:
            clist = [arg]

        if self.__class__ in clist:
            return True
        else:
            return False
示例#3
0
 def AddStroke( self, newStroke ):
     "Input: Stroke newStroke.  Adds a Stroke to the board and calls any Stroke Observers as needed"
     logger.debug( "Adding Stroke: %d"% (newStroke.id) )
     
     self.Strokes.append( newStroke )
     
     logger.debug("Observers: %s" % (self.StrokeObservers))
     for so in self.StrokeObservers:
         if newStroke not in self._removed_strokes: #Nobody has removed this stroke yet
             logger.debug("Alerting %s observer" % (type(so)))
             so.onStrokeAdded( newStroke )
示例#4
0
    def AnnotateStrokes(self, strokes, anno):
        "Input: list of Strokes strokes, Annotation anno.  Add annotation to the set of strokes"
        logger.debug("Annotating strokes as %s" % (type(anno)))
        annoHash = type(anno)
        logger.debug("Annotype: %s, Observers: %s" % (annoHash, self.AnnoObservers.keys()))
        # time is used to play back stroke orderings during debug
        if not hasattr(anno, "Time"):
	    anno.Time = datetime.datetime.utcnow()
        # the annotation keeps a list of strokes it annotates
        anno.Strokes = list(strokes)
        # for each stroke, add this annotation to the list of annotations of that type for that stroke
        for s in strokes:
            annoList = s.Annotations.setdefault(annoHash, [])
            annoList.append(anno)

        # if anyone listening for this class of anno, notify them
        annoObsvrs = self.AnnoObservers.get(annoHash)
        if (annoObsvrs != None):
            for i in annoObsvrs:
                if anno not in self._removed_annotations: #Will fail if someone has called "RemoveAnnotation"
                    logger.debug("Alerting %s to new annotation %s" % (type(i), annoHash))
                    i.onAnnotationAdded(strokes, anno)
示例#5
0
    def RegisterForAnnotation( self, annoType, annoObserver, funcToCall = None ):
        "Input: Type annoType, BoardObserver annoObserver, function funcToCall.  Call the observer when the matching annoation is found"
	    #  Function funcToCall Registers with the board an Observer based on an 
	    #  Annotation type.  Optional: An *additional* function to call on the observer upon annotation occurence
        annoHash = annoType.__name__
        if ( annoHash not in self.AnnoObservers ):
            self.AnnoObservers[annoHash] = []

        if annoObserver not in self.AnnoObservers[annoHash]:
            self.AnnoObservers[annoHash].append( annoObserver )
            logger.debug( "Registering %s for %s"% ( type(annoObserver), annoHash ) )
        else:
            logger.warning( "%s already registered for %s"% str(type(annoObserver)), str(annoHash) )
            
        # TODO: can we depricate this?  Is this still actively used?
        if (funcToCall != None):
            if not hasattr(annoObserver, "AnnoFuncs"): #Cause Python does things arguably backwards and calls the child ctors before the parents..
                annoObserver.AnnoFuncs = {}
            
            if annoHash not in annoObserver.AnnoFuncs:
                 annoObserver.AnnoFuncs[annoHash] = funcToCall
                 logger.debug( "Registering %s.%s for %s" % (type(annoObserver),funcToCall,  annoHash))
示例#6
0
    def UpdateAnnotation(self, anno, new_strokes=None, notify=True, remove_empty = True ):
	"""Input: Annotation, Strokes.  Changes the annotation and alerts the correct listeners. 
       If the new strokes are empty, remove_empty determines whether to remove the annotation."""
        # if strokes are different from the old strokes then we update them too
        # if notify is False, then don't send the update notification.  This allows
        # people to perform multiple updates, and then call notify one time at the end
        # preventing everyone from being notified on every small change made
        logger.debug( "Updating Annotation: %s"% str(anno) )

        # if we added or subtracted strokes, update accordingly
        annoHash = type(anno)
        old_strokes = anno.Strokes
        shouldRemove = (len(new_strokes) == 0 and remove_empty) #We still have strokes, or no strokes and we're not removing empty annos
        if new_strokes!=None:
            if new_strokes!=old_strokes:
                stroke_gone_list = list( set(old_strokes).difference(new_strokes))
                stroke_added_list = list( set(new_strokes).difference(old_strokes))
                for old_stroke in stroke_gone_list:
                    if anno in old_stroke.Annotations[annoHash]:
                        old_stroke.Annotations[annoHash].remove( anno )
                for new_stroke in stroke_added_list:
                    if annoHash in new_stroke.Annotations:
                        new_stroke.Annotations[annoHash].append(anno)
                    else:
                        new_stroke.Annotations[annoHash] = [anno]
                anno.Strokes = new_strokes

            # if anyone is listening for this class of annotation, let them know we updated
            if not shouldRemove and notify and annoHash in self.AnnoObservers:
                for obs in self.AnnoObservers[annoHash]:
                    # tell obs about the updated annotation
                    if anno not in self._removed_annotations: #Fails if someone called removeAnnotation
                        logger.debug("Alerting %s to updated annotation %s" % (type(i), annoHash))
                        obs.onAnnotationUpdated(anno)
            elif shouldRemove:
                #The strokes are empty, so remove the annotation
                self.RemoveAnnotation(anno)
示例#7
0
    def RemoveAnnotation(self, anno):
        "Input: Annotation anno.  Removes anno from the board and alert the correct listeners"
        logger.debug( "Removing Annotation: %s"% str(anno) )
        annoHash = type(anno)

        self._removed_annotations[anno] = True
        
        # if anyone is listening for this class of annotation, let them know
        if annoHash in self.AnnoObservers:
            for obs in self.AnnoObservers[annoHash]:
                obs.onAnnotationRemoved(anno)
        # remove the annotation from the strokes. 
        # do this second, since observers may need to check the old strokes' properties
        for stroke in anno.Strokes:
            # logger.debug("RemoveAnnotation: stroke.Annotations = %s, id=%d", stroke.Annotations, stroke.id )
            # logger.debug("RemoveAnnotation: anno.__class__ = %s", anno.__class__ )
            try:
                stroke.Annotations[annoHash].remove(anno)
                #if len(stroke.Annotations[anno.__class__]) == 0:
                #    del(stroke.Annotations[anno.__class__]) #Delete the entry if it's empty
            except KeyError:
                logger.error( "RemoveAnnotation: Annotation %s not found in stroke.Annotations"% annoHash )
            except ValueError:
                logger.error( "RemoveAnnotation: Trying to remove nonexistant annotation %s"% anno  )
示例#8
0
 def RegisterForStroke( self, strokeObserver ):
     "Input: BoardObserver stroke.  Registers with the board an Observer to be called when strokes are added"
     logger.debug("Registering observer %s for STROKES" % (type(strokeObserver)))
     self.StrokeObservers.append( strokeObserver )
示例#9
0
 def AddBoardObserver ( self, obs ):
     "Input: Observer obs.  Obs is added to the list of Board Observers"
     # FIXME? should we check that the object is one in the list once?
     logger.debug( "Adding Observer: %s" % str(type(obs)) )
     self.BoardObservers.append( obs )
示例#10
0
    def UnregisterStrokeObserver( self, observer ):
        "Input: BoardObserver observer.  Remove the observer from the list of stroke observers"
        logger.debug("Unregistering stroke observer %s" % (type(observer)))
        if observer in self.StrokeObservers:
	        self.StrokeObservers.remove(observer)
示例#11
0
    def drawMyself( self ):
        # FIXME: does this tie us to the tk front-end?  If so, what should
        # we put into the GUI API to enable this sort of animation? is it mostly 
        # "update" that is needed?
        from SketchFramework import SketchGUI as gui
        canvas = gui.SketchGUISingleton()
        color_levels = { 0: "#FF6633", 1: "#FF00FF", 2: "#3366FF", 3: "#00CC00",}
        scale = 18  # pixels for text size

        # start with a list of all the annotations
        allAnnoSet = set([])
        logger.debug("Watch set %s" % (self.watchSet))
        for stroke in BoardSingleton().Strokes:
            logger.debug("Stroke annotations %s" % (stroke.findAnnotations(None)))

            for anno in stroke.findAnnotations(None):
                logger.debug ("%s in %s?" % (type(anno), list(self.watchSet)))
                if type(anno) in list(self.watchSet):
                    logger.debug("Adding %s to annoset" % (anno))
                    allAnnoSet.add( anno )

        # now make a map from the sets of strokes to the annotations on them
        annoMap = {} # dictionary of {frozenset(strokes):[annotations]}
        for anno in allAnnoSet:
            strokeset = frozenset(anno.Strokes)
            if strokeset not in annoMap:
                annoMap[strokeset] = []
            annoMap[strokeset].append( anno )

        # now assign a unique size for each anno on a given set of strokes
        sizeDict = {}
        for strokeset in annoMap.keys():
            depth = 0
            for anno in annoMap[strokeset]:
                sizeDict[anno] = depth
                depth += 1

        # sort the annotations based on the time at which they were added
        annoList = list(allAnnoSet)
        annoList.sort(key= (lambda x: x.Time))
        for anno in annoList:
            nestlevel = sizeDict[anno] # get the nesting level for this annotation
            # for the set of stroke this anno is annotating, find the bounding box
            
            tl = anno.Strokes[0].BoundTopLeft
            br = anno.Strokes[0].BoundBottomRight
            tlx = tl.X
            tly = tl.Y
            brx = br.X
            bry = br.Y
            
            bottomright_list = [s.BoundBottomRight for s in anno.Strokes]
            topleft_list = [s.BoundTopLeft for s in anno.Strokes]
            br, tl = _nestingBox(bottomright_list, topleft_list, scale = nestlevel*3)
            br.Y -= nestlevel * scale # save some space for text on bottom of box

            # if this is a "new" anno, wait a little before drawing
            if anno not in self.seenBefore:
                #time.sleep(0.5)
                self.seenBefore[anno] = True

            # now draw the actual boxes
            labeltext = anno.classname()
            tlx = tl.X
            tly = tl.Y
            brx = br.X
            bry = br.Y
            
            gui.drawBox(tl,br,color=color_levels[nestlevel % len(color_levels)])
            gui.drawText(tl.X, br.Y+scale, size = 12, InText=labeltext)