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