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