add zapping history.. useable with < > buttons
[enigma2.git] / lib / python / Screens / InfoBarGenerics.py
1 from Screen import Screen
2 from Components.ActionMap import ActionMap, HelpableActionMap
3 from Components.ActionMap import NumberActionMap
4 from Components.Label import *
5 from Components.ProgressBar import *
6 from Components.config import configfile, configsequencearg
7 from Components.config import config, configElement, ConfigSubsection, configSequence
8 from ChannelSelection import ChannelSelection, BouquetSelector
9
10 from Components.Pixmap import Pixmap, PixmapConditional
11 from Components.BlinkingPixmap import BlinkingPixmapConditional
12 from Components.ServiceName import ServiceName
13 from Components.EventInfo import EventInfo, EventInfoProgress
14
15 from ServiceReference import ServiceReference
16 from EpgSelection import EPGSelection
17
18 from Screens.MessageBox import MessageBox
19 from Screens.Dish import Dish
20 from Screens.Standby import Standby
21 from Screens.EventView import EventViewEPGSelect
22 from Screens.MinuteInput import MinuteInput
23 from Components.Harddisk import harddiskmanager
24
25 from Components.ServiceEventTracker import ServiceEventTracker
26
27 from Tools import Notifications
28 from Tools.Directories import *
29
30 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
31 from enigma import *
32
33 import time
34 import os
35 import bisect
36
37 from Components.config import config, currentConfigSelectionElement
38
39 # hack alert!
40 from Menu import MainMenu, mdom
41
42 class InfoBarDish:
43         def __init__(self):
44                 self.dishDialog = self.session.instantiateDialog(Dish)
45                 self.onLayoutFinish.append(self.dishDialog.show)
46
47 class InfoBarShowHide:
48         """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
49         fancy animations. """
50         STATE_HIDDEN = 0
51         STATE_HIDING = 1
52         STATE_SHOWING = 2
53         STATE_SHOWN = 3
54         
55         def __init__(self):
56                 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
57                         {
58                                 "toggleShow": self.toggleShow,
59                                 "hide": self.hide,
60                         })
61
62                 self.__state = self.STATE_SHOWN
63                 self.__locked = 0
64                 
65                 self.onExecBegin.append(self.show)
66                 
67                 self.hideTimer = eTimer()
68                 self.hideTimer.timeout.get().append(self.doTimerHide)
69                 self.hideTimer.start(5000, True)
70                 
71                 self.onShow.append(self.__onShow)
72                 self.onHide.append(self.__onHide)
73
74         def __onShow(self):
75                 self.__state = self.STATE_SHOWN
76                 self.startHideTimer()
77         
78         def startHideTimer(self):
79                 if self.__state == self.STATE_SHOWN and not self.__locked:
80                         self.hideTimer.start(5000, True)
81
82         def __onHide(self):
83                 self.__state = self.STATE_HIDDEN
84
85         def doShow(self):
86                 self.show()
87                 self.startHideTimer()
88
89         def doTimerHide(self):
90                 self.hideTimer.stop()
91                 if self.__state == self.STATE_SHOWN:
92                         self.hide()
93
94         def toggleShow(self):
95                 if self.__state == self.STATE_SHOWN:
96                         self.hide()
97                         self.hideTimer.stop()
98                 elif self.__state == self.STATE_HIDDEN:
99                         self.show()
100
101         def lockShow(self):
102                 self.__locked = self.__locked + 1
103                 if self.execing:
104                         self.show()
105                         self.hideTimer.stop()
106         
107         def unlockShow(self):
108                 self.__locked = self.__locked - 1
109                 if self.execing:
110                         self.startHideTimer()
111
112 #       def startShow(self):
113 #               self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
114 #               self.__state = self.STATE_SHOWN
115 #       
116 #       def startHide(self):
117 #               self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
118 #               self.__state = self.STATE_HIDDEN
119
120 class NumberZap(Screen):
121         def quit(self):
122                 self.Timer.stop()
123                 self.close(0)
124
125         def keyOK(self):
126                 self.Timer.stop()
127                 self.close(int(self["number"].getText()))
128
129         def keyNumberGlobal(self, number):
130                 self.Timer.start(3000, True)            #reset timer
131                 self.field = self.field + str(number)
132                 self["number"].setText(self.field)
133                 if len(self.field) >= 4:
134                         self.keyOK()
135
136         def __init__(self, session, number):
137                 Screen.__init__(self, session)
138                 self.field = str(number)
139
140                 self["channel"] = Label(_("Channel:"))
141
142                 self["number"] = Label(self.field)
143
144                 self["actions"] = NumberActionMap( [ "SetupActions" ], 
145                         {
146                                 "cancel": self.quit,
147                                 "ok": self.keyOK,
148                                 "1": self.keyNumberGlobal,
149                                 "2": self.keyNumberGlobal,
150                                 "3": self.keyNumberGlobal,
151                                 "4": self.keyNumberGlobal,
152                                 "5": self.keyNumberGlobal,
153                                 "6": self.keyNumberGlobal,
154                                 "7": self.keyNumberGlobal,
155                                 "8": self.keyNumberGlobal,
156                                 "9": self.keyNumberGlobal,
157                                 "0": self.keyNumberGlobal
158                         })
159
160                 self.Timer = eTimer()
161                 self.Timer.timeout.get().append(self.keyOK)
162                 self.Timer.start(3000, True)
163
164 class InfoBarPowerKey:
165         """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
166         
167         def __init__(self):
168                 self.powerKeyTimer = eTimer()
169                 self.powerKeyTimer.timeout.get().append(self.powertimer)
170                 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
171                         {
172                                 "powerdown": self.powerdown,
173                                 "powerup": self.powerup,
174                                 "discreteStandby": (self.standby, "Go standby"),
175                                 "discretePowerOff": (self.quit, "Go to deep standby"),
176                         })
177
178         def powertimer(self):   
179                 print "PowerOff - Now!"
180                 self.quit()
181         
182         def powerdown(self):
183                 self.standbyblocked = 0
184                 self.powerKeyTimer.start(3000, True)
185
186         def powerup(self):
187                 self.powerKeyTimer.stop()
188                 if self.standbyblocked == 0:
189                         self.standbyblocked = 1
190                         self.standby()
191
192         def standby(self):
193                 self.session.open(Standby, self)
194
195         def quit(self):
196                 # halt
197                 quitMainloop(1)
198
199 class InfoBarNumberZap:
200         """ Handles an initial number for NumberZapping """
201         def __init__(self):
202                 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
203                         {
204                                 "1": self.keyNumberGlobal,
205                                 "2": self.keyNumberGlobal,
206                                 "3": self.keyNumberGlobal,
207                                 "4": self.keyNumberGlobal,
208                                 "5": self.keyNumberGlobal,
209                                 "6": self.keyNumberGlobal,
210                                 "7": self.keyNumberGlobal,
211                                 "8": self.keyNumberGlobal,
212                                 "9": self.keyNumberGlobal,
213                                 "0": self.keyNumberGlobal,
214                         })
215
216         def keyNumberGlobal(self, number):
217 #               print "You pressed number " + str(number)
218                 if number == 0:
219                         self.servicelist.recallPrevService()
220                         self.doShow()
221                 else:
222                         self.session.openWithCallback(self.numberEntered, NumberZap, number)
223
224         def numberEntered(self, retval):
225 #               print self.servicelist
226                 if retval > 0:
227                         self.zapToNumber(retval)
228
229         def searchNumberHelper(self, serviceHandler, num, bouquet):
230                 servicelist = serviceHandler.list(bouquet)
231                 if not servicelist is None:
232                         while num:
233                                 serviceIterator = servicelist.getNext()
234                                 if not serviceIterator.valid(): #check end of list
235                                         break
236                                 if serviceIterator.flags: #assume normal dvb service have no flags set
237                                         continue
238                                 num -= 1;
239                         if not num: #found service with searched number ?
240                                 return serviceIterator, 0
241                 return None, num
242
243         def zapToNumber(self, number):
244                 bouquet = self.servicelist.bouquet_root
245                 service = None
246                 serviceHandler = eServiceCenter.getInstance()
247                 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
248                         service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
249                 else:
250                         bouquetlist = serviceHandler.list(bouquet)
251                         if not bouquetlist is None:
252                                 while number:
253                                         bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
254                                         if not bouquet.valid(): #check end of list
255                                                 break
256                                         if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
257                                                 continue
258                                         service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
259                 if not service is None:
260                         if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
261                                 self.servicelist.clearPath()
262                                 if self.servicelist.bouquet_root != bouquet:
263                                         self.servicelist.enterPath(self.servicelist.bouquet_root)
264                                 self.servicelist.enterPath(bouquet)
265                         self.servicelist.setCurrentSelection(service) #select the service in servicelist
266                         self.servicelist.zap()
267
268 class InfoBarChannelSelection:
269         """ ChannelSelection - handles the channelSelection dialog and the initial 
270         channelChange actions which open the channelSelection dialog """
271         def __init__(self):
272                 #instantiate forever
273                 self.servicelist = self.session.instantiateDialog(ChannelSelection)
274
275                 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
276                         {
277                                 "switchChannelUp": self.switchChannelUp,
278                                 "switchChannelDown": self.switchChannelDown,
279                                 "zapUp": (self.zapUp, _("next channel")),
280                                 "zapDown": (self.zapDown, _("previous channel")),
281                                 "historyBack": (self.historyBack, _("previous channel in history")),
282                                 "historyNext": (self.historyNext, _("next channel in history"))
283                         })
284
285         def historyBack(self):
286                 self.servicelist.historyBack()
287
288         def historyNext(self):
289                 self.servicelist.historyNext()
290
291         def switchChannelUp(self):
292                 self.servicelist.moveUp()
293                 self.session.execDialog(self.servicelist)
294
295         def switchChannelDown(self):
296                 self.servicelist.moveDown()
297                 self.session.execDialog(self.servicelist)
298
299         def zapUp(self):
300                 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
301                         if self.servicelist.inBouquet() and self.servicelist.atBegin():
302                                 self.servicelist.prevBouquet()
303                 self.servicelist.moveUp()
304                 self.servicelist.zap()
305                 self.doShow()
306
307         def zapDown(self):
308                 if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
309                         self.servicelist.nextBouquet()
310                 else:
311                         self.servicelist.moveDown()
312                 self.servicelist.zap()
313                 self.doShow()
314
315 class InfoBarMenu:
316         """ Handles a menu action, to open the (main) menu """
317         def __init__(self):
318                 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions", 
319                         {
320                                 "mainMenu": (self.mainMenu, "Enter main menu..."),
321                         })
322
323         def mainMenu(self):
324                 print "loading mainmenu XML..."
325                 menu = mdom.childNodes[0]
326                 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
327                 self.session.open(MainMenu, menu, menu.childNodes)
328
329 class InfoBarEPG:
330         """ EPG - Opens an EPG list when the showEPGList action fires """
331         def __init__(self):
332                 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
333                         {
334                                 "showEventInfo": (self.openEventView, _("show EPG...")),
335                         })
336
337         def zapToService(self, service):
338                 if not service is None:
339                         if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
340                                 self.servicelist.clearPath()
341                                 if self.servicelist.bouquet_root != self.epg_bouquet:
342                                         self.servicelist.enterPath(self.servicelist.bouquet_root)
343                                 self.servicelist.enterPath(self.epg_bouquet)
344                         self.servicelist.setCurrentSelection(service) #select the service in servicelist
345                         self.servicelist.zap()
346
347         def openBouquetEPG(self, bouquet):
348                 ptr=eEPGCache.getInstance()
349                 services = [ ]
350                 servicelist = eServiceCenter.getInstance().list(bouquet)
351                 if not servicelist is None:
352                         while True:
353                                 service = servicelist.getNext()
354                                 if not service.valid(): #check if end of list
355                                         break
356                                 if service.flags: #ignore non playable services
357                                         continue
358                                 services.append(ServiceReference(service))
359                 if len(services):
360                         self.epg_bouquet = bouquet
361                         self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
362
363         def closed(self, ret):
364                 if ret:
365                         self.close(ret)
366
367         def openMultiServiceEPG(self):
368                 bouquets = self.servicelist.getBouquetList()
369                 if bouquets is None:
370                         cnt = 0
371                 else:
372                         cnt = len(bouquets)
373                 if cnt > 1: # show bouquet list
374                         self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
375                 elif cnt == 1: 
376                         self.openBouquetEPG(bouquets[0][1])
377
378         def openSingleServiceEPG(self):
379                 ref=self.session.nav.getCurrentlyPlayingServiceReference()
380                 ptr=eEPGCache.getInstance()
381                 self.session.openWithCallback(self.closed, EPGSelection, ref)
382
383         def openEventView(self):
384                 self.epglist = [ ]
385                 service = self.session.nav.getCurrentService()
386                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
387                 info = service.info()
388                 ptr=info.getEvent(0)
389                 if ptr:
390                         self.epglist.append(ptr)
391                 ptr=info.getEvent(1)
392                 if ptr:
393                         self.epglist.append(ptr)
394                 if len(self.epglist) == 0:
395                         epg = eEPGCache.getInstance()
396                         ptr = epg.lookupEventTime(ref, -1)
397                         if ptr:
398                                 self.epglist.append(ptr)
399                                 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
400                                 if ptr:
401                                         self.epglist.append(ptr)
402                 if len(self.epglist) > 0:
403                         self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
404                 else:
405                         print "no epg for the service avail.. so we show multiepg instead of eventinfo"
406                         self.openMultiServiceEPG()
407
408         def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
409                 if len(self.epglist) > 1:
410                         tmp = self.epglist[0]
411                         self.epglist[0]=self.epglist[1]
412                         self.epglist[1]=tmp
413                         setEvent(self.epglist[0])
414
415 from math import log
416
417 class InfoBarTuner:
418         """provides a snr/agc/ber display"""
419         def __init__(self):
420                 self["snr"] = Label()
421                 self["agc"] = Label()
422                 self["ber"] = Label()
423                 self["snr_percent"] = Label()
424                 self["agc_percent"] = Label()
425                 self["ber_count"] = Label()
426                 self["snr_progress"] = ProgressBar()
427                 self["agc_progress"] = ProgressBar()
428                 self["ber_progress"] = ProgressBar()
429                 self.timer = eTimer()
430                 self.timer.timeout.get().append(self.updateTunerInfo)
431                 self.timer.start(1000)
432
433         def calc(self,val):
434                 if not val:
435                         return 0
436                 if val < 2500:
437                         return (long)(log(val)/log(2))
438                 return val*100/65535
439
440         def updateTunerInfo(self):
441                 if self.instance.isVisible():
442                         service = self.session.nav.getCurrentService()
443                         snr=0
444                         agc=0
445                         ber=0
446                         if service is not None:
447                                 feinfo = service.frontendStatusInfo()
448                                 if feinfo is not None:
449                                         ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
450                                         snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
451                                         agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
452                         self["snr_percent"].setText("%d%%"%(snr))
453                         self["agc_percent"].setText("%d%%"%(agc))
454                         self["ber_count"].setText("%d"%(ber))
455                         self["snr_progress"].setValue(snr)
456                         self["agc_progress"].setValue(agc)
457                         self["ber_progress"].setValue(self.calc(ber))
458
459 class InfoBarEvent:
460         """provides a current/next event info display"""
461         def __init__(self):
462                 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
463                 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
464                                 
465                 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
466                 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
467
468                 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
469                 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
470
471                 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
472
473 class InfoBarServiceName:
474         def __init__(self):
475                 self["ServiceName"] = ServiceName(self.session.nav)
476
477 class InfoBarSeek:
478         """handles actions like seeking, pause"""
479         
480         # ispause, isff, issm
481         SEEK_STATE_PLAY = (0, 0, 0, ">")
482         SEEK_STATE_PAUSE = (1, 0, 0, "||")
483         SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
484         SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
485         SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
486         SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
487         SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
488         SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
489         
490         SEEK_STATE_BACK_4X = (0, -4, 0, "<< 4x")
491         SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
492         SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
493         SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
494         
495         SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
496         SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
497         SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
498         
499         def __init__(self):
500                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
501                         {
502                                 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
503                                 iPlayableService.evStart: self.__serviceStarted,
504                                 
505                                 iPlayableService.evEOF: self.__evEOF,
506                                 iPlayableService.evSOF: self.__evSOF,
507                         })
508                 self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions", 
509                         {
510                                 "pauseService": (self.pauseService, "pause"),
511                                 "unPauseService": (self.unPauseService, "continue"),
512                                 
513                                 "seekFwd": (self.seekFwd, "skip forward"),
514                                 "seekFwdUp": (self.seekFwdUp, "skip forward"),
515                                 "seekBack": (self.seekBack, "skip backward"),
516                                 "seekBackUp": (self.seekBackUp, "skip backward"),
517                         }, prio=-1)
518                         # give them a little more priority to win over color buttons
519
520                 self.seekstate = self.SEEK_STATE_PLAY
521                 self.onClose.append(self.delTimer)
522                 
523                 self.fwdtimer = False
524                 self.fwdKeyTimer = eTimer()
525                 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
526
527                 self.rwdtimer = False
528                 self.rwdKeyTimer = eTimer()
529                 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
530                 
531                 self.onPlayStateChanged = [ ]
532                 
533                 self.lockedBecauseOfSkipping = False
534         
535         def up(self):
536                 pass
537         
538         def down(self):
539                 pass
540         
541         def delTimer(self):
542                 del self.fwdKeyTimer
543                 del self.rwdKeyTimer
544         
545         def getSeek(self):
546                 service = self.session.nav.getCurrentService()
547                 if service is None:
548                         return False
549
550                 seek = service.seek()
551
552                 if seek is None or not seek.isCurrentlySeekable():
553                         return None
554                 
555                 return seek
556         
557         def isSeekable(self):
558                 if self.getSeek() is None:
559                         return False
560                 return True
561
562         def __seekableStatusChanged(self):
563                 print "seekable status changed!"
564                 if not self.isSeekable():
565                         self["SeekActions"].setEnabled(False)
566                         print "not seekable, return to play"
567                         self.setSeekState(self.SEEK_STATE_PLAY)
568                 else:
569                         self["SeekActions"].setEnabled(True)
570                         print "seekable"
571
572         def __serviceStarted(self):
573                 self.seekstate = self.SEEK_STATE_PLAY
574
575         def setSeekState(self, state):
576                 service = self.session.nav.getCurrentService()
577                 
578                 if service is None:
579                         return False
580                 
581                 if not self.isSeekable():
582                         if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
583                                 state = self.SEEK_STATE_PLAY
584                 
585                 pauseable = service.pause()
586
587                 if pauseable is None:
588                         print "not pauseable."
589                         state = self.SEEK_STATE_PLAY
590                 
591                 oldstate = self.seekstate
592                 self.seekstate = state
593                 
594                 for i in range(3):
595                         if oldstate[i] != self.seekstate[i]:
596                                 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
597
598                 for c in self.onPlayStateChanged:
599                         c(self.seekstate)
600                 
601                 self.checkSkipShowHideLock()
602
603                 return True
604                 
605         def pauseService(self):
606                 if self.seekstate == self.SEEK_STATE_PAUSE:
607                         print "pause, but in fact unpause"
608                         self.unPauseService()
609                 else:
610                         if self.seekstate == self.SEEK_STATE_PLAY:
611                                 print "yes, playing."
612                         else:
613                                 print "no", self.seekstate
614                         print "pause"
615                         self.setSeekState(self.SEEK_STATE_PAUSE);
616                 
617         def unPauseService(self):
618                 print "unpause"
619                 self.setSeekState(self.SEEK_STATE_PLAY);
620         
621         def doSeek(self, seektime):
622                 print "doseek", seektime
623                 service = self.session.nav.getCurrentService()
624                 if service is None:
625                         return
626                 
627                 seekable = self.getSeek()
628                 if seekable is None:
629                         return
630                 
631                 seekable.seekTo(90 * seektime)
632
633         def seekFwd(self):
634                 print "start fwd timer"
635                 self.fwdtimer = True
636                 self.fwdKeyTimer.start(500)
637
638         def seekBack(self):
639                 print "start rewind timer"
640                 self.rwdtimer = True
641                 self.rwdKeyTimer.start(500)
642
643         def seekFwdUp(self):
644                 print "seekFwdUp"
645                 if self.fwdtimer:
646                         self.fwdKeyTimer.stop()
647                         self.fwdtimer = False
648                         lookup = {
649                                         self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
650                                         self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
651                                         self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
652                                         self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
653                                         self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
654                                         self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
655                                         self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
656                                         self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
657                                         self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
658                                         self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
659                                         self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
660                                         self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
661                                         self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
662                                         self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
663                                         self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
664                                 }
665                         self.setSeekState(lookup[self.seekstate]);
666         
667         def seekBackUp(self):
668                 print "seekBackUp"
669                 if self.rwdtimer:
670                         self.rwdKeyTimer.stop()
671                         self.rwdtimer = False
672                 
673                         lookup = {
674                                         self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
675                                         self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
676                                         self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
677                                         self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
678                                         self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
679                                         self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
680                                         self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
681                                         self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
682                                         self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
683                                         self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
684                                         self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
685                                         self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
686                                         self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
687                                         self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
688                                         self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
689                                 }
690                         self.setSeekState(lookup[self.seekstate]);
691                 
692         def fwdTimerFire(self):
693                 print "Display seek fwd"
694                 self.fwdKeyTimer.stop()
695                 self.fwdtimer = False
696                 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
697                 
698         def fwdSeekTo(self, minutes):
699                 print "Seek", minutes, "minutes forward"
700                 if minutes != 0:
701                         seekable = self.getSeek()
702                         if seekable is not None:
703                                 seekable.seekRelative(1, minutes * 60 * 90000)
704         
705         def rwdTimerFire(self):
706                 print "rwdTimerFire"
707                 self.rwdKeyTimer.stop()
708                 self.rwdtimer = False
709                 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
710         
711         def rwdSeekTo(self, minutes):
712                 print "rwdSeekTo"
713                 self.fwdSeekTo(0 - minutes)
714         
715         def checkSkipShowHideLock(self):
716                 wantlock = self.seekstate != self.SEEK_STATE_PLAY
717                 
718                 if self.lockedBecauseOfSkipping and not wantlock:
719                         self.unlockShow()
720                         self.lockedBecauseOfSkipping = False
721                 
722                 if wantlock and not self.lockedBecauseOfSkipping:
723                         self.lockShow()
724                         self.lockedBecauseOfSkipping = True
725
726         def __evEOF(self):
727                 self.setSeekState(self.SEEK_STATE_PAUSE)
728         
729         def __evSOF(self):
730                 self.setSeekState(self.SEEK_STATE_PLAY)
731                 self.doSeek(0)
732
733         def seekRelative(self, diff):
734                 seekable = self.getSeek()
735                 if seekable is not None:
736                         seekable.seekRelative(0, diff)
737
738 from Screens.PVRState import PVRState
739
740 class InfoBarPVRState:
741         def __init__(self):
742                 self.onPlayStateChanged.append(self.__playStateChanged)
743                 self.pvrStateDialog = self.session.instantiateDialog(PVRState)
744                 self.onShow.append(self.__mayShow)
745                 self.onHide.append(self.pvrStateDialog.hide)
746         
747         def __mayShow(self):
748                 if self.seekstate != self.SEEK_STATE_PLAY:
749                         self.pvrStateDialog.show()
750
751         def __playStateChanged(self, state):
752                 playstateString = state[3]
753                 self.pvrStateDialog["state"].setText(playstateString)
754                 self.__mayShow()
755
756 class InfoBarShowMovies:
757
758         # i don't really like this class. 
759         # it calls a not further specified "movie list" on up/down/movieList,
760         # so this is not more than an action map
761         def __init__(self):
762                 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions", 
763                         {
764                                 "movieList": (self.showMovies, "movie list"),
765                                 "up": (self.showMovies, "movie list"),
766                                 "down": (self.showMovies, "movie list")
767                         })
768
769 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
770
771 # Hrmf.
772 #
773 # Timeshift works the following way:
774 #                                         demux0   demux1                    "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
775 # - normal playback                       TUNER    unused      PLAY               enable                disable              disable
776 # - user presses "yellow" button.         TUNER    record      PAUSE              enable                disable              enable
777 # - user presess pause again              FILE     record      PLAY               enable                disable              enable
778 # - user fast forwards                    FILE     record      FF                 enable                disable              enable
779 # - end of timeshift buffer reached       TUNER    record      PLAY               enable                enable               disable
780 # - user backwards                        FILE     record      BACK  # !!         enable                disable              enable
781 #
782
783 # in other words:
784 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
785 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
786 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
787 # - the user can now PVR around
788 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
789 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
790 # after!
791 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
792 # - if the user rewinds, or press pause, timeshift will be activated again
793
794 # note that a timeshift can be enabled ("recording") and
795 # activated (currently time-shifting).
796
797 class InfoBarTimeshift:
798         def __init__(self):
799                 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions", 
800                         {
801                                 "timeshiftStart": (self.startTimeshift, "start timeshift"),  # the "yellow key"
802                                 "timeshiftStop": (self.stopTimeshift, "stop timeshift")      # currently undefined :), probably 'TV'
803                         }, prio=1)
804                 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
805                         {
806                                 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
807                                 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause  # something like "backward key"
808                         }, prio=-1) # priority over record
809
810                 self.timeshift_enabled = 0
811                 self.timeshift_state = 0
812                 self.ts_pause_timer = eTimer()
813                 self.ts_pause_timer.timeout.get().append(self.pauseService)
814
815                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
816                         {
817                                 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
818                         })
819         
820         def getTimeshift(self):
821                 service = self.session.nav.getCurrentService()
822                 return service.timeshift()
823
824         def startTimeshift(self):
825                 print "enable timeshift"
826                 ts = self.getTimeshift()
827                 if ts is None:
828                         self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
829                         print "no ts interface"
830                         return
831                 
832                 if self.timeshift_enabled:
833                         print "hu, timeshift already enabled?"
834                 else:
835                         if not ts.startTimeshift():
836                                 self.timeshift_enabled = 1
837                                 
838                                 # PAUSE.
839                                 self.setSeekState(self.SEEK_STATE_PAUSE)
840                                 
841                                 # enable the "TimeshiftEnableActions", which will override
842                                 # the startTimeshift actions
843                                 self.__seekableStatusChanged()
844                         else:
845                                 print "timeshift failed"
846
847         def stopTimeshift(self):
848                 if not self.timeshift_enabled:
849                         return
850                 print "disable timeshift"
851                 ts = self.getTimeshift()
852                 if ts is None:
853                         return
854                 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
855
856         def stopTimeshiftConfirmed(self, confirmed):
857                 if not confirmed:
858                         return
859
860                 ts = self.getTimeshift()
861                 if ts is None:
862                         return
863
864                 ts.stopTimeshift()
865                 self.timeshift_enabled = 0
866
867                 # disable actions
868                 self.__seekableStatusChanged()
869         
870         # activates timeshift, and seeks to (almost) the end
871         def activateTimeshiftEnd(self):
872                 ts = self.getTimeshift()
873                 
874                 if ts is None:
875                         return
876                 
877                 if ts.isTimeshiftActive():
878                         print "!! activate timeshift called - but shouldn't this be a normal pause?"
879                         self.pauseService()
880                 else:
881                         self.setSeekState(self.SEEK_STATE_PLAY)
882                         ts.activateTimeshift()
883                         self.seekRelative(0)
884         
885         # same as activateTimeshiftEnd, but pauses afterwards.
886         def activateTimeshiftEndAndPause(self):
887                 state = self.seekstate
888                 self.activateTimeshiftEnd()
889                 
890                 # well, this is "andPause", but it could be pressed from pause,
891                 # when pausing on the (fake-)"live" picture, so an un-pause
892                 # is perfectly ok.
893                 
894                 print "now, pauseService"
895                 if state == self.SEEK_STATE_PLAY:
896                         print "is PLAYING, start pause timer"
897                         self.ts_pause_timer.start(200, 1)
898                 else:
899                         print "unpause"
900                         self.unPauseService()
901         
902         def __seekableStatusChanged(self):
903                 enabled = False
904                 
905                 print "self.isSeekable", self.isSeekable()
906                 print "self.timeshift_enabled", self.timeshift_enabled
907                 
908                 # when this service is not seekable, but timeshift
909                 # is enabled, this means we can activate
910                 # the timeshift
911                 if not self.isSeekable() and self.timeshift_enabled:
912                         enabled = True
913
914                 print "timeshift activate:", enabled
915                 self["TimeshiftActivateActions"].setEnabled(enabled)
916
917 from RecordTimer import parseEvent
918
919 class InfoBarInstantRecord:
920         """Instant Record - handles the instantRecord action in order to 
921         start/stop instant records"""
922         def __init__(self):
923                 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
924                         {
925                                 "instantRecord": (self.instantRecord, "Instant Record..."),
926                         })
927                 self.recording = None
928                 self["BlinkingPoint"] = BlinkingPixmapConditional()
929                 self.onLayoutFinish.append(self["BlinkingPoint"].hideWidget)
930                 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
931
932         def stopCurrentRecording(self): 
933                 self.session.nav.RecordTimer.removeEntry(self.recording)
934                 self.recording = None
935
936         def startInstantRecording(self):
937                 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
938                 
939                 # try to get event info
940                 event = None
941                 try:
942                         service = self.session.nav.getCurrentService()
943                         info = service.info()
944                         ev = info.getEvent(0)
945                         event = ev
946                 except:
947                         pass
948                 
949                 if event is not None:
950                         data = parseEvent(event)
951                         begin = time.time()
952                         end = begin + 3600 * 10
953                         
954                         data = (begin, end, data[2], data[3], data[4])
955                 else:
956                         data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
957                 
958                 # fix me, description. 
959                 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
960                 self.recording.dontSave = True
961                 
962                 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
963                 
964         def isInstantRecordRunning(self):
965                 if self.recording != None:
966                         if self.recording.isRunning():
967                                 return True
968                 return False
969
970         def recordQuestionCallback(self, answer):
971                 if answer == False:
972                         return
973                 
974                 if self.isInstantRecordRunning():
975                         self.stopCurrentRecording()
976                 else:
977                         self.startInstantRecording()
978
979         def instantRecord(self):
980                 try:
981                         stat = os.stat(resolveFilename(SCOPE_HDD))
982                 except:
983                         self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
984                         return
985         
986                 if self.isInstantRecordRunning():
987                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
988                 else:
989                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
990
991 from Screens.AudioSelection import AudioSelection
992
993 class InfoBarAudioSelection:
994         def __init__(self):
995                 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", 
996                         {
997                                 "audioSelection": (self.audioSelection, "Audio Options..."),
998                         })
999
1000         def audioSelection(self):
1001                 service = self.session.nav.getCurrentService()
1002                 audio = service.audioTracks()
1003                 n = audio.getNumberOfTracks()
1004                 if n > 0:
1005                         self.session.open(AudioSelection, audio)
1006
1007 from Screens.SubserviceSelection import SubserviceSelection
1008
1009 class InfoBarSubserviceSelection:
1010         def __init__(self):
1011                 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1012                         {
1013                                 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
1014                         })
1015
1016         def subserviceSelection(self):
1017                 service = self.session.nav.getCurrentService()
1018                 subservices = service.subServices()
1019                 n = subservices.getNumberOfSubservices()
1020                 if n > 0:
1021                         self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
1022
1023         def subserviceSelected(self, service):
1024                 if not service is None:
1025                         self.session.nav.playService(service)
1026
1027 class InfoBarAdditionalInfo:
1028         def __init__(self):
1029                 self["DolbyActive"] = Pixmap()
1030                 self["CryptActive"] = Pixmap()
1031                 self["FormatActive"] = Pixmap()
1032                 
1033                 self["ButtonRed"] = PixmapConditional(withTimer = False)
1034                 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1035                 self.onShown.append(self["ButtonRed"].update)
1036                 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1037                 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1038                 self.onShown.append(self["ButtonRedText"].update)
1039
1040                 self["ButtonGreen"] = Pixmap()
1041                 self["ButtonGreenText"] = Label(_("Subservices"))
1042
1043                 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1044                 self["ButtonYellow"].setConnect(lambda: False)
1045
1046                 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1047                 self["ButtonBlue"].setConnect(lambda: False)
1048
1049                 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1050
1051         def hideSubServiceIndication(self):
1052                 self["ButtonGreen"].hideWidget()
1053                 self["ButtonGreenText"].hide()
1054
1055         def showSubServiceIndication(self):
1056                 self["ButtonGreen"].showWidget()
1057                 self["ButtonGreenText"].show()
1058
1059         def checkFormat(self, service):
1060                 info = service.info()
1061                 if info is not None:
1062                         aspect = info.getInfo(iServiceInformation.sAspect)
1063                         if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1064                                 self["FormatActive"].showWidget()
1065                         else:
1066                                 self["FormatActive"].hideWidget()
1067
1068         def checkSubservices(self, service):
1069                 if service.subServices().getNumberOfSubservices() > 0:
1070                         self.showSubServiceIndication()
1071                 else:
1072                         self.hideSubServiceIndication()
1073
1074         def checkDolby(self, service):
1075                 # FIXME
1076                 dolby = False
1077                 audio = service.audioTracks()
1078                 if audio is not None:
1079                         n = audio.getNumberOfTracks()
1080                         for x in range(n):
1081                                 i = audio.getTrackInfo(x)
1082                                 description = i.getDescription();
1083                                 if description.find("AC3") != -1 or description.find("DTS") != -1:
1084                                         dolby = True
1085                                         break
1086                 if dolby:
1087                         self["DolbyActive"].showWidget()
1088                 else:
1089                         self["DolbyActive"].hideWidget()
1090
1091         def checkCrypted(self, service):
1092                 info = service.info()
1093                 if info is not None:
1094                         if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1095                                 self["CryptActive"].showWidget()
1096                         else:
1097                                 self["CryptActive"].hideWidget()
1098
1099         def gotServiceEvent(self, ev):
1100                 service = self.session.nav.getCurrentService()
1101                 if ev == iPlayableService.evUpdatedEventInfo:
1102                         self.checkSubservices(service)
1103                         self.checkFormat(service)
1104                 elif ev == iPlayableService.evUpdatedInfo:
1105                         self.checkCrypted(service)
1106                         self.checkDolby(service)
1107                 elif ev == iPlayableService.evEnd:
1108                         self.hideSubServiceIndication()
1109                         self["CryptActive"].hideWidget()
1110                         self["DolbyActive"].hideWidget()
1111                         self["FormatActive"].hideWidget()
1112
1113 class InfoBarNotifications:
1114         def __init__(self):
1115                 self.onExecBegin.append(self.checkNotifications)
1116                 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1117         
1118         def checkNotificationsIfExecing(self):
1119                 if self.execing:
1120                         self.checkNotifications()
1121
1122         def checkNotifications(self):
1123                 if len(Notifications.notifications):
1124                         n = Notifications.notifications[0]
1125                         Notifications.notifications = Notifications.notifications[1:]
1126                         print "open",n
1127                         cb = n[0]
1128                         if cb is not None:
1129                                 self.session.openWithCallback(cb, *n[1:])
1130                         else:
1131                                 self.session.open(*n[1:])
1132
1133 class InfoBarServiceNotifications:
1134         def __init__(self):
1135                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1136                         {
1137                                 iPlayableService.evEnd: self.serviceHasEnded
1138                         })
1139
1140         def serviceHasEnded(self):
1141                 print "service end!"
1142
1143                 try:
1144                         self.setSeekState(self.SEEK_STATE_PLAY)
1145                 except:
1146                         pass
1147
1148 class InfoBarCueSheetSupport:
1149         CUT_TYPE_IN = 0
1150         CUT_TYPE_OUT = 1
1151         CUT_TYPE_MARK = 2
1152         
1153         def __init__(self):
1154                 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions", 
1155                         {
1156                                 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1157                                 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1158                                 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1159                         }, prio=1) 
1160                 
1161                 self.cut_list = [ ]
1162                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1163                         {
1164                                 iPlayableService.evStart: self.__serviceStarted,
1165                         })
1166
1167         def __serviceStarted(self):
1168                 print "new service started! trying to download cuts!"
1169                 self.downloadCuesheet()
1170
1171         def __getSeekable(self):
1172                 service = self.session.nav.getCurrentService()
1173                 if service is None:
1174                         return None
1175                 return service.seek()
1176
1177         def __getCurrentPosition(self):
1178                 seek = self.__getSeekable()
1179                 if seek is None:
1180                         return None
1181                 r = seek.getPlayPosition()
1182                 if r[0]:
1183                         return None
1184                 return long(r[1])
1185
1186         def jumpPreviousNextMark(self, cmp, alternative=None):
1187                 current_pos = self.__getCurrentPosition()
1188                 if current_pos is None:
1189                         return
1190                 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1191                 if mark is not None:
1192                         pts = mark[0]
1193                 elif alternative is not None:
1194                         pts = alternative
1195                 else:
1196                         return
1197
1198                 seekable = self.__getSeekable()
1199                 if seekable is not None:
1200                         seekable.seekTo(pts)
1201
1202         def jumpPreviousMark(self):
1203                 print "jumpPreviousMark"
1204                 # we add 2 seconds, so if the play position is <2s after
1205                 # the mark, the mark before will be used
1206                 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1207
1208         def jumpNextMark(self):
1209                 print "jumpNextMark"
1210                 self.jumpPreviousNextMark(lambda x: x)
1211
1212         def getNearestCutPoint(self, pts, cmp=abs):
1213                 # can be optimized
1214                 nearest = None
1215                 for cp in self.cut_list:
1216                         diff = cmp(cp[0] - pts)
1217                         if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1218                                 nearest = cp
1219                 return nearest
1220
1221         def toggleMark(self):
1222                 print "toggleMark"
1223                 current_pos = self.__getCurrentPosition()
1224                 if current_pos is None:
1225                         print "not seekable"
1226                         return
1227                 
1228                 print "current position: ", current_pos
1229
1230                 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1231                 print "nearest_cutpoint: ", nearest_cutpoint
1232                 
1233                 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < 5*90000:
1234                         self.cut_list.remove(nearest_cutpoint)
1235                 else:
1236                         bisect.insort(self.cut_list, (current_pos, self.CUT_TYPE_MARK))
1237                 
1238                 self.uploadCuesheet()
1239
1240         def __getCuesheet(self):
1241                 service = self.session.nav.getCurrentService()
1242                 if service is None:
1243                         return None
1244                 return service.cueSheet()
1245
1246         def uploadCuesheet(self):
1247                 cue = self.__getCuesheet()
1248
1249                 if cue is None:
1250                         print "upload failed, no cuesheet interface"
1251                         return
1252                 cue.setCutList(self.cut_list)
1253
1254         def downloadCuesheet(self):
1255                 cue = self.__getCuesheet()
1256
1257                 if cue is None:
1258                         print "upload failed, no cuesheet interface"
1259                         return
1260                 self.cut_list = cue.getCutList()
1261
1262                 print "cuts:", self.cut_list