1 # for localized messages
4 from enigma import eTimer
6 from Screens.Screen import Screen
7 from Screens.MessageBox import MessageBox
9 from Components.ActionMap import ActionMap
10 from Components.ScrollLabel import ScrollLabel
11 from Components.Sources.List import List
12 from Components.Sources.StaticText import StaticText
14 from RSSList import RSSFeedList
16 class RSSSummary(Screen):
18 <screen position="0,0" size="132,64">
19 <widget source="parent.title" render="Label" position="6,4" size="120,21" font="Regular;18" />
20 <widget source="entry" render="Label" position="6,25" size="120,21" font="Regular;16" />
21 <widget source="global.CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
22 <convert type="ClockToText">WithSeconds</convert>
26 def __init__(self, session, parent):
27 Screen.__init__(self, session, parent = parent)
28 self["entry"] = StaticText("")
29 parent.onChangedEntry.append(self.selectionChanged)
30 self.onShow.append(parent.updateInfo)
31 self.onClose.append(self.removeWatcher)
33 def removeWatcher(self):
34 self.parent.onChangedEntry.remove(self.selectionChanged)
36 def selectionChanged(self, text):
37 self["entry"].text = text
39 class RSSBaseView(Screen):
40 """Base Screen for all Screens used in SimpleRSS"""
42 def __init__(self, session, poller, parent = None):
43 Screen.__init__(self, session, parent)
44 self["title"] = StaticText()
45 self.onChangedEntry = []
46 self.rssPoller = poller
47 self.pollDialog = None
49 def createSummary(self):
52 def setTitle(self, title):
53 Screen.setTitle(self, title)
54 self["title"].text = title
56 def errorPolling(self, errmsg = ""):
57 # An error occured while polling
60 _("Error while parsing Feed, this usually means there is something wrong with it."),
61 type = MessageBox.TYPE_ERROR,
65 # Don't show "we're updating"-dialog any longer
67 self.pollDialog.close()
68 self.pollDialog = None
70 def singleUpdate(self, feedid, errback = None):
71 # Don't do anything if we have no poller
72 if self.rssPoller is None:
75 # Default errorback to self.errorPolling
76 # If an empty errorback is wanted the Screen needs to provide it
78 errback = self.errorPolling
81 self.rssPoller.singlePoll(feedid, callback=True, errorback=errback)
83 # Open Dialog and save locally
84 self.pollDialog = self.session.open(
86 _("Update is being done in Background.\nContents will automatically be updated when it's done."),
87 type = MessageBox.TYPE_INFO,
91 def selectEnclosure(self, enclosures):
93 if enclosures is None:
96 from Components.Scanner import openList
98 if not openList(self.session, enclosures):
101 _("Found no Enclosure we can display."),
102 type = MessageBox.TYPE_INFO,
106 class RSSEntryView(RSSBaseView):
107 """Shows a RSS Item"""
110 <screen position="center,center" size="460,420" title="Simple RSS Reader" >
111 <widget source="info" render="Label" position="0,0" size="460, 20" halign="right" font="Regular; 18" />
112 <widget name="content" position="0,20" size="460,400" font="Regular; 22" />
115 def __init__(self, session, data, feedTitle="", cur_idx=None, entries=None, parent=None):
116 RSSBaseView.__init__(self, session, None, parent)
119 self.feedTitle = feedTitle
120 self.cur_idx = cur_idx
121 self.entries = entries
123 if cur_idx is not None and entries is not None:
124 self["info"] = StaticText(_("Entry %s/%s") % (cur_idx+1, entries))
126 self["info"] = StaticText()
129 self["content"] = ScrollLabel(''.join((data[0], '\n\n', data[2], '\n\n', str(len(data[3])), ' ', _("Enclosures"))))
131 self["content"] = ScrollLabel()
133 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "ColorActions", "DirectionActions" ],
135 "cancel": self.close,
136 "ok": self.selectEnclosure,
137 "yellow": self.selectEnclosure,
141 "left": self.previous,
142 "nextBouquet": self.nextFeed,
143 "prevBouquet": self.previousFeed,
146 self.onLayoutFinish.append(self.setConditionalTitle)
148 def setConditionalTitle(self):
149 self.setTitle(_("Simple RSS Reader: %s") % (self.feedTitle))
151 def updateInfo(self):
155 text = _("No such Item.")
157 for x in self.onChangedEntry:
164 self["content"].pageUp()
167 self["content"].pageDown()
170 if self.parent is not None:
171 (self.data, self.cur_idx, self.entries) = self.parent.nextEntry()
175 if self.parent is not None:
176 (self.data, self.cur_idx, self.entries) = self.parent.previousEntry()
181 if self.parent is not None:
182 result = self.parent.next()
183 self.feedTitle = result[0]
184 self.entries = len(result[1])
187 self.data = result[1][0]
191 self.setConditionalTitle()
194 def previousFeed(self):
196 if self.parent is not None:
197 result = self.parent.previous()
198 self.feedTitle = result[0]
199 self.entries = len(result[1])
202 self.data = result[1][0]
206 self.setConditionalTitle()
209 def setContent(self):
210 if self.cur_idx is not None and self.entries is not None:
211 self["info"].text = _("Entry %s/%s") % (self.cur_idx+1, self.entries)
213 self["info"].text = ""
216 self["content"].setText(''.join((data[0], '\n\n', data[2], '\n\n', str(len(data[3])), ' ', _("Enclosures"))))
218 self["content"].setText(_("No such Item."))
221 def selectEnclosure(self):
222 if self.data is not None:
223 RSSBaseView.selectEnclosure(self, self.data[3])
225 class RSSFeedView(RSSBaseView):
226 """Shows a RSS-Feed"""
229 <screen position="center,center" size="460,415" title="Simple RSS Reader" >
230 <widget source="info" render="Label" position="0,0" size="460,20" halign="right" font="Regular; 18" />
231 <widget source="content" render="Listbox" position="0,20" size="460,300" scrollbarMode="showOnDemand">
232 <convert type="TemplatedMultiContent">
234 MultiContentEntryText(pos=(0, 3), size=(460, 294), font=0, flags = RT_HALIGN_LEFT|RT_WRAP, text = 0)
236 "fonts": [gFont("Regular", 22)],
241 <widget source="summary" render="Label" position="0,320" size="460,95" font="Regular;16" />
244 def __init__(self, session, feed=None, newItems=False, parent=None, rssPoller=None,id=None):
245 RSSBaseView.__init__(self, session, rssPoller, parent)
248 self.newItems = newItems
251 self["content"] = List(self.feed.history)
252 self["summary"] = StaticText()
253 self["info"] = StaticText()
256 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "MenuActions", "ColorActions" ],
258 "ok": self.showCurrentEntry,
259 "cancel": self.close,
260 "nextBouquet": self.next,
261 "prevBouquet": self.previous,
263 "yellow": self.selectEnclosure,
265 self.onLayoutFinish.append(self.__show)
266 self.onClose.append(self.__close)
270 self["actions"] = ActionMap([ "OkCancelActions" ],
272 "cancel": self.close,
275 self.timer = eTimer()
276 self.timer.callback.append(self.timerTick)
277 self.onExecBegin.append(self.startTimer)
279 self["content"].onSelectionChanged.append(self.updateInfo)
280 self.onLayoutFinish.extend((
282 self.setConditionalTitle
285 def startTimer(self):
286 self.timer.startLongTimer(5)
289 self.timer.callback.remove(self.timerTick)
294 self.rssPoller.addCallback(self.pollCallback)
297 if self.timer is not None:
298 self.timer.callback.remove(self.timerTick)
300 self.rssPoller.removeCallback(self.pollCallback)
302 def pollCallback(self, id = None):
303 print "[SimpleRSS] SimpleRSSFeed called back"
305 if id is None or id+1 == self.id:
306 self["content"].updateList(self.feed.history)
307 self.setConditionalTitle()
310 def setConditionalTitle(self):
311 self.setTitle(_("Simple RSS Reader: %s") % (self.feed.title))
313 def updateInfo(self):
314 current_entry = self["content"].current
316 self["summary"].text = current_entry[2]
318 cur_idx = self["content"].index
319 self["info"].text = _("Entry %s/%s") % (cur_idx+1, len(self.feed.history))
320 summary_text = current_entry[0]
322 self["summary"].text = _("Feed is empty.")
323 self["info"].text = ""
324 summary_text = _("Feed is empty.")
326 for x in self.onChangedEntry:
334 self.singleUpdate(self.id-1)
337 self["content"].selectNext()
338 return (self["content"].current, self["content"].index, len(self.feed.history))
340 def previousEntry(self):
341 self["content"].selectPrevious()
342 return (self["content"].current, self["content"].index, len(self.feed.history))
346 if self.parent is not None:
347 (self.feed, self.id) = self.parent.nextFeed()
348 self["content"].list = self.feed.history
349 self["content"].index = 0
351 self.setConditionalTitle() # Update title
352 return (self.feed.title, self.feed.history, self.id)
353 return (self.feed.title, self.feed.history, self.id)
357 if self.parent is not None:
358 (self.feed, self.id) = self.parent.previousFeed()
359 self["content"].list = self.feed.history
360 self["content"].index = 0
362 self.setConditionalTitle() # Update title
363 return (self.feed.title, self.feed.history, self.id)
364 return (self.feed.title, self.feed.history, self.id)
366 def checkEmpty(self):
367 if self.id > 0 and not len(self.feed.history):
368 self.singleUpdate(self.id-1)
370 def showCurrentEntry(self):
371 current_entry = self["content"].current
372 if not current_entry: # empty list
375 self.session.openWithCallback(
379 cur_idx = self["content"].index,
380 entries = len(self.feed.history),
381 feedTitle = self.feed.title,
385 def selectEnclosure(self):
386 current_entry = self["content"].current
387 if not current_entry: # empty list
390 RSSBaseView.selectEnclosure(self, current_entry[3])
392 class RSSOverview(RSSBaseView):
393 """Shows an Overview over all RSS-Feeds known to rssPoller"""
396 <screen position="center,center" size="460,415" title="Simple RSS Reader" >
397 <widget source="info" render="Label" position="0,0" size="460,20" halign="right" font="Regular; 18" />
398 <widget name="content" position="0,20" size="460,300" scrollbarMode="showOnDemand" />
399 <widget source="summary" render="Label" position="0,320" size="460,95" font="Regular;16" />
402 def __init__(self, session, poller):
403 RSSBaseView.__init__(self, session, poller)
405 self["actions"] = ActionMap([ "OkCancelActions", "MenuActions", "ColorActions" ],
407 "ok": self.showCurrentEntry,
408 "cancel": self.close,
410 "yellow": self.selectEnclosure,
415 # We always have at least "New Items"-Feed
416 self["content"] = RSSFeedList(self.feeds)
417 self["summary"] = StaticText(' '.join((str(len(self.feeds[0][0].history)), _("Entries"))))
418 self["info"] = StaticText(_("Feed %s/%s") % (1, len(self.feeds)))
420 self["content"].connectSelChanged(self.updateInfo)
421 self.onLayoutFinish.append(self.__show)
422 self.onClose.append(self.__close)
425 self.rssPoller.addCallback(self.pollCallback)
426 self.setTitle(_("Simple RSS Reader"))
429 self.rssPoller.removeCallback(self.pollCallback)
432 # Feedlist contains our virtual Feed and all real ones
433 self.feeds = [(self.rssPoller.newItemFeed,)]
434 self.feeds.extend([(feed,) for feed in self.rssPoller.feeds])
436 def pollCallback(self, id = None):
437 print "[SimpleRSS] SimpleRSS called back"
439 self["content"].invalidate()
441 def updateInfo(self):
442 current_entry = self["content"].getCurrent()
443 self["summary"].text = ' '.join((str(len(current_entry.history)), _("Entries")))
444 self["info"].text = _("Feed %s/%s") % (self["content"].getSelectedIndex()+1, len(self.feeds))
445 summary_text = current_entry.title
447 for x in self.onChangedEntry:
454 from Screens.ChoiceBox import ChoiceBox
456 cur_idx = self["content"].getSelectedIndex()
459 (_("Update Feed"), "update"),
460 (_("Setup"), "setup"),
461 (_("Close"), "close")
465 (_("Setup"), "setup"),
466 (_("Close"), "close")
469 self.session.openWithCallback(
476 def menuChoice(self, result):
478 if result[1] == "update":
479 cur_idx = self["content"].getSelectedIndex()
481 self.singleUpdate(cur_idx-1)
482 elif result[1] == "setup":
483 from RSSSetup import RSSSetup
485 self.session.openWithCallback(
488 rssPoller=self.rssPoller
490 elif result[1] == "close":
494 current_entry = self["content"].getCurrent()
497 self["content"].setList(self.feeds)
499 self["content"].moveToEntry(current_entry)
504 return (self["content"].getCurrent(), self["content"].getSelectedIndex())
506 def previousFeed(self):
507 self["content"].down()
508 return (self["content"].getCurrent(), self["content"].getSelectedIndex())
510 def showCurrentEntry(self):
511 current_entry = self["content"].getCurrent()
512 self.session.openWithCallback(
517 rssPoller=self.rssPoller,
518 id=self["content"].getSelectedIndex()
521 def selectEnclosure(self):
522 # Build a list of all enclosures in this feed
524 for entry in self["content"].getCurrent().history:
525 enclosures.extend(entry[3])
526 RSSBaseView.selectEnclosure(self, enclosures)