def getfileurl(self, node): # This method has all sorts of magic to write a # RealPix file "just in time". If the node has # changed there is a tmpfile attribute. Since the # node has changed internally, we must write a copy # and we'll use the tmpfile attribute for a file name. # If the node has no URL, there is no existing file # that we can use, so we invent a name and write the # file. url = Channel.ChannelWindowAsync.getfileurl(self, node) if not url or url[:5] == 'data:': if hasattr(node, 'rptmpfile') and node.rptmpfile[1] == url: url = node.rptmpfile[0] else: import tempfile, realsupport, MMurl f = MMurl.urlopen(url) head = f.read(4) if head != '<imf': f.close() # delete rptmpfile attr if it exists node.rptmpfile = None del node.rptmpfile return url rp = realsupport.RPParser(url) rp.feed(head) rp.feed(f.read()) f.close() rp.close() f = tempfile.mktemp('.rp') nurl = MMurl.pathname2url(f) node.rptmpfile = nurl, url realsupport.writeRP(f, rp, node, baseurl=url) if not self.__callback_added: import windowinterface windowinterface.addclosecallback(_deltmpfiles, ()) VideoChannel.__callback_added = 1 self.tmpfiles.append(f) return url
def update(self, changed = 0): node = self.node oldrp = self.rp if node.GetType() != 'ext' or \ node.GetChannelType() != 'RealPix': # not a RealPix node anymore ## if hasattr(node, 'expanded'): ## import HierarchyView ## HierarchyView.collapsenode(node) del node.slideshow self.destroy() # XXX what to do with node.tmpfile? if hasattr(node, 'tmpfile'): try: os.unlink(node.tmpfile) except: pass del node.tmpfile return if oldrp is None: return ctx = node.GetContext() url = MMAttrdefs.getattr(node, 'file') ourl = url if url: url = ctx.findurl(url) utype, host, path, params, query, tag = urlparse.urlparse(url) url = urlparse.urlunparse((utype, host, path, params, query, '')) if url != self.url: # different URL specified try: if not url: raise IOError fp = MMurl.urlopen(url) except IOError: # new file does not exist, keep content rp = self.rp else: # new file exists, use it import realsupport self.filename = url rp = realsupport.RPParser(url, baseurl = ourl, printfunc = self.printfunc) try: rp.feed(fp.read()) rp.close() except: import sys tp, vl, tb = sys.exc_info() msg = 'Error reading RealPix file %s:\n%s' % (url, vl) windowinterface.showmessage(msg, mtype = 'warning') self.node.set_infoicon('error', msg) rp = DummyRP() fp.close() if rp is not self.rp and hasattr(node, 'tmpfile'): # new content, delete temp file ## windowinterface.showmessage('You have edited the content of the slideshow file in node %s on channel %s' % (MMAttrdefs.getattr(node, 'name') or '<unnamed>', node.GetChannelName()), mtype = 'warning') choice = self.asksavechanges() if choice == 2: # cancel node.SetAttr('file', self.url) self.update() return if choice == 0: # yes, save file node.SetAttr('file', self.url) writenode(node) node.SetAttr('file', url) else: # no, discard changes try: os.unlink(node.tmpfile) except: pass del node.tmpfile self.url = url self.rp = rp rp = self.rp attrdict = node.GetAttrDict() bitrate = MMAttrdefs.getattr(node, 'bitrate') if bitrate != rp.bitrate: if rp is oldrp: rp.bitrate = bitrate changed = 1 else: attrdict['bitrate'] = rp.bitrate size = MMAttrdefs.getattr(node, 'size') if size != (rp.width, rp.height): if rp is oldrp: rp.width, rp.height = size changed = 1 else: if rp.width == 0 and rp.height == 0: rp.width, rp.height = node.GetChannel().get('base_winoff',(0,0,256,256))[2:4] attrdict['size'] = rp.width, rp.height duration = MMAttrdefs.getattr(node, 'duration') if abs(float(duration - rp.duration)) / max(duration, rp.duration, 1) > 0.00001: ## if duration != rp.duration: if rp is oldrp: rp.duration = duration changed = 1 else: attrdict['duration'] = rp.duration aspect = MMAttrdefs.getattr(node, 'aspect') if (rp.aspect == 'true') != aspect: if rp is oldrp: rp.aspect = ['false','true'][aspect] changed = 1 else: attrdict['aspect'] = rp.aspect == 'true' author = MMAttrdefs.getattr(node, 'author') if author != rp.author: if rp is oldrp: rp.author = author changed = 1 elif rp.author: attrdict['author'] = rp.author elif attrdict.has_key('author'): del attrdict['author'] copyright = MMAttrdefs.getattr(node, 'copyright') if copyright != rp.copyright: if rp is oldrp: rp.copyright = attrdict.get('copyright') changed = 1 elif rp.copyright: attrdict['copyright'] = rp.copyright elif attrdict.has_key('copyright'): del attrdict['copyright'] title = MMAttrdefs.getattr(node, 'title') if title != rp.title: if rp is oldrp: rp.title = attrdict.get('title') changed = 1 elif rp.title: attrdict['title'] = rp.title elif attrdict.has_key('title'): del attrdict['title'] href = MMAttrdefs.getattr(node, 'href') if href != rp.url: if rp is oldrp: rp.url = attrdict.get('href') changed = 1 elif rp.url: attrdict['href'] = rp.url elif attrdict.has_key('href'): del attrdict['href'] maxfps = MMAttrdefs.getattr(node, 'maxfps') if maxfps != rp.maxfps: if rp is oldrp: rp.maxfps = maxfps changed = 1 elif rp.maxfps is not None: attrdict['maxfps'] = rp.maxfps elif attrdict.has_key('maxfps'): del attrdict['maxfps'] preroll = MMAttrdefs.getattr(node, 'preroll') if preroll != rp.preroll: if rp is oldrp: rp.preroll = preroll changed = 1 elif rp.preroll is not None: attrdict['preroll'] = rp.preroll elif attrdict.has_key('preroll'): del attrdict['preroll'] if hasattr(node, 'expanded'): if oldrp is rp: i = 0 children = node.children nchildren = len(children) taglist = rp.tags ntags = len(taglist) rp.tags = [] nnodes = max(ntags, nchildren) while i < nnodes: if i < nchildren: childattrs = children[i].attrdict rp.tags.append(childattrs.copy()) else: changed = 1 childattrs = None if i < ntags: attrs = taglist[i] else: changed = 1 attrs = None if childattrs != attrs: changed = 1 i = i + 1 ## else: ## # re-create children ## import HierarchyView ## HierarchyView.collapsenode(node) ## HierarchyView.expandnode(node) if changed: if not hasattr(node, 'tmpfile'): url = MMAttrdefs.getattr(node, 'file') url = node.context.findurl(url) ## if not url: ## windowinterface.showmessage('specify a location for this node') ## return utype, host, path, params, query, fragment = urlparse.urlparse(url) if (utype and utype != 'file') or \ (host and host != 'localhost'): windowinterface.showmessage('Cannot edit remote RealPix files.') return import tempfile pre = tempfile.gettempprefix() dir = os.path.dirname(MMurl.url2pathname(path)) while 1: tempfile.counter = tempfile.counter + 1 file = os.path.join(dir, pre+`tempfile.counter`+'.rp') if not os.path.exists(file): break node.tmpfile = file if not SlideShow.__callback_added: windowinterface.addclosecallback( deltmpfiles, ()) SlideShow.__callback_added = 1 SlideShow.tmpfiles.append(file) ## import realsupport ## realsupport.writeRP(node.tmpfile, rp, node) MMAttrdefs.flushcache(node)
def __init__(self, node, new_file = 0): if node is None: # special case, only used in copy method return if node.GetType() != 'ext' or \ node.GetChannelType() != 'RealPix': raise RuntimeError("shouldn't happen") update = 0 self.node = node import realsupport ctx = node.GetContext() url = MMAttrdefs.getattr(node, 'file') if not url: name = MMAttrdefs.getattr(node, 'name') or '<unnamed>' cname = node.GetChannelName() windowinterface.showmessage('No URL specified for slideshow node %s on channel %s' % (name, cname), mtype = 'warning') rp = DummyRP() else: ourl = url url = ctx.findurl(url) utype, host, path, params, query, tag = urlparse.urlparse(url) url = urlparse.urlunparse((utype, host, path, params, query, '')) self.url = url fp = None is_data = utype == 'data' if new_file and type(new_file) == type(''): url = MMurl.basejoin(new_file, ourl) if is_data: file = None baseurl = new_file else: file = baseurl = url try: self.filename = url fp = MMurl.urlopen(url) rp = realsupport.RPParser(file, baseurl = baseurl, printfunc = self.printfunc) rp.feed(fp.read()) rp.close() fp.close() update = 1 # zap the URL so that the # template doesn't get # overwritten node.DelAttr('file') url = self.url = '' except: pass url = self.url else: if is_data: file = None baseurl = '' else: file = url baseurl = ourl try: self.filename = url fp = MMurl.urlopen(url) rp = realsupport.RPParser(file, baseurl = baseurl, printfunc = self.printfunc) rp.feed(fp.read()) rp.close() fp.close() except: windowinterface.showmessage('Cannot read slideshow file with URL %s in node %s on channel %s' % (url, MMAttrdefs.getattr(node, 'name') or '<unnamed>', node.GetChannelName()), mtype = 'warning') rp = DummyRP() if fp is not None: fp.close() if is_data: # zap the URL for "immediate" RP files node.DelAttr('file') self.url = url = '' self.url = url self.rp = rp attrdict = node.GetAttrDict() attrdict['bitrate'] = rp.bitrate if rp.width == 0 and rp.height == 0: # no size specified, initialize with channel size rp.width, rp.height = node.GetChannel().get('base_winoff',(0,0,256,256))[2:4] attrdict['size'] = rp.width, rp.height attrdict['duration'] = rp.duration if rp.aspect != 'true': attrdict['aspect'] = 0 if rp.author is not None: attrdict['author'] = rp.author if rp.copyright is not None: attrdict['copyright'] = rp.copyright if rp.maxfps is not None: attrdict['maxfps'] = rp.maxfps if rp.preroll is not None: attrdict['preroll'] = rp.preroll if rp.title is not None: attrdict['title'] = rp.title if rp.url is not None: attrdict['href'] = rp.url if rp.url not in ctx.externalanchors: ctx.externalanchors.append(rp.url) for tag in rp.tags: if tag.has_key('href') and tag['href'] and \ tag['href'] not in ctx.externalanchors: ctx.externalanchors.append(tag['href']) ctx.register(self) # *must* come first if update: self.update(changed = 1)
def rpconvert(node, errorfunc = None): # convert a RealPix node into a par node with children, # together representing the RealPix node ctx = node.GetContext() # check that node is a RealPix node furl = node.GetAttr('file') if node.GetType() != 'ext' or not furl: if errorfunc is not None: errorfunc('not a RealPix node') return ch = node.GetChannel() if not ch: if errorfunc is not None: errorfunc('no region associated with node') return url = ctx.findurl(furl) if furl[:5] == 'data:': furl = '' try: f = MMurl.urlopen(url) except IOError: if errorfunc is not None: errorfunc('cannot open RealPix file') return head = f.read(4) if head != '<imf': if errorfunc is not None: errorfunc('not a RealPix file') f.close() return # parse the RealPix file, result in rp rp = realsupport.RPParser(url) rp.feed(head) rp.feed(f.read()) f.close() rp.close() region = ch.GetLayoutChannel() regionname = region.name em = ctx.editmgr if not em.transaction(): # not allowed to do it at this point return ctx.attributes['project_boston'] = 1 # It's definitely a SMIL 2.0 document now # convert the ext node to a par node em.setnodeattr(node, 'file', None) em.setnodetype(node, 'seq') em.setnodeattr(node, 'channel', None) em.setnodeattr(node, 'bgcolor', None) em.setnodeattr(node, 'transparent', None) if node.GetAttrDef('fill', 'default') == 'default' and node.GetInherAttrDef('fillDefault', 'inherit') == 'inherit': # make default fill behavior explicit em.setnodeattr(node, 'fill', node.GetFill()) em.setnodeattr(node, 'fillDefault', 'hold') ndur = node.GetAttrDef('duration', None) if ndur is None: ndur = rp.duration else: ndur = min(ndur, rp.duration) em.setnodeattr(node, 'duration', ndur) em.setchannelattr(regionname, 'chsubtype', None) # First deal with fadein transitions that specify an # associated fadeout. We just create an explicit fadeout for # these associated fadeouts, keeping the list of transitions # sorted (and the start attribute relative to the previous). # The result is a new list of transitions in tags. start = 0 i = 0 fadeouts = [] tags = [] for tagdict in rp.tags: prevstart = start start = start + tagdict['start'] while fadeouts: fodict = fadeouts[0] if fodict['start'] < start: tags.append(fodict) fodict['start'], prevstart = fodict['start'] - prevstart, fodict['start'] del fadeouts[0] else: break tagdict['start'] = start - prevstart tags.append(tagdict) if tagdict['tag'] == 'fadein' and tagdict.get('fadeout', 0): fodict = tagdict.copy() fodict['tag'] = 'fadeout' fodict['start'] = start + tagdict['fadeouttime'] fodict['tduration'] = tagdict['fadeoutduration'] fodict['color'] = tagdict['fadeoutcolor'] del fodict['fadeouttime'] del fodict['fadeoutduration'] del fodict['fadeout'] del fodict['fadeoutcolor'] for j in range(len(fadeouts)): if fadeouts[j]['start'] > fodict['start']: fadeouts.insert(j, fodict) break else: fadeouts.append(fodict) prevstart = start for fodict in fadeouts: tags.append(fodict) fodict['start'], prevstart = fodict['start'] - prevstart, fodict['start'] # width and height of the region # this had better be in pixels rw, rh = region.getPxGeom()[2:] i = 0 # used to create unique channel name start = 0 for tagdict in tags: transition = tagdict['tag'] start = tagdict.get('start', 0) + start if transition in ('viewchange', 'animate'): if errorfunc is not None: errorfunc("ignoring transition we can't convert") continue if transition in ('fadeout', 'fill'): chtype = 'brush' newnode = ctx.newnode('brush') em.addnode(node, -1, newnode) em.setnodeattr(newnode, 'fgcolor', tagdict['color']) else: chtype = 'image' newnode = ctx.newnode('ext') em.addnode(node, -1, newnode) em.setnodeattr(newnode, 'file', MMurl.basejoin(furl, tagdict['file'])) if tagdict.get('aspect', rp.aspect == 'true'): em.setnodeattr(newnode, 'fit', 'meet') else: em.setnodeattr(newnode, 'fit', 'fill') base = posixpath.splitext(posixpath.split(tagdict['file'])[1])[0] em.setnodeattr(newnode, 'name', base) # As this item comes from a RealPix file it should # be ready for Real playback em.setnodeattr(newnode, 'project_convert', 0) # calculate subregion positioning # first work in source (RealPix) coordinates if tagdict.get('displayfull', 0): x, y, w, h = 0, 0, rp.width, rp.height else: x, y = tagdict.get('subregionxy', (0, 0)) w, h = tagdict.get('subregionwh', (0, 0)) # they really default to the size of the window if w == 0: w = rp.width if h == 0: h = rp.height # if size too big, reduce to RealPix size if w > rp.width: w = rp.width if h > rp.height: h = rp.height # if the destination area doesn't fit, it is shifted up and left to make it fit if x + w > rp.width: x = rp.width - w if y + h > rp.height: y = rp.height - h # convert to destination (SMIL 2.0) coordinates x = int((float(x) / rp.width) * rw + 0.5) w = int((float(w) / rp.width) * rw + 0.5) y = int((float(y) / rp.height) * rh + 0.5) h = int((float(h) / rp.height) * rh + 0.5) em.setnodeattr(newnode, 'left', x) em.setnodeattr(newnode, 'top', y) em.setnodeattr(newnode, 'width', w) em.setnodeattr(newnode, 'height', h) em.setnodeattr(newnode, 'regPoint', 'center') em.setnodeattr(newnode, 'regAlign', 'center') # XXX to be compatible with RealPix, the background # should not be transparent and be transitioned in # together with the image. However, that's not so # easy in SMIL 2.0. We'd need a coordinated # transition of a brush to represent the background # and the image. For now, just use a transparent # background so that it isn't too ugly. em.setnodeattr(newnode, 'transparent', 1) em.setnodeattr(newnode, 'channel', regionname) em.addsyncarc(newnode, 'beginlist', MMSyncArc(newnode, 'begin', srcnode='syncbase', delay=start)) start = 0 if transition in ('fadein', 'fadeout', 'crossfade', 'wipe'): # the real transtions trdict = {'dur': tagdict.get('tduration', 0), # defaults ## 'direction': 'forward', ## 'startProgress': 0.0, ## 'endProgress': 1.0, ## 'horzRepeat': 1, ## 'vertRepeat': 1, ## 'borderWidth': 0, # removed from SMIL 2.0 ## 'coordinated': 0, ## 'clipBoundary': 'children', } if transition == 'wipe': dir = tagdict['direction'] if tagdict['wipetype'] == 'normal': trdict['trtype'] = 'barWipe' if dir == 'left': trdict['subtype'] = 'leftToRight' trdict['direction'] = 'reverse' elif dir == 'right': trdict['subtype'] = 'leftToRight' elif dir == 'up': trdict['subtype'] = 'topToBottom' trdict['direction'] = 'reverse' elif dir == 'down': trdict['subtype'] = 'topToBottom' else: trdict['trtype'] = 'pushWipe' if dir == 'left': trdict['subtype'] = 'fromRight' elif dir == 'right': trdict['subtype'] = 'fromLeft' elif dir == 'up': trdict['subtype'] = 'fromBottom' elif dir == 'down': trdict['subtype'] = 'fromTop' else: trdict['trtype'] = 'fade' # no point in doing zero-duration transitions if trdict['dur'] > 0: for trname, trval in ctx.transitions.items(): if trval == trdict: # found an existing transition that'll do break else: j = 0 trname = '%s %d' % (transition, j) while ctx.transitions.has_key(trname): j = j + 1 trname = '%s %d' % (transition, j) em.addtransition(trname, trdict) em.setnodeattr(newnode, 'transIn', [trname]) if tagdict.get('href'): anchor = ctx.newnode('anchor') em.addnode(newnode, -1, anchor) em.setnodeattr(anchor, 'sourcePlaystate', 'play') em.setnodeattr(anchor, 'destinationPlaystate', 'play') em.setnodeattr(anchor, 'show', 'new') em.addlink((anchor, tagdict['href'], DIR_1TO2)) em.commit()