followup to previous commit
[enigma2-plugins.git] / 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 is not None:
96                         self["content"] = ScrollLabel("\n\n".join((data[0], data[2], " ".join((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                 if self.data is not None:
170                         self["content"].setText("\n\n".join((self.data[0], self.data[2], " ".join((str(len(self.data[3])), _("Enclosures"))))))
171                 else:
172                         self["content"].setText(_("No such Item."))
173
174         def selectEnclosure(self):
175                 if self.data is not None:
176                         RSSBaseView.selectEnclosure(self, self.data[3])
177
178 class RSSFeedView(RSSBaseView):
179         """Shows a RSS-Feed"""
180
181         skin = """
182                 <screen position="100,100" size="460,415" title="Simple RSS Reader" >
183                         <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
184                         <widget name="content" position="0,20" size="460,300" scrollbarMode="showOnDemand" />
185                         <widget name="summary" position="0,320" size="460,95" font="Regular;16" />
186                 </screen>"""
187
188         def __init__(self, session, feed=None, newItems=False, parent=None, rssPoller=None,id=None):
189                 RSSBaseView.__init__(self, session, rssPoller, parent)
190
191                 self.feed = feed
192                 self.newItems = newItems
193                 self.id = id
194
195                 self["content"] = RSSEntryList(self.feed.history)
196                 self["summary"] = Label()
197                 self["info"] = Label()
198
199                 if not newItems:
200                         self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "MenuActions", "ColorActions" ],
201                         {
202                                 "ok": self.showCurrentEntry,
203                                 "cancel": self.close,
204                                 "nextBouquet": self.next,
205                                 "prevBouquet": self.previous,
206                                 "menu": self.menu,
207                                 "yellow": self.selectEnclosure,
208                         })
209                         self.onLayoutFinish.append(self.__show)
210                         self.onClose.append(self.__close)
211
212                         self.timer = None
213                 else:
214                         self["actions"] = ActionMap([ "OkCancelActions" ],
215                         {
216                                 "cancel": self.close,
217                         })
218
219                         self.timer = eTimer()
220                         self.timer.callback.append(self.timerTick)
221                         self.onExecBegin.append(self.startTimer)
222
223                 self["content"].connectSelChanged(self.updateInfo)
224                 self.onLayoutFinish.extend([self.updateInfo, self.setConditionalTitle])
225
226         def startTimer(self):
227                 self.timer.startLongTimer(5)
228
229         def timerTick(self):
230                 self.timer.callback.remove(self.timerTick)
231
232                 self.close()
233
234         def __show(self):
235                 self.rssPoller.addCallback(self.pollCallback)
236
237         def __close(self):
238                 if self.timer is not None:
239                         self.timer.callback.remove(self.timerTick)
240                         self.timer = None
241                 self.rssPoller.removeCallback(self.pollCallback)
242
243         def pollCallback(self, id = None):
244                 print "[SimpleRSS] SimpleRSSFeed called back"
245
246                 if id is None or id+1 == self.id:
247                         # TODO: do we really need this?
248                         current_entry = self["content"].getCurrent()
249                         self["content"].moveToEntry(current_entry)
250
251                         self["content"].invalidate()
252                         self.setConditionalTitle()
253                         self.updateInfo()
254
255         def setConditionalTitle(self):
256                 self.setTitle(_("Simple RSS Reader: %s") % (self.feed.title))
257
258         def updateInfo(self):
259                 current_entry = self["content"].getCurrent()
260                 if current_entry:
261                         self["summary"].setText(current_entry[2])
262
263                         cur_idx = self["content"].getSelectedIndex()
264                         self["info"].setText(_("Entry %s/%s") % (cur_idx+1, len(self.feed.history)))
265                 else:
266                         self["summary"].setText(_("Feed is empty."))
267                         self["info"].setText("")
268
269         def menu(self):
270                 if self.id > 0:
271                         self.singleUpdate(self.id-1)
272
273         def nextEntry(self):
274                 self["content"].down()
275                 return (self["content"].getCurrent(), self["content"].getSelectedIndex(), len(self.feed.history))
276
277         def previousEntry(self):
278                 self["content"].up()
279                 return (self["content"].getCurrent(), self["content"].getSelectedIndex(), len(self.feed.history))
280
281         # TODO: Fix moving back to previously marked entry (same goes for self.previous)
282         def next(self):
283                 # Show next Feed
284                 if self.parent is not None:
285                         (self.feed, self.id) = self.parent.nextFeed()
286                         #current_entry = self["content"].getCurrent()
287                         self["content"].setList(self.feed.history) # Update list
288                         self["content"].moveToIndex(0)
289                         #self["content"].moveToEntry(current_entry)
290                         self.updateInfo() # In case entry is no longer in history
291                         self.setConditionalTitle() # Update title
292                         return (self.feed.title, self.feed.history, self.id)
293                 return (self.feed.title, self.feed.history, self.id)
294
295         def previous(self):
296                 # Show previous Feed
297                 if self.parent is not None:
298                         (self.feed, self.id) = self.parent.previousFeed()
299                         #current_entry = self["content"].getCurrent()
300                         self["content"].setList(self.feed.history) # Update list
301                         self["content"].moveToIndex(0)
302                         #self["content"].moveToEntry(current_entry)
303                         self.updateInfo() # In case entry is no longer in history
304                         self.setConditionalTitle() # Update title
305                         return (self.feed.title, self.feed.history, self.id)
306                 return (self.feed.title, self.feed.history, self.id)
307
308         def checkEmpty(self):
309                 if self.id > 0 and not len(self.feed.history):
310                         self.singleUpdate(self.id-1)
311
312         def showCurrentEntry(self):
313                 current_entry = self["content"].getCurrent()
314                 if current_entry is None: # empty list
315                         return
316
317                 self.session.openWithCallback(
318                         self.updateInfo,
319                         RSSEntryView,
320                         current_entry,
321                         cur_idx=self["content"].getSelectedIndex(),
322                         entries=len(self.feed.history),
323                         feedTitle=self.feed.title,
324                         parent=self
325                 )
326
327         def selectEnclosure(self):
328                 current_entry = self["content"].getCurrent()
329                 if current_entry is None: # empty list
330                         return
331
332                 RSSBaseView.selectEnclosure(self, current_entry[3])
333
334 class RSSOverview(RSSBaseView):
335         """Shows an Overview over all RSS-Feeds known to rssPoller"""
336
337         skin = """
338                 <screen position="100,100" size="460,415" title="Simple RSS Reader" >
339                         <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
340                         <widget name="content" position="0,20" size="460,300" scrollbarMode="showOnDemand" />
341                         <widget name="summary" position="0,320" size="460,95" font="Regular;16" />
342                 </screen>"""
343
344         def __init__(self, session, poller):
345                 RSSBaseView.__init__(self, session, poller)
346
347                 self["actions"] = ActionMap([ "OkCancelActions", "MenuActions", "ColorActions" ],
348                 {
349                         "ok": self.showCurrentEntry,
350                         "cancel": self.close,
351                         "menu": self.menu,
352                         "yellow": self.selectEnclosure,
353                 })
354
355                 self.fillFeeds()
356
357                 # We always have at least "New Items"-Feed
358                 self["content"] = RSSFeedList(self.feeds)
359                 self["summary"] = Label(' '.join((str(len(self.feeds[0][0].history)), _("Entries"))))
360                 self["info"] = Label(_("Feed %s/%s") % (1, len(self.feeds)))
361
362                 self["content"].connectSelChanged(self.updateInfo)
363                 self.onLayoutFinish.append(self.__show)
364                 self.onClose.append(self.__close)
365
366         def __show(self):
367                 self.rssPoller.addCallback(self.pollCallback)
368                 self.setTitle(_("Simple RSS Reader"))
369
370         def __close(self):
371                 self.rssPoller.removeCallback(self.pollCallback)
372
373         def fillFeeds(self):
374                 # Feedlist contains our virtual Feed and all real ones
375                 self.feeds = [(self.rssPoller.newItemFeed,)]
376                 self.feeds.extend([(feed,) for feed in self.rssPoller.feeds])
377
378         def pollCallback(self, id = None):
379                 print "[SimpleRSS] SimpleRSS called back"
380                 self.updateInfo()
381                 self["content"].invalidate()
382
383         def updateInfo(self):
384                 current_entry = self["content"].getCurrent()
385                 self["summary"].setText(' '.join((str(len(current_entry.history)), _("Entries"))))
386                 self["info"].setText(_("Feed %s/%s") % (self["content"].getSelectedIndex()+1, len(self.feeds)))
387
388         def menu(self):
389                 from Screens.ChoiceBox import ChoiceBox
390
391                 cur_idx = self["content"].getSelectedIndex()
392                 if cur_idx > 0:
393                         possible_actions = (
394                                 (_("Update Feed"), "update"),
395                                 (_("Setup"), "setup"),
396                                 (_("Close"), "close")
397                         )
398                 else:
399                         possible_actions = (
400                                 (_("Setup"), "setup"),
401                                 (_("Close"), "close")
402                         )
403
404                 self.session.openWithCallback(
405                         self.menuChoice,
406                         ChoiceBox,
407                         _("What to do?"),
408                         possible_actions
409                 )
410
411         def menuChoice(self, result):
412                 if result:
413                         if result[1] == "update":
414                                 cur_idx = self["content"].getSelectedIndex()
415                                 if cur_idx > 0:
416                                         self.singleUpdate(cur_idx-1)
417                         elif result[1] == "setup":
418                                 from RSSSetup import RSSSetup
419
420                                 self.session.openWithCallback(
421                                         self.refresh,
422                                         RSSSetup,
423                                         rssPoller=self.rssPoller
424                                 )
425                         elif result[1] == "close":
426                                 self.close()
427
428         def refresh(self):
429                 current_entry = self["content"].getCurrent()
430
431                 self.fillFeeds()
432                 self["content"].setList(self.feeds)
433
434                 self["content"].moveToEntry(current_entry)
435                 self.updateInfo()
436
437         def nextFeed(self):
438                 self["content"].up()
439                 return (self["content"].getCurrent(), self["content"].getSelectedIndex())
440
441         def previousFeed(self):
442                 self["content"].down()
443                 return (self["content"].getCurrent(), self["content"].getSelectedIndex())
444
445         def showCurrentEntry(self):
446                 current_entry = self["content"].getCurrent()
447                 self.session.openWithCallback(
448                         self.updateInfo,
449                         RSSFeedView,
450                         feed=current_entry,
451                         parent=self,
452                         rssPoller=self.rssPoller,
453                         id=self["content"].getSelectedIndex()
454                 )
455
456         def selectEnclosure(self):
457                 # Build a list of all enclosures in this feed
458                 enclosures = []
459                 for entry in self["content"].getCurrent().history:
460                                 enclosures.extend(entry[3])
461                 RSSBaseView.selectEnclosure(self, enclosures)
462