e7b8edb4f382744ba90c4c40615172fd57cadf91
[openblackhole/openblackhole-enigma2.git] / lib / python / Screens / TimerEdit.py
1 from Components.ActionMap import ActionMap
2 from Components.Button import Button
3 from Components.config import config
4 from Components.MenuList import MenuList
5 from Components.TimerList import TimerList
6 from Components.TimerSanityCheck import TimerSanityCheck
7 from Components.UsageConfig import preferredTimerPath
8 from RecordTimer import RecordTimerEntry, parseEvent, AFTEREVENT
9 from Screen import Screen
10 from Screens.ChoiceBox import ChoiceBox
11 from Screens.MessageBox import MessageBox
12 from Screens.InputBox import PinInput
13 from ServiceReference import ServiceReference
14 from TimerEntry import TimerEntry, TimerLog
15 from Tools.BoundFunction import boundFunction
16 from time import time
17 from timer import TimerEntry as RealTimerEntry
18
19 class TimerEditList(Screen):
20         EMPTY = 0
21         ENABLE = 1
22         DISABLE = 2
23         CLEANUP = 3
24         DELETE = 4
25
26         def __init__(self, session):
27                 Screen.__init__(self, session)
28
29                 list = [ ]
30                 self.list = list
31                 self.fillTimerList()
32
33                 self["timerlist"] = TimerList(list)
34
35                 self.key_red_choice = self.EMPTY
36                 self.key_yellow_choice = self.EMPTY
37                 self.key_blue_choice = self.EMPTY
38
39                 self["key_red"] = Button(" ")
40                 self["key_green"] = Button(_("Add"))
41                 self["key_yellow"] = Button(" ")
42                 self["key_blue"] = Button(" ")
43
44                 print "[TimerEditList] key_red_choice:",self.key_red_choice
45
46                 self["actions"] = ActionMap(["OkCancelActions", "DirectionActions", "ShortcutActions", "TimerEditActions"],
47                         {
48                                 "ok": self.openEdit,
49                                 "cancel": self.leave,
50                                 "green": self.addCurrentTimer,
51                                 "log": self.showLog,
52                                 "left": self.left,
53                                 "right": self.right,
54                                 "up": self.up,
55                                 "down": self.down
56                         }, -1)
57                 self.setTitle(_("Timer overview"))
58                 self.session.nav.RecordTimer.on_state_change.append(self.onStateChange)
59                 self.onShown.append(self.updateState)
60                 if self.isProtected() and config.ParentalControl.servicepin[0].value:
61                         self.onFirstExecBegin.append(boundFunction(self.session.openWithCallback, self.pinEntered, PinInput, pinList=[x.value for x in config.ParentalControl.servicepin], triesEntry=config.ParentalControl.retries.servicepin, title=_("Please enter the correct pin code"), windowTitle=_("Enter pin code")))
62
63         def isProtected(self):
64                 return config.ParentalControl.setuppinactive.value and (not config.ParentalControl.config_sections.main_menu.value or hasattr(self.session, 'infobar') and self.session.infobar is None) and config.ParentalControl.config_sections.timer_menu.value
65
66         def pinEntered(self, result):
67                 if result is None:
68                         self.closeProtectedScreen()
69                 elif not result:
70                         self.session.openWithCallback(self.close(), MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR, timeout=3)
71
72         def closeProtectedScreen(self, result=None):
73                 self.close(None)
74
75         def up(self):
76                 self["timerlist"].instance.moveSelection(self["timerlist"].instance.moveUp)
77                 self.updateState()
78
79         def down(self):
80                 self["timerlist"].instance.moveSelection(self["timerlist"].instance.moveDown)
81                 self.updateState()
82
83         def left(self):
84                 self["timerlist"].instance.moveSelection(self["timerlist"].instance.pageUp)
85                 self.updateState()
86
87         def right(self):
88                 self["timerlist"].instance.moveSelection(self["timerlist"].instance.pageDown)
89                 self.updateState()
90
91         def toggleDisabledState(self):
92                 cur=self["timerlist"].getCurrent()
93                 timer_changed = True
94                 if cur:
95                         t = cur
96                         if t.disabled and t.repeated and t.isRunning() and not t.justplay:
97                                 return
98                         if t.disabled:
99                                 print "[TimerEditList] try to ENABLE timer"
100                                 t.enable()
101                                 timersanitycheck = TimerSanityCheck(self.session.nav.RecordTimer.timer_list, cur)
102                                 if not timersanitycheck.check():
103                                         t.disable()
104                                         print "[TimerEditList] sanity check failed"
105                                         simulTimerList = timersanitycheck.getSimulTimerList()
106                                         if simulTimerList is not None:
107                                                 self.session.openWithCallback(self.finishedEdit, TimerSanityConflict, simulTimerList)
108                                                 timer_changed = False
109                                 else:
110                                         print "[TimerEditList] sanity check passed"
111                                         if timersanitycheck.doubleCheck():
112                                                 t.disable()
113                         else:
114                                 if t.isRunning():
115                                         if t.repeated:
116                                                 list = (
117                                                         (_("Stop current event but not coming events"), "stoponlycurrent"),
118                                                         (_("Stop current event and disable coming events"), "stopall"),
119                                                         (_("Don't stop current event but disable coming events"), "stoponlycoming")
120                                                 )
121                                                 self.session.openWithCallback(boundFunction(self.runningEventCallback, t), ChoiceBox, title=_("Repeating event currently recording... What do you want to do?"), list = list)
122                                                 timer_changed = False
123                                 else:
124                                         t.disable()
125                         if timer_changed:
126                                 self.session.nav.RecordTimer.timeChanged(t)
127                         self.refill()
128                         self.updateState()
129
130         def runningEventCallback(self, t, result):
131                 if result is not None and t.isRunning():
132                         findNextRunningEvent = True
133                         if result[1] == "stoponlycurrent" or result[1] == "stopall":
134                                 findNextRunningEvent = False
135                                 t.enable()
136                                 t.processRepeated(findRunningEvent = False)
137                                 self.session.nav.RecordTimer.doActivate(t)
138                         if result[1] == "stoponlycoming" or result[1] == "stopall":
139                                 findNextRunningEvent = True
140                                 t.disable()
141                         self.session.nav.RecordTimer.timeChanged(t)
142                         t.findRunningEvent = findNextRunningEvent
143                         self.refill()
144                         self.updateState()
145
146         def removeAction(self, descr):
147                 actions = self["actions"].actions
148                 if descr in actions:
149                         del actions[descr]
150
151         def updateState(self):
152                 cur = self["timerlist"].getCurrent()
153                 if cur:
154                         if self.key_red_choice != self.DELETE:
155                                 self["actions"].actions.update({"red":self.removeTimerQuestion})
156                                 self["key_red"].setText(_("Delete"))
157                                 self.key_red_choice = self.DELETE
158
159                         if cur.disabled and (self.key_yellow_choice != self.ENABLE):
160                                 if cur.isRunning() and cur.repeated and not cur.justplay:
161                                         self.removeAction("yellow")
162                                         self["key_yellow"].setText(" ")
163                                         self.key_yellow_choice = self.EMPTY
164                                 else:
165                                         self["actions"].actions.update({"yellow":self.toggleDisabledState})
166                                         self["key_yellow"].setText(_("Enable"))
167                                         self.key_yellow_choice = self.ENABLE
168                         elif cur.isRunning() and not cur.repeated and (self.key_yellow_choice != self.EMPTY):
169                                 self.removeAction("yellow")
170                                 self["key_yellow"].setText(" ")
171                                 self.key_yellow_choice = self.EMPTY
172                         elif (not cur.isRunning() or cur.repeated) and not cur.disabled and (self.key_yellow_choice != self.DISABLE):
173                                 self["actions"].actions.update({"yellow":self.toggleDisabledState})
174                                 self["key_yellow"].setText(_("Disable"))
175                                 self.key_yellow_choice = self.DISABLE
176                 else:
177                         if self.key_red_choice != self.EMPTY:
178                                 self.removeAction("red")
179                                 self["key_red"].setText(" ")
180                                 self.key_red_choice = self.EMPTY
181                         if self.key_yellow_choice != self.EMPTY:
182                                 self.removeAction("yellow")
183                                 self["key_yellow"].setText(" ")
184                                 self.key_yellow_choice = self.EMPTY
185
186                 showCleanup = True
187                 for x in self.list:
188                         if (not x[0].disabled) and (x[1] == True):
189                                 break
190                 else:
191                         showCleanup = False
192
193                 if showCleanup and (self.key_blue_choice != self.CLEANUP):
194                         self["actions"].actions.update({"blue":self.cleanupQuestion})
195                         self["key_blue"].setText(_("Cleanup"))
196                         self.key_blue_choice = self.CLEANUP
197                 elif (not showCleanup) and (self.key_blue_choice != self.EMPTY):
198                         self.removeAction("blue")
199                         self["key_blue"].setText(" ")
200                         self.key_blue_choice = self.EMPTY
201
202         def fillTimerList(self):
203                 #helper function to move finished timers to end of list
204                 def eol_compare(x, y):
205                         if x[0].state != y[0].state and x[0].state == RealTimerEntry.StateEnded or y[0].state == RealTimerEntry.StateEnded:
206                                 return cmp(x[0].state, y[0].state)
207                         return cmp(x[0].begin, y[0].begin)
208
209                 list = self.list
210                 del list[:]
211                 list.extend([(timer, False) for timer in self.session.nav.RecordTimer.timer_list])
212                 list.extend([(timer, True) for timer in self.session.nav.RecordTimer.processed_timers])
213                 if config.usage.timerlist_finished_timer_position.index: #end of list
214                         list.sort(cmp = eol_compare)
215                 else:
216                         list.sort(key = lambda x: x[0].begin)
217
218         def showLog(self):
219                 cur=self["timerlist"].getCurrent()
220                 if cur:
221                         self.session.openWithCallback(self.finishedEdit, TimerLog, cur)
222
223         def openEdit(self):
224                 cur=self["timerlist"].getCurrent()
225                 if cur:
226                         self.session.openWithCallback(self.finishedEdit, TimerEntry, cur)
227
228         def cleanupQuestion(self):
229                 self.session.openWithCallback(self.cleanupTimer, MessageBox, _("Really delete done timers?"))
230
231         def cleanupTimer(self, delete):
232                 if delete:
233                         self.session.nav.RecordTimer.cleanup()
234                         self.refill()
235                         self.updateState()
236
237         def removeTimerQuestion(self):
238                 cur = self["timerlist"].getCurrent()
239                 if not cur:
240                         return
241
242                 self.session.openWithCallback(self.removeTimer, MessageBox, _("Do you really want to delete %s?") % (cur.name))
243
244         def removeTimer(self, result):
245                 if not result:
246                         return
247                 list = self["timerlist"]
248                 cur = list.getCurrent()
249                 if cur:
250                         timer = cur
251                         timer.afterEvent = AFTEREVENT.NONE
252                         self.session.nav.RecordTimer.removeEntry(timer)
253                         self.refill()
254                         self.updateState()
255
256
257         def refill(self):
258                 oldsize = len(self.list)
259                 self.fillTimerList()
260                 lst = self["timerlist"]
261                 newsize = len(self.list)
262                 if oldsize and oldsize != newsize:
263                         idx = lst.getCurrentIndex()
264                         lst.entryRemoved(idx)
265                 else:
266                         lst.invalidate()
267
268         def addCurrentTimer(self):
269                 event = None
270                 service = self.session.nav.getCurrentService()
271                 if service is not None:
272                         info = service.info()
273                         if info is not None:
274                                 event = info.getEvent(0)
275
276                 # FIXME only works if already playing a service
277                 serviceref = ServiceReference(self.session.nav.getCurrentlyPlayingServiceOrGroup())
278
279                 if event is None:
280                         data = (int(time()), int(time() + 60), "", "", None)
281                 else:
282                         data = parseEvent(event, description = False)
283
284                 self.addTimer(RecordTimerEntry(serviceref, checkOldTimers = True, dirname = preferredTimerPath(), *data))
285
286         def addTimer(self, timer):
287                 self.session.openWithCallback(self.finishedAdd, TimerEntry, timer)
288
289
290         def finishedEdit(self, answer):
291                 print "[TimerEditList] finished edit"
292
293                 if answer[0]:
294                         print "[TimerEditList] edited timer"
295                         entry = answer[1]
296                         timersanitycheck = TimerSanityCheck(self.session.nav.RecordTimer.timer_list, entry)
297                         success = False
298                         if not timersanitycheck.check():
299                                 simulTimerList = timersanitycheck.getSimulTimerList()
300                                 if simulTimerList is not None:
301                                         for x in simulTimerList:
302                                                 if x.setAutoincreaseEnd(entry):
303                                                         self.session.nav.RecordTimer.timeChanged(x)
304                                         if not timersanitycheck.check():
305                                                 simulTimerList = timersanitycheck.getSimulTimerList()
306                                                 if simulTimerList is not None:
307                                                         self.session.openWithCallback(self.finishedEdit, TimerSanityConflict, timersanitycheck.getSimulTimerList())
308                                         else:
309                                                 success = True
310                         else:
311                                 success = True
312                         if success:
313                                 print "[TimerEditList] sanity check passed"
314                                 self.session.nav.RecordTimer.timeChanged(entry)
315
316                         self.fillTimerList()
317                         self.updateState()
318                 else:
319                         print "[TimerEditList] timer edit aborted"
320
321         def finishedAdd(self, answer):
322                 print "[TimerEditList] finished add"
323                 if answer[0]:
324                         entry = answer[1]
325                         simulTimerList = self.session.nav.RecordTimer.record(entry)
326                         if simulTimerList is not None:
327                                 for x in simulTimerList:
328                                         if x.setAutoincreaseEnd(entry):
329                                                 self.session.nav.RecordTimer.timeChanged(x)
330                                 simulTimerList = self.session.nav.RecordTimer.record(entry)
331                                 if simulTimerList is not None:
332                                         self.session.openWithCallback(self.finishSanityCorrection, TimerSanityConflict, simulTimerList)
333                         self.fillTimerList()
334                         self.updateState()
335                 else:
336                         print "[TimerEditList] timer edit aborted"
337
338         def finishSanityCorrection(self, answer):
339                 self.finishedAdd(answer)
340
341         def leave(self):
342                 self.session.nav.RecordTimer.on_state_change.remove(self.onStateChange)
343                 self.close()
344
345         def onStateChange(self, entry):
346                 self.refill()
347                 self.updateState()
348
349 confirmConflict = True
350
351 class TimerSanityConflict(Screen):
352         def __init__(self, session, timer):
353                 Screen.__init__(self, session)
354                 self.skinName = "TimerEditList"
355                 self.timer = timer
356
357                 self.list = []
358                 count = 0
359                 for x in timer:
360                         self.list.append((timer[count], False))
361                         count += 1
362                 if count == 1:
363                         self.setTitle((_("Channel not in services list")))
364                 else:
365                         self.setTitle(_("Timer sanity error"))
366
367                 self["timerlist"] = TimerList(self.list)
368
369                 self["key_red"] = Button(_("Cancel"))
370                 self["key_green"] = Button(" ")
371                 self["key_yellow"] = Button(" ")
372                 self["key_blue"] = Button(" ")
373
374                 self["actions"] = ActionMap(["OkCancelActions", "DirectionActions", "ShortcutActions", "TimerEditActions"],
375                         {
376                                 "cancel": self.leave_cancel,
377                                 "red": self.leave_cancel,
378                                 "green": self.editTimer,
379                                 "ok": self.editTimer,
380                                 "yellow": self.toggleTimer,
381                                 "blue": self.ignoreConflict,
382                                 "up": self.up,
383                                 "down": self.down,
384                                 "log": self.showLog
385                         }, -1)
386                 self.onShown.append(self.updateState)
387
388         def getTimerList(self, timer):
389                 return [(timer, False)]
390
391         def editTimer(self):
392                 self.session.openWithCallback(self.editTimerCallBack, TimerEntry, self["timerlist"].getCurrent())
393
394         def showLog(self):
395                 selected_timer = self["timerlist"].getCurrent()
396                 if selected_timer:
397                         self.session.openWithCallback(self.editTimerCallBack, TimerLog, selected_timer)
398
399         def editTimerCallBack(self, answer=None):
400                 if answer and len(answer) > 1 and answer[0] is True:
401                         self.session.nav.RecordTimer.timeChanged(answer[1])
402                         self.leave_ok()
403
404         def toggleTimer(self):
405                 selected_timer = self["timerlist"].getCurrent()
406                 if selected_timer and self["key_yellow"].getText() != " ":
407                         selected_timer.disabled = not selected_timer.disabled
408                         self.session.nav.RecordTimer.timeChanged(selected_timer)
409                         self.leave_ok()
410
411         def ignoreConflict(self):
412                         selected_timer = self["timerlist"].getCurrent()
413                         if selected_timer and selected_timer.conflict_detection:
414                                 if confirmConflict:
415                                         list = [(_("yes"), True), (_("no"), False), (_("yes") + " " + _("and never ask again this session again"), "never")]
416                                         self.session.openWithCallback(self.ignoreConflictConfirm, MessageBox, _("Warning!\nThis is an option for advanced users.\nReally disable timer conflict detection?"), list=list)
417                                 else:
418                                         self.ignoreConflictConfirm(True)
419
420         def ignoreConflictConfirm(self, answer):
421                 selected_timer = self["timerlist"].getCurrent()
422                 if answer and selected_timer and selected_timer.conflict_detection:
423                         if answer == "never":
424                                 global confirmConflict
425                                 confirmConflict = False
426                         selected_timer.conflict_detection = False
427                         selected_timer.disabled = False
428                         self.session.nav.RecordTimer.timeChanged(selected_timer)
429                         self.leave_ok()
430
431         def leave_ok(self):
432                 if self.isResolvedConflict():
433                         self.close((True, self.timer[0]))
434                 else:
435                         self.timer[0].disabled = True
436                         self.session.nav.RecordTimer.timeChanged(self.timer[0])
437                         self.updateState()
438                         self.session.open(MessageBox, _("Conflict not resolved!"), MessageBox.TYPE_ERROR, timeout=3)
439
440         def leave_cancel(self):
441                 isTimerSave = self.timer[0] in self.session.nav.RecordTimer.timer_list
442                 if self.isResolvedConflict() or not isTimerSave:
443                         self.close((False, self.timer[0]))
444                 else:
445                         timer_text = ""
446                         if not self.timer[0].isRunning():
447                                 self.timer[0].disabled = True
448                                 self.session.nav.RecordTimer.timeChanged(self.timer[0])
449                                 timer_text = _("\nTimer '%s' disabled!") % self.timer[0].name
450                         self.session.openWithCallback(self.canceling, MessageBox, _("Conflict not resolved!") + timer_text, MessageBox.TYPE_INFO, timeout=3)
451
452         def canceling(self, answer=None):
453                 self.close((False, self.timer[0]))
454
455         def isResolvedConflict(self):
456                 timersanitycheck = TimerSanityCheck(self.session.nav.RecordTimer.timer_list, self.timer[0])
457                 success = False
458                 if not timersanitycheck.check():
459                         simulTimerList = timersanitycheck.getSimulTimerList()
460                         if simulTimerList is not None:
461                                 for x in simulTimerList:
462                                         if x.setAutoincreaseEnd(self.timer[0]):
463                                                 self.session.nav.RecordTimer.timeChanged(x)
464                                 if timersanitycheck.check():
465                                         success = True
466                 else:
467                         success = True
468                 return success
469
470         def up(self):
471                 self["timerlist"].instance.moveSelection(self["timerlist"].instance.moveUp)
472                 self.updateState()
473
474         def down(self):
475                 self["timerlist"].instance.moveSelection(self["timerlist"].instance.moveDown)
476                 self.updateState()
477
478         def updateState(self):
479                 selected_timer = self["timerlist"].getCurrent()
480                 if selected_timer:
481                         self["key_green"].setText(_("Edit"))
482                         if selected_timer.disabled:
483                                 self["key_yellow"].setText(_("Enable"))
484                         elif selected_timer.isRunning() and not selected_timer.repeated:
485                                 self["key_yellow"].setText(" ")
486                         elif not selected_timer.isRunning() or selected_timer.repeated:
487                                 self["key_yellow"].setText(_("Disable"))
488                         if selected_timer.conflict_detection:
489                                 self["key_blue"].setText(_("Ignore conflict"))
490                         else:
491                                 self["key_blue"].setText(" ")
492                 else:
493                         self["key_green"].setText(" ")
494                         self["key_yellow"].setText(" ")
495                         self["key_blue"].setText(" ")