d4c17b82253f1794cf1cca4548d0f3b6873453b7
[vuplus_dvbapp-plugin] / simplerss / src / RSSScreens.py
1 # for localized messages
2 from . import _
3
4 from enigma import eTimer
5
6 from Screens.Screen import Screen
7 from Screens.MessageBox import MessageBox
8
9 from Components.ActionMap import ActionMap
10 from Components.Label import Label
11 from Components.ScrollLabel import ScrollLabel
12
13 from RSSList import RSSFeedList, RSSEntryList
14
15 class RSSBaseView(Screen):
16         """Base Screen for all Screens used in SimpleRSS"""
17
18         def __init__(self, session, poller, parent = None):
19                 Screen.__init__(self, session, parent)
20                 self.rssPoller = poller
21                 self.pollDialog = None
22
23         def errorPolling(self, errmsg = ""):
24                 # An error occured while polling
25                 self.session.open(
26                         MessageBox,
27                         _("Error while parsing Feed, this usually means there is something wrong with it."),
28                         type = MessageBox.TYPE_ERROR,
29                         timeout = 3
30                 )
31
32                 # Don't show "we're updating"-dialog any longer
33                 if self.pollDialog:
34                         self.pollDialog.close()
35                         self.pollDialog = None
36
37         def singleUpdate(self, feedid, errback = None):
38                 # Don't do anything if we have no poller
39                 if self.rssPoller is None:
40                         return
41
42                 # Default errorback to self.errorPolling
43                 # If an empty errorback is wanted the Screen needs to provide it
44                 if errback is None:
45                         errback = self.errorPolling
46
47                 # Tell Poller to poll
48                 self.rssPoller.singlePoll(feedid, callback=True, errorback=errback)
49
50                 # Open Dialog and save locally
51                 self.pollDialog = self.session.open(
52                         MessageBox,
53                         _("Update is being done in Background.\nContents will automatically be updated when it's done."),
54                         type = MessageBox.TYPE_INFO,
55                         timeout = 5
56                 )
57
58         def selectEnclosure(self, enclosures):
59                 # Empty List
60                 if enclosures is None:
61                         return
62
63                 from Components.Scanner import openList
64
65                 if not openList(self.session, enclosures):
66                         self.session.open(
67                                 MessageBox,
68                                 _("Found no Enclosure we can display."),
69                                 type = MessageBox.TYPE_INFO,
70                                 timeout = 5
71                         )
72
73 class RSSEntryView(RSSBaseView):
74         """Shows a RSS Item"""
75
76         skin = """
77                 <screen position="100,100" size="460,420" title="Simple RSS Reader" >
78                         <widget name="info" position="0,0" size="460, 20" halign="right" font="Regular; 18" />
79                         <widget name="content" position="0,20" size="460,400" font="Regular; 22" />
80                 </screen>"""
81
82         def __init__(self, session, data, feedTitle="", cur_idx=None, entries=None, parent=None):
83                 RSSBaseView.__init__(self, session, None, parent)
84
85                 self.data = data
86                 self.feedTitle = feedTitle
87                 self.cur_idx = cur_idx
88                 self.entries = entries
89
90                 if cur_idx is not None and entries is not None:
91                         self["info"] = Label(_("Entry %s/%s") % (cur_idx+1, entries))
92                 else:
93                         self["info"] = Label()
94
95                 if data:
96                         self["content"] = ScrollLabel(''.join((data[0], '\n\n', data[2], '\n\n', str(len(data[3])), ' ',  _("Enclosures"))))
97                 else:
98                         self["content"] = ScrollLabel()
99
100                 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "ColorActions", "DirectionActions" ],
101                 {
102                         "cancel": self.close,
103                         "ok": self.selectEnclosure,
104                         "yellow": self.selectEnclosure,
105                         "up": self.up,
106                         "down": self.down,
107                         "right": self.next,
108                         "left": self.previous,
109                         "nextBouquet": self.nextFeed,
110                         "prevBouquet": self.previousFeed,
111                 })
112
113                 self.onLayoutFinish.append(self.setConditionalTitle)
114
115         def setConditionalTitle(self):
116                 self.setTitle(_("Simple RSS Reader: %s") % (self.feedTitle))
117
118         def up(self):
119                 self["content"].pageUp()
120
121         def down(self):
122                 self["content"].pageDown()
123
124         def next(self):
125                 if self.parent is not None:
126                         (self.data, self.cur_idx, self.entries) = self.parent.nextEntry()
127                         self.setContent()
128
129         def previous(self):
130                 if self.parent is not None:
131                         (self.data, self.cur_idx, self.entries) = self.parent.previousEntry()
132                         self.setContent()
133
134         def nextFeed(self):
135                 # Show next Feed
136                 if self.parent is not None:
137                         result = self.parent.next()
138                         self.feedTitle = result[0]
139                         self.entries = len(result[1])
140                         if self.entries:
141                                 self.cur_idx = 0
142                                 self.data = result[1][0]
143                         else:
144                                 self.cur_idx = None
145                                 self.data = None
146                         self.setConditionalTitle()
147                         self.setContent()
148
149         def previousFeed(self):
150                 # Show previous Feed
151                 if self.parent is not None:
152                         result = self.parent.previous()
153                         self.feedTitle = result[0]
154                         self.entries = len(result[1])
155                         if self.entries:
156                                 self.cur_idx = 0
157                                 self.data = result[1][0]
158                         else:
159                                 self.cur_idx = None
160                                 self.data = None
161                         self.setConditionalTitle()
162                         self.setContent()
163
164         def setContent(self):
165                 if self.cur_idx is not None and self.entries is not None:
166                         self["info"].setText(_("Entry %s/%s") % (self.cur_idx+1, self.entries))
167                 else:
168                         self["info"].setText("")
169                 data = self.data
170                 if data:
171                         self["content"].setText(''.join((data[0], '\n\n', data[2], '\n\n', str(len(data[3])), ' ',  _("Enclosures"))))
172                 else:
173                         self["content"].setText(_("No such Item."))
174
175         def selectEnclosure(self):
176                 if self.data is not None:
177                         RSSBaseView.selectEnclosure(self, self.data[3])
178
179 class RSSFeedView(RSSBaseView):
180         """Shows a RSS-Feed"""
181
182         skin = """
183                 <screen position="100,100" size="460,415" title="Simple RSS Reader" >
184                         <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
185                         <widget name="content" position="0,20" size="460,300" scrollbarMode="showOnDemand" />
186                         <widget name="summary" position="0,320" size="460,95" font="Regular;16" />
187                 </screen>"""
188
189         def __init__(self, session, feed=None, newItems=False, parent=None, rssPoller=None,id=None):
190                 RSSBaseView.__init__(self, session, rssPoller, parent)
191
192                 self.feed = feed
193                 self.newItems = newItems
194                 self.id = id
195
196                 self["content"] = RSSEntryList(self.feed.history)
197                 self["summary"] = Label()
198                 self["info"] = Label()
199
200                 if not newItems:
201                         self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "MenuActions", "ColorActions" ],
202                         {
203                                 "ok": self.showCurrentEntry,
204                                 "cancel": self.close,
205                                 "nextBouquet": self.next,
206                                 "prevBouquet": self.previous,
207                                 "menu": self.menu,
208                                 "yellow": self.selectEnclosure,
209                         })
210                         self.onLayoutFinish.append(self.__show)
211                         self.onClose.append(self.__close)
212
213                         self.timer = None
214                 else:
215                         self["actions"] = ActionMap([ "OkCancelActions" ],
216                         {
217                                 "cancel": self.close,
218                         })
219
220                         self.timer = eTimer()
221                         self.timer.callback.append(self.timerTick)
222                         self.onExecBegin.append(self.startTimer)
223
224                 self["content"].connectSelChanged(self.updateInfo)
225                 self.onLayoutFinish.extend([self.updateInfo, self.setConditionalTitle])
226
227         def startTimer(self):
228                 self.timer.startLongTimer(5)
229
230         def timerTick(self):
231                 self.timer.callback.remove(self.timerTick)
232
233                 self.close()
234
235         def __show(self):
236                 self.rssPoller.addCallback(self.pollCallback)
237
238         def __close(self):
239                 if self.timer is not None:
240                         self.timer.callback.remove(self.timerTick)
241                         self.timer = None
242                 self.rssPoller.removeCallback(self.pollCallback)
243
244         def pollCallback(self, id = None):
245                 print "[SimpleRSS] SimpleRSSFeed called back"
246
247                 if id is None or id+1 == self.id:
248                         # TODO: do we really need this?
249                         current_entry = self["content"].getCurrent()
250                         self["content"].moveToEntry(current_entry)
251
252                         self["content"].invalidate()
253                         self.setConditionalTitle()
254                         self.updateInfo()
255
256         def setConditionalTitle(self):
257                 self.setTitle(_("Simple RSS Reader: %s") % (self.feed.title))
258
259         def updateInfo(self):
260                 current_entry = self["content"].getCurrent()
261                 if current_entry:
262                         self["summary"].setText(current_entry[2])
263
264                         cur_idx = self["content"].getSelectedIndex()
265                         self["info"].setText(_("Entry %s/%s") % (cur_idx+1, len(self.feed.history)))
266                 else:
267                         self["summary"].setText(_("Feed is empty."))
268                         self["info"].setText("")
269
270         def menu(self):
271                 if self.id > 0:
272                         self.singleUpdate(self.id-1)
273
274         def nextEntry(self):
275                 self["content"].down()
276                 return (self["content"].getCurrent(), self["content"].getSelectedIndex(), len(self.feed.history))
277
278         def previousEntry(self):
279                 self["content"].up()
280                 return (self["content"].getCurrent(), self["content"].getSelectedIndex(), len(self.feed.history))
281
282         # TODO: Fix moving back to previously marked entry (same goes for self.previous)
283         def next(self):
284                 # Show next Feed
285                 if self.parent is not None:
286                         (self.feed, self.id) = self.parent.nextFeed()
287                         #current_entry = self["content"].getCurrent()
288                         self["content"].setList(self.feed.history) # Update list
289                         self["content"].moveToIndex(0)
290                         #self["content"].moveToEntry(current_entry)
291                         self.updateInfo() # In case entry is no longer in history
292                         self.setConditionalTitle() # Update title
293                         return (self.feed.title, self.feed.history, self.id)
294                 return (self.feed.title, self.feed.history, self.id)
295
296         def previous(self):
297                 # Show previous Feed
298                 if self.parent is not None:
299                         (self.feed, self.id) = self.parent.previousFeed()
300                         #current_entry = self["content"].getCurrent()
301                         self["content"].setList(self.feed.history) # Update list
302                         self["content"].moveToIndex(0)
303                         #self["content"].moveToEntry(current_entry)
304                         self.updateInfo() # In case entry is no longer in history
305                         self.setConditionalTitle() # Update title
306                         return (self.feed.title, self.feed.history, self.id)
307                 return (self.feed.title, self.feed.history, self.id)
308
309         def checkEmpty(self):
310                 if self.id > 0 and not len(self.feed.history):
311                         self.singleUpdate(self.id-1)
312
313         def showCurrentEntry(self):
314                 current_entry = self["content"].getCurrent()
315                 if current_entry is None: # empty list
316                         return
317
318                 self.session.openWithCallback(
319                         self.updateInfo,
320                         RSSEntryView,
321                         current_entry,
322                         cur_idx=self["content"].getSelectedIndex(),
323                         entries=len(self.feed.history),
324                         feedTitle=self.feed.title,
325                         parent=self
326                 )
327
328         def selectEnclosure(self):
329                 current_entry = self["content"].getCurrent()
330                 if current_entry is None: # empty list
331                         return
332
333                 RSSBaseView.selectEnclosure(self, current_entry[3])
334
335 class RSSOverview(RSSBaseView):
336         """Shows an Overview over all RSS-Feeds known to rssPoller"""
337
338         skin = """
339                 <screen position="100,100" size="460,415" title="Simple RSS Reader" >
340                         <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
341                         <widget name="content" position="0,20" size="460,300" scrollbarMode="showOnDemand" />
342                         <widget name="summary" position="0,320" size="460,95" font="Regular;16" />
343                 </screen>"""
344
345         def __init__(self, session, poller):
346                 RSSBaseView.__init__(self, session, poller)
347
348                 self["actions"] = ActionMap([ "OkCancelActions", "MenuActions", "ColorActions" ],
349                 {
350                         "ok": self.showCurrentEntry,
351                         "cancel": self.close,
352                         "menu": self.menu,
353                         "yellow": self.selectEnclosure,
354                 })
355
356                 self.fillFeeds()
357
358                 # We always have at least "New Items"-Feed
359                 self["content"] = RSSFeedList(self.feeds)
360                 self["summary"] = Label(' '.join((str(len(self.feeds[0][0].history)), _("Entries"))))
361                 self["info"] = Label(_("Feed %s/%s") % (1, len(self.feeds)))
362
363                 self["content"].connectSelChanged(self.updateInfo)
364                 self.onLayoutFinish.append(self.__show)
365                 self.onClose.append(self.__close)
366
367         def __show(self):
368                 self.rssPoller.addCallback(self.pollCallback)
369                 self.setTitle(_("Simple RSS Reader"))
370
371         def __close(self):
372                 self.rssPoller.removeCallback(self.pollCallback)
373
374         def fillFeeds(self):
375                 # Feedlist contains our virtual Feed and all real ones
376                 self.feeds = [(self.rssPoller.newItemFeed,)]
377                 self.feeds.extend([(feed,) for feed in self.rssPoller.feeds])
378
379         def pollCallback(self, id = None):
380                 print "[SimpleRSS] SimpleRSS called back"
381                 self.updateInfo()
382                 self["content"].invalidate()
383
384         def updateInfo(self):
385                 current_entry = self["content"].getCurrent()
386                 self["summary"].setText(' '.join((str(len(current_entry.history)), _("Entries"))))
387                 self["info"].setText(_("Feed %s/%s") % (self["content"].getSelectedIndex()+1, len(self.feeds)))
388
389         def menu(self):
390                 from Screens.ChoiceBox import ChoiceBox
391
392                 cur_idx = self["content"].getSelectedIndex()
393                 if cur_idx > 0:
394                         possible_actions = (
395                                 (_("Update Feed"), "update"),
396                                 (_("Setup"), "setup"),
397                                 (_("Close"), "close")
398                         )
399                 else:
400                         possible_actions = (
401                                 (_("Setup"), "setup"),
402                                 (_("Close"), "close")
403                         )
404
405                 self.session.openWithCallback(
406                         self.menuChoice,
407                         ChoiceBox,
408                         _("What to do?"),
409                         possible_actions
410                 )
411
412         def menuChoice(self, result):
413                 if result:
414                         if result[1] == "update":
415                                 cur_idx = self["content"].getSelectedIndex()
416                                 if cur_idx > 0:
417                                         self.singleUpdate(cur_idx-1)
418                         elif result[1] == "setup":
419                                 from RSSSetup import RSSSetup
420
421                                 self.session.openWithCallback(
422                                         self.refresh,
423                                         RSSSetup,
424                                         rssPoller=self.rssPoller
425                                 )
426                         elif result[1] == "close":
427                                 self.close()
428
429         def refresh(self):
430                 current_entry = self["content"].getCurrent()
431
432                 self.fillFeeds()
433                 self["content"].setList(self.feeds)
434
435                 self["content"].moveToEntry(current_entry)
436                 self.updateInfo()
437
438         def nextFeed(self):
439                 self["content"].up()
440                 return (self["content"].getCurrent(), self["content"].getSelectedIndex())
441
442         def previousFeed(self):
443                 self["content"].down()
444                 return (self["content"].getCurrent(), self["content"].getSelectedIndex())
445
446         def showCurrentEntry(self):
447                 current_entry = self["content"].getCurrent()
448                 self.session.openWithCallback(
449                         self.updateInfo,
450                         RSSFeedView,
451                         feed=current_entry,
452                         parent=self,
453                         rssPoller=self.rssPoller,
454                         id=self["content"].getSelectedIndex()
455                 )
456
457         def selectEnclosure(self):
458                 # Build a list of all enclosures in this feed
459                 enclosures = []
460                 for entry in self["content"].getCurrent().history:
461                                 enclosures.extend(entry[3])
462                 RSSBaseView.selectEnclosure(self, enclosures)
463