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