1 from enigma import eTimer
3 from Screens.Screen import Screen
4 from Screens.MessageBox import MessageBox
6 from Components.ActionMap import ActionMap
7 from Components.Label import Label
8 from Components.ScrollLabel import ScrollLabel
10 from RSSList import RSSFeedList, RSSEntryList
12 class RSSBaseView(Screen):
13 """Base Screen for all Screens used in SimpleRSS"""
15 def __init__(self, session, poller, parent=None):
16 Screen.__init__(self, session)
17 self.rssPoller = poller
18 self.pollDialog = None
21 def errorPolling(self, errmsg = ""):
22 # An error occured while polling
25 _("Error while parsing Feed, this usually means there is something wrong with it."),
26 type = MessageBox.TYPE_ERROR,
30 # Don't show "we're updating"-dialog any longer
32 self.pollDialog.close()
33 self.pollDialog = None
35 def singleUpdate(self, feedid, errback = None):
36 # Don't do anything if we have no poller
37 if self.rssPoller is None:
40 # Default errorback to self.errorPolling
41 # If an empty errorback is wanted the Screen needs to provide it
43 errback = self.errorPolling
46 self.rssPoller.singlePoll(feedid, callback=True, errorback=errback)
48 # Open Dialog and save locally
49 self.pollDialog = self.session.open(
51 _("Update is being done in Background.\nContents will automatically be updated when it's done."),
52 type = MessageBox.TYPE_INFO,
56 def selectEnclosure(self, enclosures):
58 if enclosures is None:
61 from Components.Scanner import openList
63 if not openList(self.session, enclosures):
66 _("Found no Enclosure we can display."),
67 type = MessageBox.TYPE_INFO,
71 class RSSEntryView(RSSBaseView):
72 """Shows a RSS Item"""
75 <screen position="100,100" size="460,420" title="Simple RSS Reader" >
76 <widget name="info" position="0,0" size="460, 20" halign="right" font="Regular; 18" />
77 <widget name="content" position="0,20" size="460,400" font="Regular; 22" />
80 def __init__(self, session, data, feedTitle="", cur_idx=None, entries=None, parent=None):
81 RSSBaseView.__init__(self, session, None, parent)
84 self.feedTitle = feedTitle
85 self.cur_idx = cur_idx
86 self.entries = entries
88 if cur_idx is not None and entries is not None:
89 self["info"] = Label(_("Entry %s/%s") % (cur_idx+1, entries))
91 self["info"] = Label()
94 self["content"] = ScrollLabel("\n\n".join([data[0], data[2], " ".join([str(len(data[3])), "Enclosures"])]))
96 self["content"] = ScrollLabel()
98 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "ColorActions", "DirectionActions" ],
100 "cancel": self.close,
101 "ok": self.selectEnclosure,
102 "yellow": self.selectEnclosure,
106 "left": self.previous,
107 "nextBouquet": self.nextFeed,
108 "prevBouquet": self.previousFeed,
111 self.onLayoutFinish.append(self.setConditionalTitle)
113 def setConditionalTitle(self):
114 self.setTitle(': '.join(["Simple RSS Reader", self.feedTitle]))
117 self["content"].pageUp()
120 self["content"].pageDown()
123 if self.parent is not None:
124 (self.data, self.cur_idx, self.entries) = self.parent.nextEntry()
128 if self.parent is not None:
129 (self.data, self.cur_idx, self.entries) = self.parent.previousEntry()
134 if self.parent is not None:
135 result = self.parent.next()
136 self.feedTitle = result[0]
137 self.entries = len(result[1])
140 self.data = result[1][0]
144 self.setConditionalTitle()
147 def previousFeed(self):
149 if self.parent is not None:
150 result = self.parent.previous()
151 self.feedTitle = result[0]
152 self.entries = len(result[1])
155 self.data = result[1][0]
159 self.setConditionalTitle()
162 def setContent(self):
163 if self.cur_idx is not None and self.entries is not None:
164 self["info"].setText(_("Entry %s/%s") % (self.cur_idx+1, self.entries))
166 self["info"].setText("")
167 if self.data is not None:
168 self["content"].setText("\n\n".join([self.data[0], self.data[2], " ".join([str(len(self.data[3])), _("Enclosures")])]))
170 self["content"].setText(_("No such Item."))
172 def selectEnclosure(self):
173 if self.data is not None:
174 RSSBaseView.selectEnclosure(self, self.data[3])
176 class RSSFeedView(RSSBaseView):
177 """Shows a RSS-Feed"""
180 <screen position="100,100" size="460,415" title="Simple RSS Reader" >
181 <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
182 <widget name="content" position="0,20" size="460,300" scrollbarMode="showOnDemand" />
183 <widget name="summary" position="0,320" size="460,95" font="Regular;16" />
186 def __init__(self, session, feed=None, newItems=False, parent=None, rssPoller=None,id=None):
187 RSSBaseView.__init__(self, session, rssPoller, parent)
190 self.newItems = newItems
193 self["content"] = RSSEntryList(self.feed.history)
194 self["summary"] = Label()
195 self["info"] = Label()
198 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "MenuActions", "ColorActions" ],
200 "ok": self.showCurrentEntry,
201 "cancel": self.close,
202 "nextBouquet": self.next,
203 "prevBouquet": self.previous,
205 "yellow": self.selectEnclosure,
207 self.onLayoutFinish.append(self.__show)
208 self.onClose.append(self.__close)
212 self["actions"] = ActionMap([ "OkCancelActions" ],
214 "cancel": self.close,
217 self.timer = eTimer()
218 self.timer.callback.append(self.timerTick)
219 self.onExecBegin.append(self.startTimer)
221 self["content"].connectSelChanged(self.updateInfo)
222 self.onLayoutFinish.extend([self.updateInfo, self.setConditionalTitle])
224 def startTimer(self):
225 self.timer.startLongTimer(5)
228 self.timer.callback.remove(self.timerTick)
233 self.rssPoller.addCallback(self.pollCallback)
236 if self.timer is not None:
237 self.timer.callback.remove(self.timerTick)
239 self.rssPoller.removeCallback(self.pollCallback)
241 def pollCallback(self, id = None):
242 print "[SimpleRSS] SimpleRSSFeed called back"
244 if id is None or id+1 == self.id:
245 # TODO: do we really need this?
246 current_entry = self["content"].getCurrent()
247 self["content"].moveToEntry(current_entry)
249 self["content"].invalidate()
250 self.setConditionalTitle()
253 def setConditionalTitle(self):
254 self.setTitle(': '.join(["Simple RSS Reader", self.feed.title]))
256 def updateInfo(self):
257 current_entry = self["content"].getCurrent()
259 self["summary"].setText(current_entry[2])
261 cur_idx = self["content"].getSelectedIndex()
262 self["info"].setText(_("Entry %s/%s") % (cur_idx+1, len(self.feed.history)))
264 self["summary"].setText(_("Feed is empty."))
265 self["info"].setText("")
269 self.singleUpdate(self.id-1)
272 self["content"].down()
273 return (self["content"].getCurrent(), self["content"].getSelectedIndex(), len(self.feed.history))
275 def previousEntry(self):
277 return (self["content"].getCurrent(), self["content"].getSelectedIndex(), len(self.feed.history))
279 # TODO: Fix moving back to previously marked entry (same goes for self.previous)
282 if self.parent is not None:
283 (self.feed, self.id) = self.parent.nextFeed()
284 #current_entry = self["content"].getCurrent()
285 self["content"].l.setList(self.feed.history) # Update list
286 self["content"].moveToIndex(0)
287 #self["content"].moveToEntry(current_entry)
288 self.updateInfo() # In case entry is no longer in history
289 self.setConditionalTitle() # Update title
290 return (self.feed.title, self.feed.history, self.id)
291 return (self.feed.title, self.feed.history, self.id)
295 if self.parent is not None:
296 (self.feed, self.id) = self.parent.previousFeed()
297 #current_entry = self["content"].getCurrent()
298 self["content"].l.setList(self.feed.history) # Update list
299 self["content"].moveToIndex(0)
300 #self["content"].moveToEntry(current_entry)
301 self.updateInfo() # In case entry is no longer in history
302 self.setConditionalTitle() # Update title
303 return (self.feed.title, self.feed.history, self.id)
304 return (self.feed.title, self.feed.history, self.id)
306 def checkEmpty(self):
307 if self.id > 0 and not len(self.feed.history):
308 self.singleUpdate(self.id-1)
310 def showCurrentEntry(self):
311 current_entry = self["content"].getCurrent()
312 if current_entry is None: # empty list
315 self.session.openWithCallback(
319 cur_idx=self["content"].getSelectedIndex(),
320 entries=len(self.feed.history),
321 feedTitle=self.feed.title,
325 def selectEnclosure(self):
326 current_entry = self["content"].getCurrent()
327 if current_entry is None: # empty list
330 RSSBaseView.selectEnclosure(self, current_entry[3])
332 class RSSOverview(RSSBaseView):
333 """Shows an Overview over all RSS-Feeds known to rssPoller"""
336 <screen position="100,100" size="460,415" title="Simple RSS Reader" >
337 <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
338 <widget name="content" position="0,20" size="460,300" scrollbarMode="showOnDemand" />
339 <widget name="summary" position="0,320" size="460,95" font="Regular;16" />
342 def __init__(self, session, poller):
343 RSSBaseView.__init__(self, session, poller)
345 self["actions"] = ActionMap([ "OkCancelActions", "MenuActions", "ColorActions" ],
347 "ok": self.showCurrentEntry,
348 "cancel": self.close,
350 "yellow": self.selectEnclosure,
355 # We always have at least "New Items"-Feed
356 self["content"] = RSSFeedList(self.feeds)
357 self["summary"] = Label(' '.join([str(len(self.feeds[0][0].history)), _("Entries")]))
358 self["info"] = Label(_("Feed %s/%s") % (1, len(self.feeds)))
360 self["content"].connectSelChanged(self.updateInfo)
361 self.onLayoutFinish.append(self.__show)
362 self.onClose.append(self.__close)
365 self.rssPoller.addCallback(self.pollCallback)
368 self.rssPoller.removeCallback(self.pollCallback)
371 # Feedlist contains our virtual Feed and all real ones
372 self.feeds = [(self.rssPoller.newItemFeed,)]
373 self.feeds.extend([(feed,) for feed in self.rssPoller.feeds])
375 def pollCallback(self, id = None):
376 print "[SimpleRSS] SimpleRSS called back"
378 self["content"].invalidate()
380 def updateInfo(self):
381 current_entry = self["content"].getCurrent()
382 self["summary"].setText(' '.join([str(len(current_entry.history)), _("Entries")]))
383 self["info"].setText(_("Feed %s/%s") % (self["content"].getSelectedIndex()+1, len(self.feeds)))
386 from Screens.ChoiceBox import ChoiceBox
388 cur_idx = self["content"].getSelectedIndex()
391 (_("Update Feed"), "update"),
392 (_("Setup"), "setup"),
393 (_("Close"), "close")
397 (_("Setup"), "setup"),
398 (_("Close"), "close")
401 self.session.openWithCallback(
408 def menuChoice(self, result):
410 if result[1] == "update":
411 cur_idx = self["content"].getSelectedIndex()
413 self.singleUpdate(cur_idx-1)
414 elif result[1] == "setup":
415 from RSSSetup import RSSSetup
417 self.session.openWithCallback(
420 rssPoller=self.rssPoller
422 elif result[1] == "close":
426 current_entry = self["content"].getCurrent()
429 self["content"].l.setList(self.feeds)
431 self["content"].moveToEntry(current_entry)
436 return (self["content"].getCurrent(), self["content"].getSelectedIndex())
438 def previousFeed(self):
439 self["content"].down()
440 return (self["content"].getCurrent(), self["content"].getSelectedIndex())
442 def showCurrentEntry(self):
443 current_entry = self["content"].getCurrent()
444 self.session.openWithCallback(
449 rssPoller=self.rssPoller,
450 id=self["content"].getSelectedIndex()
453 def selectEnclosure(self):
454 # Build a list of all enclosures in this feed
456 for entry in self["content"].getCurrent().history:
457 enclosures.extend(entry[3])
458 RSSBaseView.selectEnclosure(self, enclosures)