1 #!/usr/bin/env python2.5
4 # Copyright (c) 2007-2008 INdT.
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # ============================================================================
21 # Author : Yves Marcoz
23 # Description : Simple RSS Reader
24 # ============================================================================
40 from os.path import isfile, isdir
45 from portrait import FremantleRotation
48 from feedingitdbus import ServerObject
49 from config import Config
52 from opml import GetOpmlData, ExportOpmlData
56 socket.setdefaulttimeout(timeout)
58 CONFIGDIR="/home/user/.feedingit/"
60 class AddWidgetWizard(hildon.WizardDialog):
62 def __init__(self, parent, urlIn, titleIn=None):
64 self.notebook = gtk.Notebook()
66 self.nameEntry = hildon.Entry(gtk.HILDON_SIZE_AUTO)
67 self.nameEntry.set_placeholder("Enter Feed Name")
68 vbox = gtk.VBox(False,10)
69 label = gtk.Label("Enter Feed Name:")
70 vbox.pack_start(label)
71 vbox.pack_start(self.nameEntry)
72 if not titleIn == None:
73 self.nameEntry.set_text(titleIn)
74 self.notebook.append_page(vbox, None)
76 self.urlEntry = hildon.Entry(gtk.HILDON_SIZE_AUTO)
77 self.urlEntry.set_placeholder("Enter a URL")
78 self.urlEntry.set_text(urlIn)
79 self.urlEntry.select_region(0,-1)
81 vbox = gtk.VBox(False,10)
82 label = gtk.Label("Enter Feed URL:")
83 vbox.pack_start(label)
84 vbox.pack_start(self.urlEntry)
85 self.notebook.append_page(vbox, None)
87 labelEnd = gtk.Label("Success")
89 self.notebook.append_page(labelEnd, None)
91 hildon.WizardDialog.__init__(self, parent, "Add Feed", self.notebook)
93 # Set a handler for "switch-page" signal
94 #self.notebook.connect("switch_page", self.on_page_switch, self)
96 # Set a function to decide if user can go to next page
97 self.set_forward_page_func(self.some_page_func)
102 return (self.nameEntry.get_text(), self.urlEntry.get_text())
104 def on_page_switch(self, notebook, page, num, dialog):
107 def some_page_func(self, nb, current, userdata):
108 # Validate data for 1st page
110 return len(self.nameEntry.get_text()) != 0
112 # Check the url is not null, and starts with http
113 return ( (len(self.urlEntry.get_text()) != 0) and (self.urlEntry.get_text().lower().startswith("http")) )
119 class GetImage(threading.Thread):
120 def __init__(self, url, stream):
121 threading.Thread.__init__(self)
126 f = urllib2.urlopen(self.url)
129 self.stream.write(data)
132 class ImageDownloader():
135 self.downloading = False
137 def queueImage(self, url, stream):
138 self.images.append((url, stream))
139 if not self.downloading:
140 self.downloading = True
141 gobject.timeout_add(50, self.checkQueue)
143 def checkQueue(self):
144 for i in range(4-threading.activeCount()):
145 if len(self.images) > 0:
146 (url, stream) = self.images.pop()
147 GetImage(url, stream).start()
148 if len(self.images)>0:
149 gobject.timeout_add(200, self.checkQueue)
151 self.downloading=False
157 class Download(threading.Thread):
158 def __init__(self, listing, key, config):
159 threading.Thread.__init__(self)
160 self.listing = listing
165 self.listing.updateFeed(self.key, self.config.getExpiry())
168 class DownloadBar(gtk.ProgressBar):
169 def __init__(self, parent, listing, listOfKeys, config, single=False):
170 gtk.ProgressBar.__init__(self)
171 self.listOfKeys = listOfKeys[:]
172 self.listing = listing
173 self.total = len(self.listOfKeys)
179 #self.progress = gtk.ProgressBar()
180 #self.waitingWindow = hildon.Note("cancel", parent, "Downloading",
181 # progressbar=self.progress)
182 self.set_text("Downloading")
184 self.set_fraction(self.fraction)
187 self.timeout_handler_id = gobject.timeout_add(50, self.update_progress_bar)
188 #self.waitingWindow.show_all()
189 #response = self.waitingWindow.run()
190 #self.listOfKeys = []
191 #while threading.activeCount() > 1:
192 # Wait for current downloads to finish
194 #self.waitingWindow.destroy()
196 def update_progress_bar(self):
197 #self.progress_bar.pulse()
198 if threading.activeCount() < 4:
199 x = threading.activeCount() - 1
200 k = len(self.listOfKeys)
201 fin = self.total - k - x
202 fraction = float(fin)/float(self.total) + float(x)/(self.total*2.)
203 #print x, k, fin, fraction
204 self.set_fraction(fraction)
206 if len(self.listOfKeys)>0:
207 self.current = self.current+1
208 key = self.listOfKeys.pop()
209 if (not self.listing.getCurrentlyDisplayedFeed() == key) or (self.single == True):
210 # Check if the feed is being displayed
211 download = Download(self.listing, key, self.config)
214 elif threading.activeCount() > 1:
217 #self.waitingWindow.destroy()
219 self.emit("download-done", "success")
224 class SortList(gtk.Dialog):
225 def __init__(self, parent, listing):
226 gtk.Dialog.__init__(self, "Organizer", parent)
227 self.listing = listing
229 self.vbox2 = gtk.VBox(False, 10)
231 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
232 button.set_label("Move Up")
233 button.connect("clicked", self.buttonUp)
234 self.vbox2.pack_start(button, expand=False, fill=False)
236 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
237 button.set_label("Move Down")
238 button.connect("clicked", self.buttonDown)
239 self.vbox2.pack_start(button, expand=False, fill=False)
241 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
242 button.set_label("Add Feed")
243 button.connect("clicked", self.buttonAdd)
244 self.vbox2.pack_start(button, expand=False, fill=False)
246 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
247 button.set_label("Edit Feed")
248 button.connect("clicked", self.buttonEdit)
249 self.vbox2.pack_start(button, expand=False, fill=False)
251 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
252 button.set_label("Delete")
253 button.connect("clicked", self.buttonDelete)
254 self.vbox2.pack_start(button, expand=False, fill=False)
256 #button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
257 #button.set_label("Done")
258 #button.connect("clicked", self.buttonDone)
259 #self.vbox.pack_start(button)
260 self.hbox2= gtk.HBox(False, 10)
261 self.pannableArea = hildon.PannableArea()
262 self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
263 self.treeview = gtk.TreeView(self.treestore)
264 self.hbox2.pack_start(self.pannableArea, expand=True)
266 self.hbox2.pack_end(self.vbox2, expand=False)
267 self.set_default_size(-1, 600)
268 self.vbox.pack_start(self.hbox2)
271 #self.connect("destroy", self.buttonDone)
273 def displayFeeds(self):
274 self.treeview.destroy()
275 self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
276 self.treeview = gtk.TreeView()
278 self.treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
279 hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview, gtk.HILDON_UI_MODE_EDIT)
281 self.treeview.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
283 self.pannableArea.add(self.treeview)
287 def refreshList(self, selected=None, offset=0):
288 rect = self.treeview.get_visible_rect()
289 y = rect.y+rect.height
290 self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
291 for key in self.listing.getListOfFeeds():
292 item = self.treestore.append([self.listing.getFeedTitle(key), key])
295 self.treeview.set_model(self.treestore)
296 if not selected == None:
297 self.treeview.get_selection().select_iter(selectedItem)
298 self.treeview.scroll_to_cell(self.treeview.get_model().get_path(selectedItem))
299 self.pannableArea.show_all()
301 def getSelectedItem(self):
302 (model, iter) = self.treeview.get_selection().get_selected()
305 return model.get_value(iter, 1)
307 def findIndex(self, key):
311 for row in self.treestore:
313 return (before, row.iter)
314 if key == list(row)[0]:
318 return (before, None)
320 def buttonUp(self, button):
321 key = self.getSelectedItem()
323 self.listing.moveUp(key)
324 self.refreshList(key, -10)
326 def buttonDown(self, button):
327 key = self.getSelectedItem()
329 self.listing.moveDown(key)
330 self.refreshList(key, 10)
332 def buttonDelete(self, button):
333 key = self.getSelectedItem()
335 self.listing.removeFeed(key)
338 def buttonEdit(self, button):
339 key = self.getSelectedItem()
341 wizard = AddWidgetWizard(self, self.listing.getFeedUrl(key), self.listing.getFeedTitle(key))
344 (title, url) = wizard.getData()
345 if (not title == '') and (not url == ''):
346 self.listing.editFeed(key, title, url)
350 def buttonDone(self, *args):
353 def buttonAdd(self, button, urlIn="http://"):
354 wizard = AddWidgetWizard(self, urlIn)
357 (title, url) = wizard.getData()
358 if (not title == '') and (not url == ''):
359 self.listing.addFeed(title, url)
364 class DisplayArticle(hildon.StackableWindow):
365 def __init__(self, title, text, link, index, key, listing, config):
366 hildon.StackableWindow.__init__(self)
367 self.imageDownloader = ImageDownloader()
373 self.set_title(title)
377 # Init the article display
379 self.view = webkit.WebView()
380 #self.view.set_editable(False)
382 self.view = gtkhtml2.View()
383 self.document = gtkhtml2.Document()
384 self.view.set_document(self.document)
385 self.document.connect("link_clicked", self._signal_link_clicked)
386 self.pannable_article = hildon.PannableArea()
387 self.pannable_article.add(self.view)
388 #self.pannable_article.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
389 #self.gestureId = self.pannable_article.connect('horizontal-movement', self.gesture)
392 self.view.load_string(self.text, "text/html", "utf-8", self.link)
393 self.view.set_zoom_level(float(config.getArtFontSize())/10.)
395 if not key == "1295627ef630df9d239abeb0ba631c3f":
396 # Do not download images if the feed is "Archived Articles"
397 self.document.connect("request-url", self._signal_request_url)
399 self.document.clear()
400 self.document.open_stream("text/html")
401 self.document.write_stream(self.text)
402 self.document.close_stream()
404 menu = hildon.AppMenu()
405 # Create a button and add it to the menu
406 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
407 button.set_label("Allow Horizontal Scrolling")
408 button.connect("clicked", self.horiz_scrolling_button)
411 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
412 button.set_label("Open in Browser")
413 button.connect("clicked", self._signal_link_clicked, self.link)
416 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
417 button.set_label("Add to Archived Articles")
418 button.connect("clicked", self.archive_button)
421 self.set_app_menu(menu)
424 #self.event_box = gtk.EventBox()
425 #self.event_box.add(self.pannable_article)
426 self.add(self.pannable_article)
429 self.pannable_article.show_all()
431 self.destroyId = self.connect("destroy", self.destroyWindow)
433 self.view.connect("button_press_event", self.button_pressed)
434 self.view.connect("button_release_event", self.button_released)
435 #self.timeout_handler_id = gobject.timeout_add(300, self.reloadArticle)
437 def button_pressed(self, window, event):
438 #print event.x, event.y
439 self.coords = (event.x, event.y)
441 def button_released(self, window, event):
442 x = self.coords[0] - event.x
443 y = self.coords[1] - event.y
447 self.emit("article-previous", self.index)
449 self.emit("article-next", self.index)
453 #def gesture(self, widget, direction, startx, starty):
454 # if (direction == 3):
455 # self.emit("article-next", self.index)
456 # if (direction == 2):
457 # self.emit("article-previous", self.index)
458 #print startx, starty
459 #self.timeout_handler_id = gobject.timeout_add(200, self.destroyWindow)
461 def destroyWindow(self, *args):
462 self.disconnect(self.destroyId)
463 self.emit("article-closed", self.index)
464 self.imageDownloader.stopAll()
467 def horiz_scrolling_button(self, *widget):
468 self.pannable_article.disconnect(self.gestureId)
469 self.pannable_article.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
471 def archive_button(self, *widget):
472 # Call the listing.addArchivedArticle
473 self.listing.addArchivedArticle(self.key, self.index)
475 #def reloadArticle(self, *widget):
476 # if threading.activeCount() > 1:
477 # Image thread are still running, come back in a bit
480 # for (stream, imageThread) in self.images:
482 # stream.write(imageThread.data)
487 def _signal_link_clicked(self, object, link):
488 bus = dbus.SystemBus()
489 proxy = bus.get_object("com.nokia.osso_browser", "/com/nokia/osso_browser/request")
490 iface = dbus.Interface(proxy, 'com.nokia.osso_browser')
493 def _signal_request_url(self, object, url, stream):
495 self.imageDownloader.queueImage(url, stream)
496 #imageThread = GetImage(url)
498 #self.images.append((stream, imageThread))
501 class DisplayFeed(hildon.StackableWindow):
502 def __init__(self, listing, feed, title, key, config):
503 hildon.StackableWindow.__init__(self)
504 self.listing = listing
506 self.feedTitle = title
507 self.set_title(title)
511 self.downloadDialog = False
513 self.listing.setCurrentlyDisplayedFeed(self.key)
517 menu = hildon.AppMenu()
518 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
519 button.set_label("Update Feed")
520 button.connect("clicked", self.button_update_clicked)
523 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
524 button.set_label("Mark All As Read")
525 button.connect("clicked", self.buttonReadAllClicked)
527 self.set_app_menu(menu)
532 self.connect("destroy", self.destroyWindow)
534 def destroyWindow(self, *args):
535 self.emit("feed-closed", self.key)
537 #gobject.idle_add(self.feed.saveFeed, CONFIGDIR)
538 self.listing.closeCurrentlyDisplayedFeed()
540 def displayFeed(self):
541 self.vboxFeed = gtk.VBox(False, 10)
542 self.pannableFeed = hildon.PannableArea()
543 self.pannableFeed.add_with_viewport(self.vboxFeed)
544 self.pannableFeed.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
546 for index in range(self.feed.getNumberOfEntries()):
547 button = gtk.Button(self.feed.getTitle(index))
548 button.set_alignment(0,0)
550 if self.feed.isEntryRead(index):
551 #label.modify_font(pango.FontDescription("sans 16"))
552 label.modify_font(pango.FontDescription(self.config.getReadFont()))
554 #print self.listing.getFont() + " bold"
555 label.modify_font(pango.FontDescription(self.config.getUnreadFont()))
556 #label.modify_font(pango.FontDescription("sans bold 23"))
558 label.set_line_wrap(True)
560 label.set_size_request(self.get_size()[0]-50, -1)
561 button.connect("clicked", self.button_clicked, index)
562 self.buttons.append(button)
564 self.vboxFeed.pack_start(button, expand=False)
567 self.add(self.pannableFeed)
571 self.remove(self.pannableFeed)
573 def button_clicked(self, button, index, previous=False, next=False):
574 newDisp = DisplayArticle(self.feedTitle, self.feed.getArticle(index), self.feed.getLink(index), index, self.key, self.listing, self.config)
575 stack = hildon.WindowStack.get_default()
578 stack.pop_and_push(1, newDisp, tmp)
580 gobject.timeout_add(200, self.destroyArticle, tmp)
585 #if not self.disp == False:
586 # self.disp.destroyWindow()
588 #print type(self.disp).__name__
590 #self.disp.destroyWindow()
591 #stack.pop_and_push(1,newDisp)
593 # stack.push(newDisp)
596 if type(self.disp).__name__ == "DisplayArticle":
597 gobject.timeout_add(200, self.destroyArticle, self.disp)
599 #self.disp.show_all()
600 #if not self.disp == False:
601 # self.disp.destroyWindow()
607 self.ids.append(self.disp.connect("article-closed", self.onArticleClosed))
608 self.ids.append(self.disp.connect("article-next", self.nextArticle))
609 self.ids.append(self.disp.connect("article-previous", self.previousArticle))
611 def destroyArticle(self, handle):
612 handle.destroyWindow()
614 def nextArticle(self, object, index):
615 label = self.buttons[index].child
616 label.modify_font(pango.FontDescription(self.config.getReadFont()))
617 index = (index+1) % self.feed.getNumberOfEntries()
618 self.button_clicked(object, index, next=True)
620 def previousArticle(self, object, index):
621 label = self.buttons[index].child
622 label.modify_font(pango.FontDescription(self.config.getReadFont()))
623 index = (index-1) % self.feed.getNumberOfEntries()
624 self.button_clicked(object, index, previous=True)
626 def onArticleClosed(self, object, index):
627 label = self.buttons[index].child
628 label.modify_font(pango.FontDescription(self.config.getReadFont()))
629 self.buttons[index].show()
631 def button_update_clicked(self, button):
632 #bar = DownloadBar(self, self.listing, [self.key,], self.config )
633 if not type(self.downloadDialog).__name__=="DownloadBar":
634 self.pannableFeed.destroy()
635 self.vbox = gtk.VBox(False, 10)
636 self.downloadDialog = DownloadBar(self.window, self.listing, [self.key,], self.config, single=True )
637 self.downloadDialog.connect("download-done", self.onDownloadsDone)
638 self.vbox.pack_start(self.downloadDialog, expand=False, fill=False)
642 def onDownloadsDone(self, *widget):
645 #self.feed.updateFeed()
649 def buttonReadAllClicked(self, button):
650 for index in range(self.feed.getNumberOfEntries()):
651 self.feed.setEntryRead(index)
652 label = self.buttons[index].child
653 label.modify_font(pango.FontDescription(self.config.getReadFont()))
654 self.buttons[index].show()
660 self.window = hildon.StackableWindow()
661 self.window.set_title("FeedingIt")
662 hildon.hildon_gtk_window_set_progress_indicator(self.window, 1)
663 self.mainVbox = gtk.VBox(False,10)
664 self.pannableListing = gtk.Label("Loading...")
665 self.mainVbox.pack_start(self.pannableListing)
666 self.window.add(self.mainVbox)
667 self.window.show_all()
668 self.config = Config(self.window, CONFIGDIR+"config.ini")
669 gobject.idle_add(self.createWindow)
671 def createWindow(self):
672 self.listing = Listing(CONFIGDIR)
674 self.downloadDialog = False
675 #self.orientation = FremantleRotation("FeedingIt", main_window=self.window)
676 #self.orientation.set_mode(self.config.getOrientation())
678 menu = hildon.AppMenu()
679 # Create a button and add it to the menu
680 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
681 button.set_label("Update All Feeds")
682 button.connect("clicked", self.button_update_clicked, "All")
685 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
686 button.set_label("Mark All As Read")
687 button.connect("clicked", self.button_markAll)
690 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
691 button.set_label("Organize Feeds")
692 button.connect("clicked", self.button_organize_clicked)
695 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
696 button.set_label("Preferences")
697 button.connect("clicked", self.button_preferences_clicked)
700 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
701 button.set_label("Import Feeds")
702 button.connect("clicked", self.button_import_clicked)
705 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
706 button.set_label("Export Feeds")
707 button.connect("clicked", self.button_export_clicked)
710 self.window.set_app_menu(menu)
713 #self.feedWindow = hildon.StackableWindow()
714 #self.articleWindow = hildon.StackableWindow()
716 self.displayListing()
717 self.autoupdate = False
718 self.checkAutoUpdate()
719 hildon.hildon_gtk_window_set_progress_indicator(self.window, 0)
721 def button_markAll(self, button):
722 for key in self.listing.getListOfFeeds():
723 feed = self.listing.getFeed(key)
724 for index in range(feed.getNumberOfEntries()):
725 feed.setEntryRead(index)
728 def button_export_clicked(self, button):
729 opml = ExportOpmlData(self.window, self.listing)
731 def button_import_clicked(self, button):
732 opml = GetOpmlData(self.window)
733 feeds = opml.getData()
734 for (title, url) in feeds:
735 self.listing.addFeed(title, url)
736 self.displayListing()
738 def addFeed(self, urlIn="http://"):
739 wizard = AddWidgetWizard(self.window, urlIn)
742 (title, url) = wizard.getData()
743 if (not title == '') and (not url == ''):
744 self.listing.addFeed(title, url)
746 self.displayListing()
748 def button_organize_clicked(self, button):
749 org = SortList(self.window, self.listing)
752 self.listing.saveConfig()
753 self.displayListing()
755 def button_update_clicked(self, button, key):
756 if not type(self.downloadDialog).__name__=="DownloadBar":
757 self.downloadDialog = DownloadBar(self.window, self.listing, self.listing.getListOfFeeds(), self.config )
758 self.downloadDialog.connect("download-done", self.onDownloadsDone)
759 self.mainVbox.pack_end(self.downloadDialog, expand=False, fill=False)
760 self.mainVbox.show_all()
761 #self.displayListing()
763 def onDownloadsDone(self, *widget):
764 self.downloadDialog.destroy()
765 self.downloadDialog = False
766 #self.displayListing()
769 def button_preferences_clicked(self, button):
770 dialog = self.config.createDialog()
771 dialog.connect("destroy", self.prefsClosed)
773 def show_confirmation_note(self, parent, title):
774 note = hildon.Note("confirmation", parent, "Are you sure you want to delete " + title +"?")
776 retcode = gtk.Dialog.run(note)
779 if retcode == gtk.RESPONSE_OK:
784 def displayListing(self):
786 self.mainVbox.remove(self.pannableListing)
789 self.vboxListing = gtk.VBox(False,10)
790 self.pannableListing = hildon.PannableArea()
791 self.pannableListing.add_with_viewport(self.vboxListing)
794 list = self.listing.getListOfFeeds()[:]
797 #button = gtk.Button(item)
798 button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT,
799 hildon.BUTTON_ARRANGEMENT_VERTICAL)
800 button.set_text(self.listing.getFeedTitle(key), self.listing.getFeedUpdateTime(key) + " / "
801 + str(self.listing.getFeedNumberOfUnreadItems(key)) + " Unread Items")
802 button.set_alignment(0,0,1,1)
803 button.connect("clicked", self.buttonFeedClicked, self, self.window, key)
804 self.vboxListing.pack_start(button, expand=False)
805 self.buttons[key] = button
807 #if type(self.downloadDialog).__name__=="DownloadBar":
808 # self.vboxListing.pack_start(self.downloadDialog)
809 self.mainVbox.pack_start(self.pannableListing)
810 self.window.show_all()
812 def refreshList(self):
813 for key in self.listing.getListOfFeeds():
814 if self.buttons.has_key(key):
815 button = self.buttons[key]
816 button.set_text(self.listing.getFeedTitle(key), self.listing.getFeedUpdateTime(key) + " / "
817 + str(self.listing.getFeedNumberOfUnreadItems(key)) + " Unread Items")
819 self.displayListing()
822 def buttonFeedClicked(widget, button, self, window, key):
823 disp = DisplayFeed(self.listing, self.listing.getFeed(key), self.listing.getFeedTitle(key), key, self.config)
824 disp.connect("feed-closed", self.onFeedClosed)
826 def onFeedClosed(self, object, key):
827 #self.displayListing()
829 #self.buttons[key].set_text(self.listing.getFeedTitle(key), self.listing.getFeedUpdateTime(key) + " / "
830 # + str(self.listing.getFeedNumberOfUnreadItems(key)) + " Unread Items")
831 #self.buttons[key].show()
834 self.window.connect("destroy", gtk.main_quit)
836 for key in self.listing.getListOfFeeds():
837 self.listing.getFeed(key).saveFeed(CONFIGDIR)
838 self.listing.saveConfig()
840 def prefsClosed(self, *widget):
841 self.orientation.set_mode(self.config.getOrientation())
842 self.checkAutoUpdate()
844 def checkAutoUpdate(self, *widget):
845 interval = int(self.config.getUpdateInterval()*3600000)
846 if self.config.isAutoUpdateEnabled():
847 if self.autoupdate == False:
848 self.autoupdateId = gobject.timeout_add(interval, self.automaticUpdate)
849 self.autoupdate = interval
850 elif not self.autoupdate == interval:
851 # If auto-update is enabled, but not at the right frequency
852 gobject.source_remove(self.autoupdateId)
853 self.autoupdateId = gobject.timeout_add(interval, self.automaticUpdate)
854 self.autoupdate = interval
856 if not self.autoupdate == False:
857 gobject.source_remove(self.autoupdateId)
858 self.autoupdate = False
860 def automaticUpdate(self, *widget):
861 # Need to check for internet connection
862 # If no internet connection, try again in 10 minutes:
863 # gobject.timeout_add(int(5*3600000), self.automaticUpdate)
864 self.button_update_clicked(None, None)
869 for key in self.listing.getListOfFeeds():
870 if self.listing.getFeedNumberOfUnreadItems(key) > 0:
871 status += self.listing.getFeedTitle(key) + ": \t" + str(self.listing.getFeedNumberOfUnreadItems(key)) + " Unread Items\n"
873 status = "No unread items"
876 if __name__ == "__main__":
877 gobject.signal_new("feed-closed", DisplayFeed, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
878 gobject.signal_new("article-closed", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
879 gobject.signal_new("article-next", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
880 gobject.signal_new("article-previous", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
881 gobject.signal_new("download-done", DownloadBar, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
882 gobject.threads_init()
883 if not isdir(CONFIGDIR):
887 print "Error: Can't create configuration directory"
890 dbusHandler = ServerObject(app)