add some more useable characters for the match title property, thanks to dandjo!
[vuplus_dvbapp-plugin] / autotimer / src / AutoTimerEditor.py
1 # -*- coding: UTF-8 -*-
2 # for localized messages
3 from . import _
4
5 # GUI (Screens)
6 from Screens.Screen import Screen
7 from Components.ConfigList import ConfigListScreen
8 from Screens.ChannelSelection import SimpleChannelSelection
9 from Screens.MessageBox import MessageBox
10 from Screens.ChoiceBox import ChoiceBox
11
12 # GUI (Summary)
13 from Screens.Setup import SetupSummary
14
15 # GUI (Components)
16 from Components.ActionMap import ActionMap
17 from Components.Button import Button
18
19 # Configuration
20 from Components.config import getConfigListEntry, ConfigEnableDisable, \
21         ConfigYesNo, ConfigText, ConfigClock, ConfigNumber, ConfigSelection, \
22         config
23
24 # Timer
25 from RecordTimer import AFTEREVENT
26
27 # Needed to convert our timestamp back and forth
28 from time import localtime, mktime
29
30 # Show ServiceName instead of ServiceReference
31 from ServiceReference import ServiceReference
32
33 # addAutotimerFromService
34 from enigma import eServiceCenter, iServiceInformation
35
36 # Default Record Directory
37 from Tools import Directories
38
39 weekdays = [
40         ("0", _("Monday")),
41         ("1", _("Tuesday")),
42         ("2", _("Wednesday")),
43         ("3", _("Thursday")),
44         ("4", _("Friday")),
45         ("5", _("Saturday")),
46         ("6", _("Sunday")),
47         ("weekend", _("Weekend")),
48         ("weekday", _("Weekday"))
49 ]
50
51 class SimpleBouquetSelection(SimpleChannelSelection):
52         def __init__(self, session, title):
53                 SimpleChannelSelection.__init__(self, session, title)
54                 self.skinName = "SimpleChannelSelection"
55
56         def channelSelected(self): # just return selected service
57                 ref = self.getCurrentSelection()
58                 if (ref.flags & 7) == 7:
59                         self.close(ref)
60                 else:
61                         # We return the currently active path here
62                         # Asking the user if this is what he wants might be better though
63                         self.close(self.servicePath[-1])
64
65 class AutoTimerEditorBase():
66         """ Base Class for all Editors """
67         def __init__(self, timer, editingDefaults = False):
68                 # Keep Timer
69                 self.timer = timer
70                 self.editingDefaults = editingDefaults
71
72                 # See if we are filtering some strings
73                 self.excludes = (
74                         timer.getExcludedTitle(),
75                         timer.getExcludedShort(),
76                         timer.getExcludedDescription(),
77                         timer.getExcludedDays()
78                 )
79                 self.includes = (
80                         timer.getIncludedTitle(),
81                         timer.getIncludedShort(),
82                         timer.getIncludedDescription(),
83                         timer.getIncludedDays()
84                 )
85                 if len(self.excludes[0]) or len(self.excludes[1]) \
86                                 or len(self.excludes[2]) or len(self.excludes[3]) \
87                                 or len(self.includes[0]) or len(self.includes[1]) \
88                                 or len(self.includes[2]) or len(self.includes[3]):
89                         self.filterSet = True
90                 else:
91                         self.filterSet = False
92
93                 # See if services are restricted
94                 self.services = timer.getServices()
95                 self.bouquets = timer.getBouquets()
96                 if len(self.services) or len(self.bouquets):
97                         self.serviceRestriction = True
98                 else:
99                         self.serviceRestriction = False
100
101                 self.createSetup(timer)
102
103         def createSetup(self, timer):
104                 # Name
105                 self.name = ConfigText(default = timer.name, fixed_size = False)
106
107                 # Match
108                 self.match = ConfigText(default = timer.match, fixed_size = False)
109                 self.match.setUseableChars('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789-_?!.:;,&%()\'"+/$@') # XXX: what exactly is useable? :-)
110
111                 # Justplay
112                 self.justplay = ConfigSelection(choices = [("zap", _("zap")), ("record", _("record"))], default = {0: "record", 1: "zap"}[int(timer.justplay)])
113
114                 # Timespan
115                 now = [x for x in localtime()]
116                 if timer.hasTimespan():
117                         default = True
118                         now[3] = timer.timespan[0][0]
119                         now[4] = timer.timespan[0][1]
120                         begin = mktime(now)
121                         now[3] = timer.timespan[1][0]
122                         now[4] = timer.timespan[1][1]
123                         end = mktime(now)
124                 else:
125                         default = False
126                         now[3] = 20
127                         now[4] = 15
128                         begin = mktime(now)
129                         now[3] = 23
130                         now[4] = 15
131                         end = mktime(now)
132                 self.timespan = ConfigEnableDisable(default = default)
133                 self.timespanbegin = ConfigClock(default = begin)
134                 self.timespanend = ConfigClock(default = end)
135
136                 # Services have their own Screen
137
138                 # Offset
139                 if timer.hasOffset():
140                         default = True
141                         begin = timer.getOffsetBegin()
142                         end = timer.getOffsetEnd()
143                 else:
144                         default = False
145                         begin = 5
146                         end = 5
147                 self.offset = ConfigEnableDisable(default = default)
148                 self.offsetbegin = ConfigNumber(default = begin)
149                 self.offsetend = ConfigNumber(default = end)
150
151                 # AfterEvent
152                 if timer.hasAfterEvent():
153                         afterevent = { None: "default", AFTEREVENT.NONE: "nothing", AFTEREVENT.DEEPSTANDBY: "deepstandby", AFTEREVENT.STANDBY: "standby"}[timer.afterevent[0][0]]
154                 else:
155                         afterevent = "default"
156                 self.afterevent = ConfigSelection(choices = [("default", _("standard")), ("nothing", _("do nothing")), ("standby", _("go to standby")), ("deepstandby", _("go to deep standby"))], default = afterevent)
157
158                 # AfterEvent (Timespan)
159                 if timer.hasAfterEvent() and timer.afterevent[0][1][0] is not None:
160                         default = True
161                         now[3] = timer.afterevent[0][1][0][0]
162                         now[4] = timer.afterevent[0][1][0][1]
163                         begin = mktime(now)
164                         now[3] = timer.afterevent[0][1][1][0]
165                         now[4] = timer.afterevent[0][1][1][1]
166                         end = mktime(now)
167                 else:
168                         default = False
169                         now[3] = 23
170                         now[4] = 15
171                         begin = mktime(now)
172                         now[3] = 7
173                         now[4] = 0
174                         end = mktime(now)
175                 self.afterevent_timespan = ConfigEnableDisable(default = default)
176                 self.afterevent_timespanbegin = ConfigClock(default = begin)
177                 self.afterevent_timespanend = ConfigClock(default = end)
178
179                 # Enabled
180                 self.enabled = ConfigYesNo(default = timer.enabled)
181
182                 # Maxduration
183                 if timer.hasDuration():
184                         default = True
185                         duration = timer.getDuration()
186                 else:
187                         default = False
188                         duration =70
189                 self.duration = ConfigEnableDisable(default = default)
190                 self.durationlength = ConfigNumber(default = duration)
191
192                 # Counter
193                 if timer.hasCounter():
194                         default = timer.matchCount
195                 else:
196                         default = 0
197                 self.counter = ConfigNumber(default = default)
198                 self.counterLeft = ConfigNumber(default = timer.matchLeft)
199                 selection = [("", _("Never")), ("%m", _("Monthly")), ("%U", _("Weekly (Sunday)")), ("%W", _("Weekly (Monday)"))]
200                 if timer.getCounterFormatString() not in ["", "%m", "%U", "%W"]:
201                         selection.append((timer.getCounterFormatString(), _("Custom (%s)") % (timer.getCounterFormatString())))
202                 self.counterFormatString = ConfigSelection(selection, default = timer.getCounterFormatString())
203
204                 # Avoid Duplicate Description
205                 self.avoidDuplicateDescription = ConfigSelection([
206                                 ("0", _("No")),
207                                 ("1", _("On same service")),
208                                 ("2", _("On any service")),
209                         ],
210                         default = str(timer.getAvoidDuplicateDescription())
211                 )
212
213                 # Custom Location
214                 if timer.hasDestination():
215                         default = True
216                 else:
217                         default = False
218
219                 self.useDestination = ConfigYesNo(default = default)
220
221                 default = timer.destination or Directories.resolveFilename(Directories.SCOPE_HDD)
222                 choices = config.movielist.videodirs.value
223
224                 if default not in choices:
225                         choices.append(default)
226                 self.destination = ConfigSelection(default = default, choices = choices)
227
228         def pathSelected(self, res):
229                 if res is not None:
230                         if res not in self.destination.choices:
231                                 self.destination.choices.append(res)
232                                 self.destination.description[res] = res
233                         self.destination.value = res
234
235         def chooseDestination(self):
236                 from Screens.LocationBox import MovieLocationBox
237
238                 self.session.openWithCallback(
239                         self.pathSelected,
240                         MovieLocationBox,
241                         _("Choose target folder"),
242                         self.destination.value,
243                         minFree = 100 # Same requirement as in Screens.TimerEntry
244                 )
245
246 class AutoTimerEditor(Screen, ConfigListScreen, AutoTimerEditorBase):
247         """Edit AutoTimer"""
248
249         skin = """<screen name="AutoTimerEdit" title="Edit AutoTimer" position="75,155" size="565,280">
250                 <widget name="config" position="5,5" size="555,225" scrollbarMode="showOnDemand" />
251                 <ePixmap position="0,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
252                 <ePixmap position="140,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
253                 <ePixmap position="280,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
254                 <ePixmap position="420,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
255                 <widget name="key_red" position="0,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
256                 <widget name="key_green" position="140,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
257                 <widget name="key_yellow" position="280,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
258                 <widget name="key_blue" position="420,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
259         </screen>"""
260
261         def __init__(self, session, timer, editingDefaults = False):
262                 Screen.__init__(self, session)
263
264                 AutoTimerEditorBase.__init__(self, timer, editingDefaults)
265
266                 # Summary
267                 self.setup_title = "AutoTimer Editor"
268                 self.onChangedEntry = []
269
270                 # We might need to change shown items, so add some notifiers
271                 self.timespan.addNotifier(self.reloadList, initial_call = False)
272                 self.offset.addNotifier(self.reloadList, initial_call = False)
273                 self.duration.addNotifier(self.reloadList, initial_call = False)
274                 self.afterevent.addNotifier(self.reloadList, initial_call = False)
275                 self.afterevent_timespan.addNotifier(self.reloadList, initial_call = False)
276                 self.counter.addNotifier(self.reloadList, initial_call = False)
277                 self.useDestination.addNotifier(self.reloadList, initial_call = False)
278
279                 self.refresh()
280
281                 ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
282
283                 # Initialize Buttons
284                 self["key_red"] = Button(_("Cancel"))
285                 self["key_green"] = Button(_("OK"))
286                 self["key_yellow"] = Button()
287                 self["key_blue"] = Button()
288
289                 # Set Button texts
290                 self.renameServiceButton()
291                 self.renameFilterButton()
292
293                 # Define Actions
294                 self["actions"] = ActionMap(["SetupActions", "ColorActions"],
295                         {
296                                 "cancel": self.cancel,
297                                 "save": self.maybeSave,
298                                 "ok": self.ok,
299                                 "yellow": self.editFilter,
300                                 "blue": self.editServices
301                         }, -2
302                 )
303
304                 # Trigger change
305                 self.changed()
306
307         def renameFilterButton(self):
308                 if self.filterSet:
309                         self["key_yellow"].setText(_("Edit Filters"))
310                 else:
311                         self["key_yellow"].setText(_("Add Filters"))
312
313         def renameServiceButton(self):
314                 if self.serviceRestriction:
315                         self["key_blue"].setText(_("Edit Services"))
316                 else:
317                         self["key_blue"].setText(_("Add Services"))
318
319         def changed(self):
320                 for x in self.onChangedEntry:
321                         try:
322                                 x()
323                         except:
324                                 pass
325
326         def getCurrentEntry(self):
327                 return self["config"].getCurrent()[0]
328
329         def getCurrentValue(self):
330                 return str(self["config"].getCurrent()[1].getText())
331
332         def createSummary(self):
333                 return SetupSummary
334
335         def refresh(self):
336                 # First three entries are only showed when not editing defaults
337                 self.list = []
338                 if not self.editingDefaults:
339                         self.list.extend([
340                                 getConfigListEntry(_("Enabled"), self.enabled),
341                                 getConfigListEntry(_("Description"), self.name),
342                                 getConfigListEntry(_("Match Title"), self.match),
343                         ])
344
345                 self.list.extend([
346                         getConfigListEntry(_("Timer Type"), self.justplay),
347                         getConfigListEntry(_("Only match during Timespan"), self.timespan)
348                 ])
349
350                 # Only allow editing timespan when it's enabled
351                 if self.timespan.value:
352                         self.list.extend([
353                                 getConfigListEntry(_("Begin of Timespan"), self.timespanbegin),
354                                 getConfigListEntry(_("End of Timespan"), self.timespanend)
355                         ])
356
357                 self.list.append(getConfigListEntry(_("Custom offset"), self.offset))
358
359                 # Only allow editing offsets when it's enabled
360                 if self.offset.value:
361                         self.list.extend([
362                                 getConfigListEntry(_("Offset before recording (in m)"), self.offsetbegin),
363                                 getConfigListEntry(_("Offset after recording (in m)"), self.offsetend)
364                         ])
365
366                 self.list.append(getConfigListEntry(_("Set maximum Duration"), self.duration))
367
368                 # Only allow editing maxduration when it's enabled
369                 if self.duration.value:
370                         self.list.append(getConfigListEntry(_("Maximum Duration (in m)"), self.durationlength))
371
372                 self.list.append(getConfigListEntry(_("After event"), self.afterevent))
373
374                 # Only allow setting afterevent timespan when afterevent is active
375                 if self.afterevent.value != "default":
376                         self.list.append(getConfigListEntry(_("Execute after Event during Timespan"), self.afterevent_timespan))
377
378                         # Only allow editing timespan when it's enabled
379                         if self.afterevent_timespan.value:
380                                 self.list.extend([
381                                         getConfigListEntry(_("Begin of after Event Timespan"), self.afterevent_timespanbegin),
382                                         getConfigListEntry(_("End of after Event Timespan"), self.afterevent_timespanend)
383                                 ])
384
385                 self.list.append(getConfigListEntry(_("Record a maximum of x times"), self.counter))
386
387                 # Only allow setting matchLeft when counting hits
388                 if self.counter.value:
389                         if not self.editingDefaults:
390                                 self.list.append(getConfigListEntry(_("Ammount of recordings left"), self.counterLeft))
391                         self.list.append(getConfigListEntry(_("Reset Count"), self.counterFormatString))
392
393                 self.list.append(getConfigListEntry(_("Require Description to be unique"), self.avoidDuplicateDescription))
394
395                 # We always add this option though its expert only in enigma2
396                 self.list.append(getConfigListEntry(_("Use a custom location"), self.useDestination))
397                 if self.useDestination.value:
398                         self.list.append(getConfigListEntry(_("Custom Location"), self.destination))
399
400         def reloadList(self, value):
401                 self.refresh()
402                 self["config"].setList(self.list)
403
404         def editFilter(self):
405                 self.session.openWithCallback(
406                         self.editFilterCallback,
407                         AutoTimerFilterEditor,
408                         self.filterSet,
409                         self.excludes,
410                         self.includes
411                 )
412
413         def editFilterCallback(self, ret):
414                 if ret:
415                         self.filterSet = ret[0]
416                         self.excludes = ret[1]
417                         self.includes = ret[2]
418                         self.renameFilterButton()
419
420         def editServices(self):
421                 self.session.openWithCallback(
422                         self.editServicesCallback,
423                         AutoTimerServiceEditor,
424                         self.serviceRestriction,
425                         self.services,
426                         self.bouquets
427                 )
428
429         def editServicesCallback(self, ret):
430                 if ret:
431                         self.serviceRestriction = ret[0]
432                         self.services = ret[1][0]
433                         self.bouquets = ret[1][1]
434                         self.renameServiceButton()
435
436         def ok(self):
437                 cur = self["config"].getCurrent()
438                 cur = cur and cur[1]
439                 if cur == self.destination:
440                         self.chooseDestination()
441                 else:
442                         ConfigListScreen.keyOK(self)
443
444         def cancel(self):
445                 if self["config"].isChanged():
446                         self.session.openWithCallback(
447                                 self.cancelConfirm,
448                                 MessageBox,
449                                 _("Really close without saving settings?")
450                         )
451                 else:
452                         self.close(None)
453
454         def cancelConfirm(self, ret):
455                 if ret:
456                         self.close(None)
457
458         def maybeSave(self):
459                 # Check if any match is set
460                 if not self.match.value.strip():
461                         self.session.open(
462                                         MessageBox,
463                                         _("The match attribute is mandatory."),
464                                         type = MessageBox.TYPE_ERROR,
465                                         timeout = 5
466                         )
467                 # Check if we have a trailing whitespace
468                 elif self.match.value[-1:] == " ":
469                         self.session.openWithCallback(
470                                 self.saveCallback,
471                                 MessageBox,
472                                 _('You entered "%s" as Text to match.\nDo you want to remove trailing whitespaces?') % (self.match.value)
473                         )
474                 # Just save else
475                 else:
476                         self.save()
477
478         def saveCallback(self, ret):
479                 if ret is not None:
480                         if ret:
481                                 self.match.value = self.match.value.rstrip()
482                         self.save()
483                 # Don't to anything if MessageBox was canceled!
484
485         def save(self):
486                 # Match
487                 self.timer.match = self.match.value
488
489                 # Name
490                 self.timer.name = self.name.value.strip() or self.timer.match
491
492                 # Enabled
493                 self.timer.enabled = self.enabled.value
494
495                 # Justplay
496                 self.timer.justplay = self.justplay.value == "zap"
497
498                 # Timespan
499                 if self.timespan.value:
500                         start = self.timespanbegin.value
501                         end = self.timespanend.value
502                         self.timer.timespan = (start, end)
503                 else:
504                         self.timer.timespan = None
505
506                 # Services
507                 if self.serviceRestriction:
508                         self.timer.services = self.services
509                         self.timer.bouquets = self.bouquets
510                 else:
511                         self.timer.services = None
512                         self.timer.bouquets = None
513
514                 # Offset
515                 if self.offset.value:
516                         self.timer.offset = (self.offsetbegin.value*60, self.offsetend.value*60)
517                 else:
518                         self.timer.offset = None
519
520                 # AfterEvent
521                 if self.afterevent.value == "default":
522                         self.timer.afterevent = []
523                 else:
524                         afterevent = {"nothing": AFTEREVENT.NONE, "deepstandby": AFTEREVENT.DEEPSTANDBY, "standby": AFTEREVENT.STANDBY}[self.afterevent.value]
525                         # AfterEvent Timespan
526                         if self.afterevent_timespan.value:
527                                 start = self.afterevent_timespanbegin.value
528                                 end = self.afterevent_timespanend.value
529                                 self.timer.afterevent = [(afterevent, (start, end))]
530                         else:
531                                 self.timer.afterevent = [(afterevent, None)]
532
533                 # Maxduration
534                 if self.duration.value:
535                         self.timer.maxduration = self.durationlength.value*60
536                 else:
537                         self.timer.maxduration = None
538
539                 # Ex-&Includes
540                 if self.filterSet:
541                         self.timer.exclude = self.excludes
542                         self.timer.include = self.includes
543                 else:
544                         self.timer.exclude = None
545                         self.timer.include = None
546
547                 # Counter
548                 if self.counter.value:
549                         self.timer.matchCount = self.counter.value
550                         if self.counterLeft.value <= self.counter.value:
551                                 self.timer.matchLeft = self.counterLeft.value
552                         else:
553                                 self.timer.matchLeft = self.counter.value
554                         if self.counterFormatString.value:
555                                 self.timer.matchFormatString = self.counterFormatString.value
556                         else:
557                                 self.timer.matchFormatString = ''
558                 else:
559                         self.timer.matchCount = 0
560                         self.timer.matchLeft = 0
561                         self.timer.matchFormatString = ''
562
563                 self.timer.avoidDuplicateDescription = int(self.avoidDuplicateDescription.value)
564
565                 if self.useDestination.value:
566                         self.timer.destination = self.destination.value
567                 else:
568                         self.timer.destination = None
569
570                 # Close
571                 self.close(self.timer)
572
573 class AutoTimerFilterEditor(Screen, ConfigListScreen):
574         """Edit AutoTimer Filter"""
575
576         skin = """<screen name="AutoFilterEditor" title="Edit AutoTimer Filters" position="75,150" size="565,245">
577                 <widget name="config" position="5,5" size="555,200" scrollbarMode="showOnDemand" />
578                 <ePixmap position="5,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
579                 <ePixmap position="145,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
580                 <ePixmap position="285,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
581                 <ePixmap position="425,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
582                 <widget name="key_red" position="5,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
583                 <widget name="key_green" position="145,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
584                 <widget name="key_yellow" position="285,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
585                 <widget name="key_blue" position="425,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
586         </screen>"""
587
588         def __init__(self, session, filterset, excludes, includes):
589                 Screen.__init__(self, session)
590
591                 # Summary
592                 self.setup_title = "AutoTimer Filters"
593                 self.onChangedEntry = []
594
595                 self.typeSelection = ConfigSelection(choices = [("title", _("in Title")), ("short", _("in Shortdescription")), ("desc", _("in Description")), ("day", _("on Weekday"))])
596                 self.typeSelection.addNotifier(self.refresh, initial_call = False)
597
598                 self.enabled = ConfigEnableDisable(default = filterset)
599
600                 self.excludes = excludes
601                 self.includes = includes
602
603                 self.reloadList()
604
605                 ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
606
607                 # Initialize Buttons
608                 self["key_red"] = Button(_("Cancel"))
609                 self["key_green"] = Button(_("Save"))
610                 self["key_yellow"] = Button(_("delete"))
611                 self["key_blue"] = Button(_("New"))
612
613                 # Define Actions
614                 self["actions"] = ActionMap(["SetupActions", "ColorActions"],
615                         {
616                                 "cancel": self.cancel,
617                                 "save": self.save,
618                                 "yellow": self.remove,
619                                 "blue": self.new
620                         }
621                 )
622
623                 # Trigger change
624                 self.changed()
625
626         def changed(self):
627                 for x in self.onChangedEntry:
628                         try:
629                                 x()
630                         except:
631                                 pass
632
633         def getCurrentEntry(self):
634                 return self["config"].getCurrent()[0]
635
636         def getCurrentValue(self):
637                 return str(self["config"].getCurrent()[1].getText())
638
639         def createSummary(self):
640                 return SetupSummary
641
642         def saveCurrent(self):
643                 del self.excludes[self.idx][:]
644                 del self.includes[self.idx][:]
645
646                 # Warning, accessing a ConfigListEntry directly might be considered evil!
647
648                 idx = -1
649                 for item in self["config"].getList()[:]:
650                         idx += 1
651                         # Skip empty entries (and those which are no filters)
652                         if item[1].value == "" or idx < 2:
653                                 continue
654                         elif idx < self.lenExcludes:
655                                 self.excludes[self.idx].append(item[1].value.encode("UTF-8"))
656                         else:
657                                 self.includes[self.idx].append(item[1].value.encode("UTF-8"))
658
659         def refresh(self, *args, **kwargs):
660                 self.saveCurrent()
661
662                 self.reloadList()
663                 self["config"].setList(self.list)
664
665         def reloadList(self):
666                 self.list = [
667                         getConfigListEntry(_("Enable Filtering"), self.enabled),
668                         getConfigListEntry(_("Filter"), self.typeSelection)
669                 ]
670
671                 if self.typeSelection.value == "day":
672                         self.idx = 3
673
674                         # Weekdays are presented as ConfigSelection
675                         self.list.extend([
676                                 getConfigListEntry(_("Exclude"), ConfigSelection(choices = weekdays, default = x))
677                                         for x in self.excludes[3]
678                         ])
679                         self.lenExcludes = len(self.list)
680                         self.list.extend([
681                                 getConfigListEntry(_("Include"), ConfigSelection(choices = weekdays, default = x))
682                                         for x in self.includes[3]
683                         ])
684                         return
685                 elif self.typeSelection.value == "title":
686                         self.idx = 0
687                 elif self.typeSelection.value == "short":
688                         self.idx = 1
689                 else: # self.typeSelection.value == "desc":
690                         self.idx = 2
691
692                 self.list.extend([
693                         getConfigListEntry(_("Exclude"), ConfigText(default = x, fixed_size = False))
694                                 for x in self.excludes[self.idx]
695                 ])
696                 self.lenExcludes = len(self.list)
697                 self.list.extend([
698                         getConfigListEntry(_("Include"), ConfigText(default = x, fixed_size = False))
699                                 for x in self.includes[self.idx]
700                 ])
701
702         def remove(self):
703                 idx = self["config"].getCurrentIndex()
704                 if idx and idx > 1:
705                         if idx < self.lenExcludes:
706                                 self.lenExcludes -= 1
707
708                         list = self["config"].getList()
709                         list.remove(self["config"].getCurrent())
710                         self["config"].setList(list)
711
712         def new(self):
713                 self.session.openWithCallback(
714                         self.typeSelected,
715                         ChoiceBox,
716                         _("Select type of Filter"),
717                         [
718                                 (_("Exclude"), 0),
719                                 (_("Include"), 1),
720                         ]
721                 )
722
723         def typeSelected(self, ret):
724                 if ret is not None:
725                         list = self["config"].getList()
726
727                         if ret[1] == 0:
728                                 pos = self.lenExcludes
729                                 self.lenExcludes += 1
730                                 text = ret[0]
731                         else:
732                                 pos = len(self.list)
733                                 text = ret[0]
734
735                         if self.typeSelection.value == "day":
736                                 entry = getConfigListEntry(text, ConfigSelection(choices = weekdays))
737                         else:
738                                 entry = getConfigListEntry(text, ConfigText(fixed_size = False))
739
740                         list.insert(pos, entry)
741                         self["config"].setList(list)
742
743         def cancel(self):
744                 if self["config"].isChanged():
745                         self.session.openWithCallback(
746                                 self.cancelConfirm,
747                                 MessageBox,
748                                 _("Really close without saving settings?")
749                         )
750                 else:
751                         self.close(None)
752
753         def cancelConfirm(self, ret):
754                 if ret:
755                         self.close(None)
756
757         def save(self):
758                 self.refresh()
759
760                 self.close((
761                         self.enabled.value,
762                         self.excludes,
763                         self.includes
764                 ))
765
766 class AutoTimerServiceEditor(Screen, ConfigListScreen):
767         """Edit allowed Services of a AutoTimer"""
768
769         skin = """<screen name="AutoTimerServiceEditor" title="Edit AutoTimer Services" position="75,150" size="565,245">
770                 <widget name="config" position="5,5" size="555,200" scrollbarMode="showOnDemand" />
771                 <ePixmap position="5,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
772                 <ePixmap position="145,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
773                 <ePixmap position="285,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
774                 <ePixmap position="425,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
775                 <widget name="key_red" position="5,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
776                 <widget name="key_green" position="145,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
777                 <widget name="key_yellow" position="285,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
778                 <widget name="key_blue" position="425,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
779         </screen>"""
780
781         def __init__(self, session, servicerestriction, servicelist, bouquetlist):
782                 Screen.__init__(self, session)
783
784                 # Summary
785                 self.setup_title = "AutoTimer Services"
786                 self.onChangedEntry = []
787
788                 self.services = (
789                         servicelist[:],
790                         bouquetlist[:]
791                 )
792
793                 self.enabled = ConfigEnableDisable(default = servicerestriction)
794                 self.typeSelection = ConfigSelection(choices = [("channels", _("Channels")), ("bouquets", _("Bouquets"))])
795                 self.typeSelection.addNotifier(self.refresh, initial_call = False)
796
797                 self.reloadList()
798
799                 ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
800
801                 # Initialize Buttons
802                 self["key_red"] = Button(_("Cancel"))
803                 self["key_green"] = Button(_("OK"))
804                 self["key_yellow"] = Button(_("delete"))
805                 self["key_blue"] = Button(_("New"))
806
807                 # Define Actions
808                 self["actions"] = ActionMap(["SetupActions", "ColorActions"],
809                         {
810                                 "cancel": self.cancel,
811                                 "save": self.save,
812                                 "yellow": self.remove,
813                                 "blue": self.new
814                         }
815                 )
816
817                 # Trigger change
818                 self.changed()
819
820         
821         def saveCurrent(self):
822                 del self.services[self.idx][:]
823                 
824                 # Warning, accessing a ConfigListEntry directly might be considered evil!
825
826                 myl = self["config"].getList()[:]
827                 myl.pop(0) # Enabled
828                 myl.pop(0) # Type
829                 for item in myl:
830                         self.services[self.idx].append(item[1].value)
831
832         def refresh(self, *args, **kwargs):
833                 self.saveCurrent()
834
835                 self.reloadList()
836                 self["config"].setList(self.list)
837
838         def reloadList(self):
839                 self.list = [
840                         getConfigListEntry(_("Enable Service Restriction"), self.enabled),
841                         getConfigListEntry(_("Editing"), self.typeSelection)
842                 ]
843                 
844                 if self.typeSelection.value == "channels":
845                         self.idx = 0
846                 else: # self.typeSelection.value == "bouquets":
847                         self.idx = 1
848
849                 self.list.extend([
850                         getConfigListEntry(_("Record on"), ConfigSelection(choices = [(str(x), ServiceReference(str(x)).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))]))
851                                 for x in self.services[self.idx]
852                 ])
853
854         def changed(self):
855                 for x in self.onChangedEntry:
856                         try:
857                                 x()
858                         except:
859                                 pass
860
861         def getCurrentEntry(self):
862                 return self["config"].getCurrent()[0]
863
864         def getCurrentValue(self):
865                 return str(self["config"].getCurrent()[1].getText())
866
867         def createSummary(self):
868                 return SetupSummary
869
870         def remove(self):
871                 if self["config"].getCurrentIndex() != 0:
872                         list = self["config"].getList()
873                         list.remove(self["config"].getCurrent())
874                         self["config"].setList(list)
875
876         def new(self):
877                 if self.typeSelection.value == "channels":
878                         self.session.openWithCallback(
879                                 self.finishedServiceSelection,
880                                 SimpleChannelSelection,
881                                 _("Select channel to record on")
882                         )
883                 else: # self.typeSelection.value == "bouquets":
884                         self.session.openWithCallback(
885                                 self.finishedServiceSelection,
886                                 SimpleBouquetSelection,
887                                 _("Select bouquet to record on")
888                         )
889
890         def finishedServiceSelection(self, *args):
891                 if len(args):
892                         list = self["config"].getList()
893                         sname = args[0].toString()
894
895                         if self.typeSelection.value == "channels":
896                                 # strip all after last : when adding a channel
897                                 pos = sname.rfind(':')
898                                 if pos != -1:
899                                         sname = sname[:pos+1]
900
901                         list.append(getConfigListEntry(_("Record on"), ConfigSelection(choices = [(sname, ServiceReference(args[0]).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))])))
902                         self["config"].setList(list)
903
904         def cancel(self):
905                 if self["config"].isChanged():
906                         self.session.openWithCallback(
907                                 self.cancelConfirm,
908                                 MessageBox,
909                                 _("Really close without saving settings?")
910                         )
911                 else:
912                         self.close(None)
913
914         def cancelConfirm(self, ret):
915                 if ret:
916                         self.close(None)
917
918         def save(self):
919                 self.refresh()
920
921                 self.close((
922                         self.enabled.value,
923                         self.services
924                 ))
925
926 def addAutotimerFromEvent(session, evt = None, service = None):
927         from AutoTimerComponent import AutoTimerComponent
928         from AutoTimerImporter import AutoTimerImporter
929         from plugin import autotimer
930                 
931         # Create instance if needed
932         if autotimer is None:
933                 from AutoTimer import AutoTimer
934                 autotimer = AutoTimer()
935                 autotimer.readXml()
936
937         match = evt and evt.getEventName() or ""
938         name = match or "New AutoTimer"
939         sref = None
940         if service is not None:
941                 service = str(service)
942                 # strip all after last :
943                 pos = service.rfind(':')
944                 if pos != -1:
945                         service = service[:pos+1]
946
947                 sref = ServiceReference(service)
948         if evt:
949                  # timespan defaults to +- 1h
950                 begin = evt.getBeginTime()-3600
951                 end = begin + evt.getDuration()+7200
952         else:
953                 begin = end = 0
954
955         # XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
956
957         session.openWithCallback(
958                 importerCallback,
959                 AutoTimerImporter,
960                 AutoTimerComponent(
961                         autotimer.getUniqueId(),                # Id
962                         name,                                                   # Name
963                         "",                                                             # Match
964                         True                                                    # Enabled
965                 ),
966                 match,                     # Proposed Match
967                 begin,                     # Proposed Begin
968                 end,                       # Proposed End
969                 None,                      # Proposed Disabled
970                 sref,                      # Proposed ServiceReference
971                 None,                  # Proposed afterEvent 
972                 None,                      # Proposed justplay 
973                 None                       # Proposed dirname, can we get anything useful here? 
974         )
975
976 def addAutotimerFromService(session, service = None):   
977         from AutoTimerComponent import AutoTimerComponent
978         from AutoTimerImporter import AutoTimerImporter
979         from plugin import autotimer
980                 
981         # Create instance if needed
982         if autotimer is None:
983                 from AutoTimer import AutoTimer
984                 autotimer = AutoTimer()
985                 autotimer.readXml()
986
987         serviceHandler = eServiceCenter.getInstance()
988         info = serviceHandler.info(service)
989
990         match = info and info.getName(service) or ""
991         name = match or "New AutoTimer"
992         sref = info and info.getInfoString(service, iServiceInformation.sServiceref)
993         if sref:
994                 # strip all after last :
995                 pos = sref.rfind(':')
996                 if pos != -1:
997                         sref = sref[:pos+1]
998
999                 sref = ServiceReference(sref)
1000         if info:
1001                 begin = info.getInfo(service, iServiceInformation.sTimeCreate)
1002                 end = begin + info.getLength(service)
1003         else:
1004                 begin = end = 0
1005
1006         # XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
1007
1008         session.openWithCallback(
1009                 importerCallback,
1010                 AutoTimerImporter,
1011                 AutoTimerComponent(
1012                         autotimer.getUniqueId(),                # Id
1013                         name,                                                   # Name
1014                         "",                                                             # Match
1015                         True                                                    # Enabled
1016                 ),
1017                 match,                     # Proposed Match
1018                 begin,                     # Proposed Begin
1019                 end,                       # Proposed End
1020                 None,                      # Proposed Disabled
1021                 sref,                      # Proposed ServiceReference
1022                 None,                  # Proposed afterEvent 
1023                 None,                      # Proposed justplay 
1024                 None                       # Proposed dirname, can we get anything useful here? 
1025         )
1026
1027 def importerCallback(ret):
1028         if ret:
1029                 ret, session = ret
1030                 
1031                 session.openWithCallback(
1032                         editorCallback,
1033                         AutoTimerEditor,
1034                         ret
1035                 )
1036         else:
1037                 # Remove instance if not running in background
1038                 if not config.plugins.autotimer.autopoll.value:
1039                         from plugin import autotimer
1040                         autotimer = None
1041
1042 def editorCallback(ret):
1043         if ret:
1044                 from plugin import autotimer
1045                 
1046                 # Create instance if needed (should have been created by addAutotimerFrom* above though)
1047                 if autotimer is None:
1048                         from AutoTimer import AutoTimer
1049                         autotimer = AutoTimer()
1050                         autotimer.readXml()
1051
1052                 autotimer.add(ret)
1053
1054         # Remove instance if not running in background
1055         if not config.plugins.autotimer.autopoll.value:
1056                 # Save xml (as long as we added something)
1057                 ret and autotimer and autotimer.writeXml()
1058                 autotimer = None
1059