Merge branch 'master' of fraxinas@git.opendreambox.org:/git/enigma2
[enigma2.git] / lib / python / Plugins / Extensions / GraphMultiEPG / GraphMultiEpg.py
1 from skin import parseColor
2 from Components.config import config, ConfigClock, ConfigInteger
3 from Components.Pixmap import Pixmap
4 from Components.Button import Button
5 from Components.ActionMap import ActionMap
6 from Components.HTMLComponent import HTMLComponent
7 from Components.GUIComponent import GUIComponent
8 from Components.EpgList import Rect
9 from Components.Sources.Event import Event
10 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
11 from Components.TimerList import TimerList
12 from Screens.Screen import Screen
13 from Screens.EventView import EventViewSimple
14 from Screens.TimeDateInput import TimeDateInput
15 from Screens.TimerEntry import TimerEntry
16 from Screens.EpgSelection import EPGSelection
17 from Screens.TimerEdit import TimerSanityConflict
18 from Screens.MessageBox import MessageBox
19 from Tools.Directories import resolveFilename, SCOPE_SKIN_IMAGE
20 from RecordTimer import RecordTimerEntry, parseEvent, AFTEREVENT
21 from ServiceReference import ServiceReference
22 from Tools.LoadPixmap import LoadPixmap
23 from enigma import eEPGCache, eListbox, gFont, eListboxPythonMultiContent, \
24         RT_HALIGN_LEFT, RT_HALIGN_CENTER, RT_VALIGN_CENTER, RT_WRAP, eRect, eTimer
25
26 from time import localtime, time, strftime
27
28 class EPGList(HTMLComponent, GUIComponent):
29         def __init__(self, selChangedCB=None, timer = None, time_epoch = 120, overjump_empty=True):
30                 self.cur_event = None
31                 self.cur_service = None
32                 self.offs = 0
33                 self.timer = timer
34                 self.onSelChanged = [ ]
35                 if selChangedCB is not None:
36                         self.onSelChanged.append(selChangedCB)
37                 GUIComponent.__init__(self)
38                 self.l = eListboxPythonMultiContent()
39                 self.l.setItemHeight(54);
40                 self.l.setBuildFunc(self.buildEntry)
41                 if overjump_empty:
42                         self.l.setSelectableFunc(self.isSelectable)
43                 self.epgcache = eEPGCache.getInstance()
44                 self.clock_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock.png'))
45                 self.clock_add_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock_add.png'))
46                 self.clock_pre_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock_pre.png'))
47                 self.clock_post_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock_post.png'))
48                 self.clock_prepost_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock_prepost.png'))
49                 self.time_base = None
50                 self.time_epoch = time_epoch
51                 self.list = None
52                 self.event_rect = None
53
54                 self.foreColor = None
55                 self.foreColorSelected = None
56                 self.borderColor = None
57                 self.backColor = 0x586d88
58                 self.backColorSelected = 0x808080
59                 self.foreColorService = None
60                 self.backColorService = None
61
62         def applySkin(self, desktop, screen):
63                 if self.skinAttributes is not None:
64                         attribs = [ ]
65                         for (attrib, value) in self.skinAttributes:
66                                 if attrib == "EntryForegroundColor":
67                                         self.foreColor = parseColor(value).argb()
68                                 elif attrib == "EntryForegroundColorSelected":
69                                         self.foreColorSelected = parseColor(value).argb()
70                                 elif attrib == "EntryBorderColor":
71                                         self.borderColor = parseColor(value).argb()
72                                 elif attrib == "EntryBackgroundColor":
73                                         self.backColor = parseColor(value).argb()
74                                 elif attrib == "EntryBackgroundColorSelected":
75                                         self.backColorSelected = parseColor(value).argb()
76                                 elif attrib == "ServiceNameForegroundColor":
77                                         self.foreColorService = parseColor(value).argb()
78                                 elif attrib == "ServiceNameBackgroundColor":
79                                         self.backColorService = parseColor(value).argb()
80                                 else:
81                                         attribs.append((attrib,value))
82                         self.skinAttributes = attribs
83                 return GUIComponent.applySkin(self, desktop, screen)
84
85         def isSelectable(self, service, sname, event_list):
86                 return (event_list and len(event_list) and True) or False
87
88         def setEpoch(self, epoch):
89                 if self.cur_event is not None and self.cur_service is not None:
90                         self.offs = 0
91                         self.time_epoch = epoch
92                         self.fillMultiEPG(None) # refill
93
94         def getEventFromId(self, service, eventid):
95                 event = None
96                 if self.epgcache is not None and eventid is not None:
97                         event = self.epgcache.lookupEventId(service.ref, eventid)
98                 return event
99
100         def moveToService(self,serviceref):
101                 for x in range(len(self.list)):
102                         if self.list[x][0] == serviceref.toString():
103                                 self.instance.moveSelectionTo(x)
104                                 break
105         
106         def getIndexFromService(self, serviceref):
107                 for x in range(len(self.list)):
108                         if self.list[x][0] == serviceref.toString():
109                                 return x
110                 return 0
111                 
112         def setCurrentIndex(self, index):
113                 if self.instance is not None:
114                         self.instance.moveSelectionTo(index)
115         
116         def getCurrent(self):
117                 if self.cur_service is None:
118                         return ( None, None )
119                 old_service = self.cur_service  #(service, service_name, events)
120                 events = self.cur_service[2]
121                 refstr = self.cur_service[0]
122                 if self.cur_event is None or not events or not len(events):
123                         return ( None, ServiceReference(refstr) )
124                 event = events[self.cur_event] #(event_id, event_title, begin_time, duration)
125                 eventid = event[0]
126                 service = ServiceReference(refstr)
127                 event = self.getEventFromId(service, eventid)
128                 return ( event, service )
129
130         def connectSelectionChanged(func):
131                 if not self.onSelChanged.count(func):
132                         self.onSelChanged.append(func)
133
134         def disconnectSelectionChanged(func):
135                 self.onSelChanged.remove(func)
136
137         def serviceChanged(self):
138                 cur_sel = self.l.getCurrentSelection()
139                 if cur_sel:
140                         self.findBestEvent()
141
142         def findBestEvent(self):
143                 old_service = self.cur_service  #(service, service_name, events)
144                 cur_service = self.cur_service = self.l.getCurrentSelection()
145                 last_time = 0;
146                 time_base = self.getTimeBase()
147                 if old_service and self.cur_event is not None:
148                         events = old_service[2]
149                         cur_event = events[self.cur_event] #(event_id, event_title, begin_time, duration)
150                         last_time = cur_event[2]
151                         if last_time < time_base:
152                                 last_time = time_base
153                 if cur_service:
154                         self.cur_event = 0
155                         events = cur_service[2]
156                         if events and len(events):
157                                 if last_time:
158                                         best_diff = 0
159                                         best = len(events) #set invalid
160                                         idx = 0
161                                         for event in events: #iterate all events
162                                                 ev_time = event[2]
163                                                 if ev_time < time_base:
164                                                         ev_time = time_base
165                                                 diff = abs(ev_time-last_time)
166                                                 if (best == len(events)) or (diff < best_diff):
167                                                         best = idx
168                                                         best_diff = diff
169                                                 idx += 1
170                                         if best != len(events):
171                                                 self.cur_event = best
172                         else:
173                                 self.cur_event = None
174                 self.selEntry(0)
175
176         def selectionChanged(self):
177                 for x in self.onSelChanged:
178                         if x is not None:
179                                 x()
180 #                               try:
181 #                                       x()
182 #                               except: # FIXME!!!
183 #                                       print "FIXME in EPGList.selectionChanged"
184 #                                       pass
185
186         GUI_WIDGET = eListbox
187
188         def postWidgetCreate(self, instance):
189                 instance.setWrapAround(True)
190                 instance.selectionChanged.get().append(self.serviceChanged)
191                 instance.setContent(self.l)
192                 self.l.setFont(0, gFont("Regular", 20))
193                 self.l.setFont(1, gFont("Regular", 14))
194                 self.l.setSelectionClip(eRect(0,0,0,0), False)
195
196         def preWidgetRemove(self, instance):
197                 instance.selectionChanged.get().remove(self.serviceChanged)
198                 instance.setContent(None)
199
200         def recalcEntrySize(self):
201                 esize = self.l.getItemSize()
202                 width = esize.width()
203                 height = esize.height()
204                 xpos = 0;
205                 w = width/10*2;
206                 self.service_rect = Rect(xpos, 0, w-10, height)
207                 xpos += w;
208                 w = width/10*8;
209                 self.event_rect = Rect(xpos, 0, w, height)
210
211         def calcEntryPosAndWidthHelper(self, stime, duration, start, end, width):
212                 xpos = (stime - start) * width / (end - start)
213                 ewidth = (stime + duration - start) * width / (end - start)
214                 ewidth -= xpos;
215                 if xpos < 0:
216                         ewidth += xpos;
217                         xpos = 0;
218                 if (xpos+ewidth) > width:
219                         ewidth = width - xpos
220                 return xpos, ewidth
221
222         def calcEntryPosAndWidth(self, event_rect, time_base, time_epoch, ev_start, ev_duration):
223                 xpos, width = self.calcEntryPosAndWidthHelper(ev_start, ev_duration, time_base, time_base + time_epoch * 60, event_rect.width())
224                 return xpos+event_rect.left(), width
225
226         def buildEntry(self, service, service_name, events):
227                 r1=self.service_rect
228                 r2=self.event_rect
229                 res = [ None, MultiContentEntryText(
230                                                 pos = (r1.left(),r1.top()),
231                                                 size = (r1.width(), r1.height()),
232                                                 font = 0, flags = RT_HALIGN_LEFT | RT_VALIGN_CENTER,
233                                                 text = service_name,
234                                                 color = self.foreColorService,
235                                                 backcolor = self.backColorService) ]
236
237                 if events:
238                         start = self.time_base+self.offs*self.time_epoch*60
239                         end = start + self.time_epoch * 60
240                         left = r2.left()
241                         top = r2.top()
242                         width = r2.width()
243                         height = r2.height()
244                         foreColor = self.foreColor
245                         foreColorSelected = self.foreColorSelected
246                         backColor = self.backColor
247                         backColorSelected = self.backColorSelected
248                         borderColor = self.borderColor
249
250                         for ev in events:  #(event_id, event_title, begin_time, duration)
251                                 rec=ev[2] and self.timer.isInTimer(ev[0], ev[2], ev[3], service)
252                                 xpos, ewidth = self.calcEntryPosAndWidthHelper(ev[2], ev[3], start, end, width)
253                                 res.append(MultiContentEntryText(
254                                         pos = (left+xpos, top), size = (ewidth, height),
255                                         font = 1, flags = RT_HALIGN_CENTER | RT_VALIGN_CENTER | RT_WRAP,
256                                         text = ev[1], color = foreColor, color_sel = foreColorSelected,
257                                         backcolor = backColor, backcolor_sel = backColorSelected, border_width = 1, border_color = borderColor))
258                                 if rec and ewidth > 23:
259                                         res.append(MultiContentEntryPixmapAlphaTest(
260                                                 pos = (left+xpos+ewidth-22, top+height-22), size = (21, 21),
261                                                 png = self.getClockPixmap(service, ev[2], ev[3], ev[0]),
262                                                 backcolor = backColor,
263                                                 backcolor_sel = backColorSelected))
264                 return res
265
266         def selEntry(self, dir, visible=True):
267                 cur_service = self.cur_service #(service, service_name, events)
268                 self.recalcEntrySize()
269                 valid_event = self.cur_event is not None
270                 if cur_service:
271                         update = True
272                         entries = cur_service[2]
273                         if dir == 0: #current
274                                 update = False
275                         elif dir == +1: #next
276                                 if valid_event and self.cur_event+1 < len(entries):
277                                         self.cur_event+=1
278                                 else:
279                                         self.offs += 1
280                                         self.fillMultiEPG(None) # refill
281                                         return True
282                         elif dir == -1: #prev
283                                 if valid_event and self.cur_event-1 >= 0:
284                                         self.cur_event-=1
285                                 elif self.offs > 0:
286                                         self.offs -= 1
287                                         self.fillMultiEPG(None) # refill
288                                         return True
289                 if cur_service and valid_event:
290                         entry = entries[self.cur_event] #(event_id, event_title, begin_time, duration)
291                         time_base = self.time_base+self.offs*self.time_epoch*60
292                         xpos, width = self.calcEntryPosAndWidth(self.event_rect, time_base, self.time_epoch, entry[2], entry[3])
293                         self.l.setSelectionClip(eRect(xpos, 0, width, self.event_rect.height()), visible and update)
294                 else:
295                         self.l.setSelectionClip(eRect(self.event_rect.left(), self.event_rect.top(), self.event_rect.width(), self.event_rect.height()), False)
296                 self.selectionChanged()
297                 return False
298
299         def queryEPG(self, list, buildFunc=None):
300                 if self.epgcache is not None:
301                         if buildFunc is not None:
302                                 return self.epgcache.lookupEvent(list, buildFunc)
303                         else:
304                                 return self.epgcache.lookupEvent(list)
305                 return [ ]
306
307         def fillMultiEPG(self, services, stime=-1):
308                 if services is None:
309                         time_base = self.time_base+self.offs*self.time_epoch*60
310                         test = [ (service[0], 0, time_base, self.time_epoch) for service in self.list ]
311                 else:
312                         self.cur_event = None
313                         self.cur_service = None
314                         self.time_base = int(stime)
315                         test = [ (service.ref.toString(), 0, self.time_base, self.time_epoch) for service in services ]
316                 test.insert(0, 'XRnITBD')
317 #               print "BEFORE:"
318 #               for x in test:
319 #                       print x
320                 epg_data = self.queryEPG(test)
321 #               print "EPG:"
322 #               for x in epg_data:
323 #                       print x
324                 self.list = [ ]
325                 tmp_list = None
326                 service = ""
327                 sname = ""
328                 for x in epg_data:
329                         if service != x[0]:
330                                 if tmp_list is not None:
331                                         self.list.append((service, sname, tmp_list[0][0] is not None and tmp_list or None))
332                                 service = x[0]
333                                 sname = x[1]
334                                 tmp_list = [ ]
335                         tmp_list.append((x[2], x[3], x[4], x[5]))
336                 if tmp_list and len(tmp_list):
337                         self.list.append((service, sname, tmp_list[0][0] is not None and tmp_list or None))
338
339                 self.l.setList(self.list)
340                 self.findBestEvent()
341
342         def getEventRect(self):
343                 rc = self.event_rect
344                 return Rect( rc.left() + (self.instance and self.instance.position().x() or 0), rc.top(), rc.width(), rc.height() )
345
346         def getTimeEpoch(self):
347                 return self.time_epoch
348
349         def getTimeBase(self):
350                 return self.time_base + (self.offs * self.time_epoch * 60)
351
352         def resetOffset(self):
353                 self.offs = 0
354         
355         def getClockPixmap(self, refstr, beginTime, duration, eventId):
356                 pre_clock = 1
357                 post_clock = 2
358                 clock_type = 0
359                 endTime = beginTime + duration
360                 for x in self.timer.timer_list:
361                         if x.service_ref.ref.toString() == refstr:
362                                 if x.eit == eventId:
363                                         return self.clock_pixmap
364                                 beg = x.begin
365                                 end = x.end
366                                 if beginTime > beg and beginTime < end and endTime > end:
367                                         clock_type |= pre_clock
368                                 elif beginTime < beg and endTime > beg and endTime < end:
369                                         clock_type |= post_clock
370                 if clock_type == 0:
371                         return self.clock_add_pixmap
372                 elif clock_type == pre_clock:
373                         return self.clock_pre_pixmap
374                 elif clock_type == post_clock:
375                         return self.clock_post_pixmap
376                 else:
377                         return self.clock_prepost_pixmap
378
379 class TimelineText(HTMLComponent, GUIComponent):
380         def __init__(self):
381                 GUIComponent.__init__(self)
382                 self.l = eListboxPythonMultiContent()
383                 self.l.setSelectionClip(eRect(0,0,0,0))
384                 self.l.setItemHeight(25);
385                 self.l.setFont(0, gFont("Regular", 20))
386
387         GUI_WIDGET = eListbox
388
389         def postWidgetCreate(self, instance):
390                 instance.setContent(self.l)
391
392         def setEntries(self, entries):
393                 res = [ None ] # no private data needed
394                 for x in entries:
395                         tm = x[0]
396                         xpos = x[1]
397                         str = strftime("%H:%M", localtime(tm))
398                         res.append((eListboxPythonMultiContent.TYPE_TEXT, xpos-30, 0, 60, 25, 0, RT_HALIGN_CENTER|RT_VALIGN_CENTER, str))
399                 self.l.setList([res])
400
401 config.misc.graph_mepg_prev_time=ConfigClock(default = time())
402 config.misc.graph_mepg_prev_time_period=ConfigInteger(default=120, limits=(60,300))
403
404 class GraphMultiEPG(Screen):
405         EMPTY = 0
406         ADD_TIMER = 1
407         REMOVE_TIMER = 2
408         
409         ZAP = 1
410
411         def __init__(self, session, services, zapFunc=None, bouquetChangeCB=None):
412                 Screen.__init__(self, session)
413                 self.bouquetChangeCB = bouquetChangeCB
414                 now = time()
415                 tmp = now % 900
416                 self.ask_time = now - tmp
417                 self.closeRecursive = False
418                 self["key_red"] = Button("")
419                 self["key_green"] = Button("")
420                 self.key_green_choice = self.EMPTY
421                 self.key_red_choice = self.EMPTY
422                 self["timeline_text"] = TimelineText()
423                 self["Event"] = Event()
424                 self.time_lines = [ ]
425                 for x in (0,1,2,3,4,5):
426                         pm = Pixmap()
427                         self.time_lines.append(pm)
428                         self["timeline%d"%(x)] = pm
429                 self["timeline_now"] = Pixmap()
430                 self.services = services
431                 self.zapFunc = zapFunc
432
433                 self["list"] = EPGList(selChangedCB = self.onSelectionChanged, timer = self.session.nav.RecordTimer, time_epoch = config.misc.graph_mepg_prev_time_period.value )
434
435                 self["actions"] = ActionMap(["EPGSelectActions", "OkCancelActions"],
436                         {
437                                 "cancel": self.closeScreen,
438                                 "ok": self.eventSelected,
439                                 "timerAdd": self.timerAdd,
440                                 "info": self.infoKeyPressed,
441                                 "red": self.zapTo,
442                                 "input_date_time": self.enterDateTime,
443                                 "nextBouquet": self.nextBouquet,
444                                 "prevBouquet": self.prevBouquet,
445                         })
446                 self["actions"].csel = self
447
448                 self["input_actions"] = ActionMap(["InputActions"],
449                         {
450                                 "left": self.leftPressed,
451                                 "right": self.rightPressed,
452                                 "1": self.key1,
453                                 "2": self.key2,
454                                 "3": self.key3,
455                                 "4": self.key4,
456                                 "5": self.key5,
457                         },-1)
458
459                 self.updateTimelineTimer = eTimer()
460                 self.updateTimelineTimer.callback.append(self.moveTimeLines)
461                 self.updateTimelineTimer.start(60*1000)
462                 self.onLayoutFinish.append(self.onCreate)
463
464         def leftPressed(self):
465                 self.prevEvent()
466
467         def rightPressed(self):
468                 self.nextEvent()
469
470         def nextEvent(self, visible=True):
471                 ret = self["list"].selEntry(+1, visible)
472                 if ret:
473                         self.moveTimeLines(True)
474
475         def prevEvent(self, visible=True):
476                 ret = self["list"].selEntry(-1, visible)
477                 if ret:
478                         self.moveTimeLines(True)
479
480         def key1(self):
481                 self["list"].setEpoch(60)
482                 config.misc.graph_mepg_prev_time_period.value = 60
483                 self.moveTimeLines()
484
485         def key2(self):
486                 self["list"].setEpoch(120)
487                 config.misc.graph_mepg_prev_time_period.value = 120
488                 self.moveTimeLines()
489
490         def key3(self):
491                 self["list"].setEpoch(180)
492                 config.misc.graph_mepg_prev_time_period.value = 180
493                 self.moveTimeLines()
494
495         def key4(self):
496                 self["list"].setEpoch(240)
497                 config.misc.graph_mepg_prev_time_period.value = 240
498                 self.moveTimeLines()
499
500         def key5(self):
501                 self["list"].setEpoch(300)
502                 config.misc.graph_mepg_prev_time_period.value = 300
503                 self.moveTimeLines()
504
505         def nextBouquet(self):
506                 if self.bouquetChangeCB:
507                         self.bouquetChangeCB(1, self)
508
509         def prevBouquet(self):
510                 if self.bouquetChangeCB:
511                         self.bouquetChangeCB(-1, self)
512
513         def enterDateTime(self):
514                 self.session.openWithCallback(self.onDateTimeInputClosed, TimeDateInput, config.misc.graph_mepg_prev_time )
515
516         def onDateTimeInputClosed(self, ret):
517                 if len(ret) > 1:
518                         if ret[0]:
519                                 self.ask_time=ret[1]
520                                 l = self["list"]
521                                 l.resetOffset()
522                                 l.fillMultiEPG(self.services, ret[1])
523                                 self.moveTimeLines(True)
524
525         def closeScreen(self):
526                 self.close(self.closeRecursive)
527
528         def infoKeyPressed(self):
529                 cur = self["list"].getCurrent()
530                 event = cur[0]
531                 service = cur[1]
532                 if event is not None:
533                         self.session.open(EventViewSimple, event, service, self.eventViewCallback, self.openSimilarList)
534
535         def openSimilarList(self, eventid, refstr):
536                 self.session.open(EPGSelection, refstr, None, eventid)
537
538         def setServices(self, services):
539                 self.services = services
540                 self.onCreate()
541
542         #just used in multipeg
543         def onCreate(self):
544                 self["list"].fillMultiEPG(self.services, self.ask_time)
545                 self["list"].moveToService(self.session.nav.getCurrentlyPlayingServiceReference())
546                 self.moveTimeLines()
547
548         def eventViewCallback(self, setEvent, setService, val):
549                 l = self["list"]
550                 old = l.getCurrent()
551                 if val == -1:
552                         self.prevEvent(False)
553                 elif val == +1:
554                         self.nextEvent(False)
555                 cur = l.getCurrent()
556                 if cur[0] is None and cur[1].ref != old[1].ref:
557                         self.eventViewCallback(setEvent, setService, val)
558                 else:
559                         setService(cur[1])
560                         setEvent(cur[0])
561
562         def zapTo(self):
563                 if self.zapFunc and self.key_red_choice == self.ZAP:
564                         self.closeRecursive = True
565                         ref = self["list"].getCurrent()[1]
566                         if ref:
567                                 self.zapFunc(ref.ref)
568
569         def eventSelected(self):
570                 self.infoKeyPressed()
571
572         def removeTimer(self, timer):
573                 timer.afterEvent = AFTEREVENT.NONE
574                 self.session.nav.RecordTimer.removeEntry(timer)
575                 self["key_green"].setText(_("Add timer"))
576                 self.key_green_choice = self.ADD_TIMER
577         
578         def timerAdd(self):
579                 cur = self["list"].getCurrent()
580                 event = cur[0]
581                 serviceref = cur[1]
582                 if event is None:
583                         return
584                 eventid = event.getEventId()
585                 refstr = serviceref.ref.toString()
586                 for timer in self.session.nav.RecordTimer.timer_list:
587                         if timer.eit == eventid and timer.service_ref.ref.toString() == refstr:
588                                 cb_func = lambda ret : not ret or self.removeTimer(timer)
589                                 self.session.openWithCallback(cb_func, MessageBox, _("Do you really want to delete %s?") % event.getEventName())
590                                 break
591                 else:
592                         newEntry = RecordTimerEntry(serviceref, checkOldTimers = True, *parseEvent(event))
593                         self.session.openWithCallback(self.finishedAdd, TimerEntry, newEntry)
594
595         def finishedAdd(self, answer):
596                 print "finished add"
597                 if answer[0]:
598                         entry = answer[1]
599                         simulTimerList = self.session.nav.RecordTimer.record(entry)
600                         if simulTimerList is not None:
601                                 if (len(simulTimerList) == 2) and (simulTimerList[1].dontSave) and (simulTimerList[1].autoincrease):
602                                         simulTimerList[1].end = entry.begin - 30
603                                         self.session.nav.RecordTimer.timeChanged(simulTimerList[1])
604                                         self.session.nav.RecordTimer.record(entry)
605                                 else:
606                                         self.session.openWithCallback(self.finishSanityCorrection, TimerSanityConflict, simulTimerList)
607                         self["key_green"].setText(_("Remove timer"))
608                         self.key_green_choice = self.REMOVE_TIMER
609                 else:
610                         self["key_green"].setText(_("Add timer"))
611                         self.key_green_choice = self.ADD_TIMER
612                         print "Timeredit aborted"
613         
614         def finishSanityCorrection(self, answer):
615                 self.finishedAdd(answer)
616
617         def onSelectionChanged(self):
618                 cur = self["list"].getCurrent()
619                 if cur is None:
620                         if self.key_green_choice != self.EMPTY:
621                                 self["key_green"].setText("")
622                                 self.key_green_choice = self.EMPTY
623                         if self.key_red_choice != self.EMPTY:
624                                 self["key_red"].setText("")
625                                 self.key_red_choice = self.EMPTY
626                         return
627                 
628                 event = cur[0]
629                 self["Event"].newEvent(event)
630                 
631                 if cur[1] is None or cur[1].getServiceName() == "":
632                         if self.key_green_choice != self.EMPTY:
633                                 self["key_green"].setText("")
634                                 self.key_green_choice = self.EMPTY
635                         if self.key_red_choice != self.EMPTY:
636                                 self["key_red"].setText("")
637                                 self.key_red_choice = self.EMPTY
638                         return
639                 elif self.key_red_choice != self.ZAP:
640                                 self["key_red"].setText("Zap")
641                                 self.key_red_choice = self.ZAP
642                         
643                 if not event:
644                         if self.key_green_choice != self.EMPTY:
645                                 self["key_green"].setText("")
646                                 self.key_green_choice = self.EMPTY
647                         return
648                 
649                 serviceref = cur[1]
650                 eventid = event.getEventId()
651                 refstr = serviceref.ref.toString()
652                 isRecordEvent = False
653                 for timer in self.session.nav.RecordTimer.timer_list:
654                         if timer.eit == eventid and timer.service_ref.ref.toString() == refstr:
655                                 isRecordEvent = True
656                                 break
657                 if isRecordEvent and self.key_green_choice != self.REMOVE_TIMER:
658                         self["key_green"].setText(_("Remove timer"))
659                         self.key_green_choice = self.REMOVE_TIMER
660                 elif not isRecordEvent and self.key_green_choice != self.ADD_TIMER:
661                         self["key_green"].setText(_("Add timer"))
662                         self.key_green_choice = self.ADD_TIMER
663         
664         def moveTimeLines(self, force=False):
665                 l = self["list"]
666                 event_rect = l.getEventRect()
667                 time_epoch = l.getTimeEpoch()
668                 time_base = l.getTimeBase()
669                 if event_rect is None or time_epoch is None or time_base is None:
670                         return
671                 time_steps = time_epoch > 180 and 60 or 30
672                 num_lines = time_epoch/time_steps
673                 incWidth=event_rect.width()/num_lines
674                 pos=event_rect.left()
675                 timeline_entries = [ ]
676                 x = 0
677                 changecount = 0
678                 for line in self.time_lines:
679                         old_pos = line.position
680                         new_pos = (x == num_lines and event_rect.left()+event_rect.width() or pos, old_pos[1])
681                         if not x or x >= num_lines:
682                                 line.visible = False
683                         else:
684                                 if old_pos != new_pos:
685                                         line.setPosition(new_pos[0], new_pos[1])
686                                         changecount += 1
687                                 line.visible = True
688                         if not x or line.visible:
689                                 timeline_entries.append((time_base + x * time_steps * 60, new_pos[0]))
690                         x += 1
691                         pos += incWidth
692
693                 if changecount or force:
694                         self["timeline_text"].setEntries(timeline_entries)
695
696                 now=time()
697                 timeline_now = self["timeline_now"]
698                 if now >= time_base and now < (time_base + time_epoch * 60):
699                         bla = (event_rect.width() * 1000) / time_epoch
700                         xpos = ((now/60) - (time_base/60)) * bla / 1000
701                         old_pos = timeline_now.position
702                         new_pos = (xpos+event_rect.left(), old_pos[1])
703                         if old_pos != new_pos:
704                                 timeline_now.setPosition(new_pos[0], new_pos[1])
705                         timeline_now.visible = True
706                 else:
707                         timeline_now.visible = False