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 # ============================================================================
34 from os.path import isfile, isdir
39 from portrait import FremantleRotation
42 from feedingitdbus import ServerObject
43 from config import Config
46 from opml import GetOpmlData, ExportOpmlData
50 socket.setdefaulttimeout(timeout)
52 CONFIGDIR="/home/user/.feedingit/"
54 class AddWidgetWizard(hildon.WizardDialog):
56 def __init__(self, parent, urlIn, titleIn=None):
58 self.notebook = gtk.Notebook()
60 self.nameEntry = hildon.Entry(gtk.HILDON_SIZE_AUTO)
61 self.nameEntry.set_placeholder("Enter Feed Name")
62 vbox = gtk.VBox(False,10)
63 label = gtk.Label("Enter Feed Name:")
64 vbox.pack_start(label)
65 vbox.pack_start(self.nameEntry)
66 if not titleIn == None:
67 self.nameEntry.set_text(titleIn)
68 self.notebook.append_page(vbox, None)
70 self.urlEntry = hildon.Entry(gtk.HILDON_SIZE_AUTO)
71 self.urlEntry.set_placeholder("Enter a URL")
72 self.urlEntry.set_text(urlIn)
73 self.urlEntry.select_region(0,-1)
75 vbox = gtk.VBox(False,10)
76 label = gtk.Label("Enter Feed URL:")
77 vbox.pack_start(label)
78 vbox.pack_start(self.urlEntry)
79 self.notebook.append_page(vbox, None)
81 labelEnd = gtk.Label("Success")
83 self.notebook.append_page(labelEnd, None)
85 hildon.WizardDialog.__init__(self, parent, "Add Feed", self.notebook)
87 # Set a handler for "switch-page" signal
88 #self.notebook.connect("switch_page", self.on_page_switch, self)
90 # Set a function to decide if user can go to next page
91 self.set_forward_page_func(self.some_page_func)
96 return (self.nameEntry.get_text(), self.urlEntry.get_text())
98 def on_page_switch(self, notebook, page, num, dialog):
101 def some_page_func(self, nb, current, userdata):
102 # Validate data for 1st page
104 return len(self.nameEntry.get_text()) != 0
106 # Check the url is not null, and starts with http
107 return ( (len(self.urlEntry.get_text()) != 0) and (self.urlEntry.get_text().lower().startswith("http")) )
113 class GetImage(threading.Thread):
114 def __init__(self, url, stream):
115 threading.Thread.__init__(self)
120 f = urllib2.urlopen(self.url)
123 self.stream.write(data)
126 class ImageDownloader():
129 self.downloading = False
131 def queueImage(self, url, stream):
132 self.images.append((url, stream))
133 if not self.downloading:
134 self.downloading = True
135 gobject.timeout_add(50, self.checkQueue)
137 def checkQueue(self):
138 for i in range(4-threading.activeCount()):
139 if len(self.images) > 0:
140 (url, stream) = self.images.pop()
141 GetImage(url, stream).start()
142 if len(self.images)>0:
143 gobject.timeout_add(200, self.checkQueue)
145 self.downloading=False
151 class Download(threading.Thread):
152 def __init__(self, listing, key, config):
153 threading.Thread.__init__(self)
154 self.listing = listing
159 self.listing.updateFeed(self.key, self.config.getExpiry())
162 class DownloadBar(gtk.ProgressBar):
163 def __init__(self, parent, listing, listOfKeys, config):
164 gtk.ProgressBar.__init__(self)
165 self.listOfKeys = listOfKeys[:]
166 self.listing = listing
167 self.total = len(self.listOfKeys)
172 #self.progress = gtk.ProgressBar()
173 #self.waitingWindow = hildon.Note("cancel", parent, "Downloading",
174 # progressbar=self.progress)
175 self.set_text("Downloading")
177 self.set_fraction(self.fraction)
180 self.timeout_handler_id = gobject.timeout_add(50, self.update_progress_bar)
181 #self.waitingWindow.show_all()
182 #response = self.waitingWindow.run()
183 #self.listOfKeys = []
184 #while threading.activeCount() > 1:
185 # Wait for current downloads to finish
187 #self.waitingWindow.destroy()
189 def update_progress_bar(self):
190 #self.progress_bar.pulse()
191 if threading.activeCount() < 4:
192 x = threading.activeCount() - 1
193 k = len(self.listOfKeys)
194 fin = self.total - k - x
195 fraction = float(fin)/float(self.total) + float(x)/(self.total*2.)
196 #print x, k, fin, fraction
197 self.set_fraction(fraction)
199 if len(self.listOfKeys)>0:
200 self.current = self.current+1
201 key = self.listOfKeys.pop()
202 if not self.listing.getCurrentlyDisplayedFeed() == key:
203 # Check if the feed is being displayed
204 download = Download(self.listing, key, self.config)
207 elif threading.activeCount() > 1:
210 #self.waitingWindow.destroy()
212 self.emit("download-done", "success")
217 class SortList(gtk.Dialog):
218 def __init__(self, parent, listing):
219 gtk.Dialog.__init__(self, "Organizer", parent)
220 self.listing = listing
222 self.vbox2 = gtk.VBox(False, 10)
224 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
225 button.set_label("Move Up")
226 button.connect("clicked", self.buttonUp)
227 self.vbox2.pack_start(button, expand=False, fill=False)
229 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
230 button.set_label("Move Down")
231 button.connect("clicked", self.buttonDown)
232 self.vbox2.pack_start(button, expand=False, fill=False)
234 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
235 button.set_label("Add Feed")
236 button.connect("clicked", self.buttonAdd)
237 self.vbox2.pack_start(button, expand=False, fill=False)
239 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
240 button.set_label("Edit Feed")
241 button.connect("clicked", self.buttonEdit)
242 self.vbox2.pack_start(button, expand=False, fill=False)
244 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
245 button.set_label("Delete")
246 button.connect("clicked", self.buttonDelete)
247 self.vbox2.pack_start(button, expand=False, fill=False)
249 #button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
250 #button.set_label("Done")
251 #button.connect("clicked", self.buttonDone)
252 #self.vbox.pack_start(button)
253 self.hbox2= gtk.HBox(False, 10)
254 self.pannableArea = hildon.PannableArea()
255 self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
256 self.treeview = gtk.TreeView(self.treestore)
257 self.hbox2.pack_start(self.pannableArea, expand=True)
259 self.hbox2.pack_end(self.vbox2, expand=False)
260 self.set_default_size(-1, 600)
261 self.vbox.pack_start(self.hbox2)
264 #self.connect("destroy", self.buttonDone)
266 def displayFeeds(self):
267 self.treeview.destroy()
268 self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
269 self.treeview = gtk.TreeView()
271 self.treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
272 hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview, gtk.HILDON_UI_MODE_EDIT)
274 self.treeview.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
276 self.pannableArea.add(self.treeview)
280 def refreshList(self, selected=None, offset=0):
281 rect = self.treeview.get_visible_rect()
282 y = rect.y+rect.height
283 self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
284 for key in self.listing.getListOfFeeds():
285 item = self.treestore.append([self.listing.getFeedTitle(key), key])
288 self.treeview.set_model(self.treestore)
289 if not selected == None:
290 self.treeview.get_selection().select_iter(selectedItem)
291 self.treeview.scroll_to_cell(self.treeview.get_model().get_path(selectedItem))
292 self.pannableArea.show_all()
294 def getSelectedItem(self):
295 (model, iter) = self.treeview.get_selection().get_selected()
298 return model.get_value(iter, 1)
300 def findIndex(self, key):
304 for row in self.treestore:
306 return (before, row.iter)
307 if key == list(row)[0]:
311 return (before, None)
313 def buttonUp(self, button):
314 key = self.getSelectedItem()
316 self.listing.moveUp(key)
317 self.refreshList(key, -10)
319 def buttonDown(self, button):
320 key = self.getSelectedItem()
322 self.listing.moveDown(key)
323 self.refreshList(key, 10)
325 def buttonDelete(self, button):
326 key = self.getSelectedItem()
328 self.listing.removeFeed(key)
331 def buttonEdit(self, button):
332 key = self.getSelectedItem()
334 wizard = AddWidgetWizard(self, self.listing.getFeedUrl(key), self.listing.getFeedTitle(key))
337 (title, url) = wizard.getData()
338 if (not title == '') and (not url == ''):
339 self.listing.editFeed(key, title, url)
343 def buttonDone(self, *args):
346 def buttonAdd(self, button, urlIn="http://"):
347 wizard = AddWidgetWizard(self, urlIn)
350 (title, url) = wizard.getData()
351 if (not title == '') and (not url == ''):
352 self.listing.addFeed(title, url)
357 class DisplayArticle(hildon.StackableWindow):
358 def __init__(self, title, text, link, index, key, listing):
359 hildon.StackableWindow.__init__(self)
360 self.imageDownloader = ImageDownloader()
366 self.set_title(title)
369 # Init the article display
370 self.view = gtkhtml2.View()
371 self.pannable_article = hildon.PannableArea()
372 self.pannable_article.add(self.view)
373 #self.pannable_article.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
374 self.gestureId = self.pannable_article.connect('horizontal-movement', self.gesture)
375 self.document = gtkhtml2.Document()
376 self.view.set_document(self.document)
378 self.document.connect("link_clicked", self._signal_link_clicked)
379 if not key == "1295627ef630df9d239abeb0ba631c3f":
380 # Do not download images if the feed is "Archived Articles"
381 self.document.connect("request-url", self._signal_request_url)
382 self.document.clear()
383 self.document.open_stream("text/html")
384 self.document.write_stream(self.text)
385 self.document.close_stream()
387 menu = hildon.AppMenu()
388 # Create a button and add it to the menu
389 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
390 button.set_label("Allow Horizontal Scrolling")
391 button.connect("clicked", self.horiz_scrolling_button)
394 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
395 button.set_label("Open in Browser")
396 button.connect("clicked", self._signal_link_clicked, self.link)
399 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
400 button.set_label("Add to Archived Articles")
401 button.connect("clicked", self.archive_button)
404 self.set_app_menu(menu)
407 self.add(self.pannable_article)
409 self.pannable_article.show_all()
411 self.destroyId = self.connect("destroy", self.destroyWindow)
412 #self.timeout_handler_id = gobject.timeout_add(300, self.reloadArticle)
414 def gesture(self, widget, direction, startx, starty):
416 self.emit("article-next", self.index)
418 self.emit("article-previous", self.index)
419 #self.timeout_handler_id = gobject.timeout_add(200, self.destroyWindow)
421 def destroyWindow(self, *args):
422 self.disconnect(self.destroyId)
423 self.emit("article-closed", self.index)
424 self.imageDownloader.stopAll()
427 def horiz_scrolling_button(self, *widget):
428 self.pannable_article.disconnect(self.gestureId)
429 self.pannable_article.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
431 def archive_button(self, *widget):
432 # Call the listing.addArchivedArticle
433 self.listing.addArchivedArticle(self.key, self.index)
435 #def reloadArticle(self, *widget):
436 # if threading.activeCount() > 1:
437 # Image thread are still running, come back in a bit
440 # for (stream, imageThread) in self.images:
442 # stream.write(imageThread.data)
447 def _signal_link_clicked(self, object, link):
448 bus = dbus.SystemBus()
449 proxy = bus.get_object("com.nokia.osso_browser", "/com/nokia/osso_browser/request")
450 iface = dbus.Interface(proxy, 'com.nokia.osso_browser')
451 iface.open_new_window(link)
453 def _signal_request_url(self, object, url, stream):
455 self.imageDownloader.queueImage(url, stream)
456 #imageThread = GetImage(url)
458 #self.images.append((stream, imageThread))
461 class DisplayFeed(hildon.StackableWindow):
462 def __init__(self, listing, feed, title, key, config):
463 hildon.StackableWindow.__init__(self)
464 self.listing = listing
466 self.feedTitle = title
467 self.set_title(title)
471 self.listing.setCurrentlyDisplayedFeed(self.key)
475 menu = hildon.AppMenu()
476 #button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
477 #button.set_label("Update Feed")
478 #button.connect("clicked", self.button_update_clicked)
481 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
482 button.set_label("Mark All As Read")
483 button.connect("clicked", self.buttonReadAllClicked)
485 self.set_app_menu(menu)
490 self.connect("destroy", self.destroyWindow)
492 def destroyWindow(self, *args):
493 self.emit("feed-closed", self.key)
495 #gobject.idle_add(self.feed.saveFeed, CONFIGDIR)
496 self.listing.closeCurrentlyDisplayedFeed()
498 def displayFeed(self):
499 self.vboxFeed = gtk.VBox(False, 10)
500 self.pannableFeed = hildon.PannableArea()
501 self.pannableFeed.add_with_viewport(self.vboxFeed)
502 self.pannableFeed.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
504 for index in range(self.feed.getNumberOfEntries()):
505 button = gtk.Button(self.feed.getTitle(index))
506 button.set_alignment(0,0)
508 if self.feed.isEntryRead(index):
509 #label.modify_font(pango.FontDescription("sans 16"))
510 label.modify_font(pango.FontDescription(self.config.getReadFont()))
512 #print self.listing.getFont() + " bold"
513 label.modify_font(pango.FontDescription(self.config.getUnreadFont()))
514 #label.modify_font(pango.FontDescription("sans bold 23"))
516 label.set_line_wrap(True)
518 label.set_size_request(self.get_size()[0]-50, -1)
519 button.connect("clicked", self.button_clicked, index)
520 self.buttons.append(button)
522 self.vboxFeed.pack_start(button, expand=False)
525 self.add(self.pannableFeed)
529 self.remove(self.pannableFeed)
531 def button_clicked(self, button, index, previous=False, next=False):
532 newDisp = DisplayArticle(self.feedTitle, self.feed.getArticle(index), self.feed.getLink(index), index, self.key, self.listing)
533 stack = hildon.WindowStack.get_default()
536 stack.pop_and_push(1, newDisp, tmp)
538 gobject.timeout_add(200, self.destroyArticle, tmp)
543 #if not self.disp == False:
544 # self.disp.destroyWindow()
546 #print type(self.disp).__name__
548 #self.disp.destroyWindow()
549 #stack.pop_and_push(1,newDisp)
551 # stack.push(newDisp)
554 if type(self.disp).__name__ == "DisplayArticle":
555 gobject.timeout_add(200, self.destroyArticle, self.disp)
557 #self.disp.show_all()
558 #if not self.disp == False:
559 # self.disp.destroyWindow()
565 self.ids.append(self.disp.connect("article-closed", self.onArticleClosed))
566 self.ids.append(self.disp.connect("article-next", self.nextArticle))
567 self.ids.append(self.disp.connect("article-previous", self.previousArticle))
569 def destroyArticle(self, handle):
570 handle.destroyWindow()
572 def nextArticle(self, object, index):
573 label = self.buttons[index].child
574 label.modify_font(pango.FontDescription(self.config.getReadFont()))
575 index = (index+1) % self.feed.getNumberOfEntries()
576 self.button_clicked(object, index, next=True)
578 def previousArticle(self, object, index):
579 label = self.buttons[index].child
580 label.modify_font(pango.FontDescription(self.config.getReadFont()))
581 index = (index-1) % self.feed.getNumberOfEntries()
582 self.button_clicked(object, index, previous=True)
584 def onArticleClosed(self, object, index):
585 label = self.buttons[index].child
586 label.modify_font(pango.FontDescription(self.config.getReadFont()))
587 self.buttons[index].show()
589 #def button_update_clicked(self, button):
590 # bar = DownloadBar(self, self.listing, [self.key,], self.config )
591 #self.feed.updateFeed()
595 def buttonReadAllClicked(self, button):
596 for index in range(self.feed.getNumberOfEntries()):
597 self.feed.setEntryRead(index)
598 label = self.buttons[index].child
599 label.modify_font(pango.FontDescription(self.config.getReadFont()))
600 self.buttons[index].show()
606 self.window = hildon.StackableWindow()
607 self.window.set_title("FeedingIt")
608 hildon.hildon_gtk_window_set_progress_indicator(self.window, 1)
609 self.mainVbox = gtk.VBox(False,10)
610 self.pannableListing = gtk.Label("Loading...")
611 self.mainVbox.pack_start(self.pannableListing)
612 self.window.add(self.mainVbox)
613 self.window.show_all()
614 self.config = Config(self.window, CONFIGDIR+"config.ini")
615 gobject.idle_add(self.createWindow)
617 def createWindow(self):
618 self.listing = Listing(CONFIGDIR)
620 self.downloadDialog = False
621 self.orientation = FremantleRotation("FeedingIt", main_window=self.window)
622 self.orientation.set_mode(self.config.getOrientation())
624 menu = hildon.AppMenu()
625 # Create a button and add it to the menu
626 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
627 button.set_label("Update All Feeds")
628 button.connect("clicked", self.button_update_clicked, "All")
631 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
632 button.set_label("Mark All As Read")
633 button.connect("clicked", self.button_markAll)
636 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
637 button.set_label("Organize Feeds")
638 button.connect("clicked", self.button_organize_clicked)
641 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
642 button.set_label("Preferences")
643 button.connect("clicked", self.button_preferences_clicked)
646 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
647 button.set_label("Import Feeds")
648 button.connect("clicked", self.button_import_clicked)
651 button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
652 button.set_label("Export Feeds")
653 button.connect("clicked", self.button_export_clicked)
656 self.window.set_app_menu(menu)
659 #self.feedWindow = hildon.StackableWindow()
660 #self.articleWindow = hildon.StackableWindow()
662 self.displayListing()
663 self.autoupdate = False
664 self.checkAutoUpdate()
665 hildon.hildon_gtk_window_set_progress_indicator(self.window, 0)
668 def button_markAll(self, button):
669 for key in self.listing.getListOfFeeds():
670 feed = self.listing.getFeed(key)
671 for index in range(feed.getNumberOfEntries()):
672 feed.setEntryRead(index)
675 def button_export_clicked(self, button):
676 opml = ExportOpmlData(self.window, self.listing)
678 def button_import_clicked(self, button):
679 opml = GetOpmlData(self.window)
680 feeds = opml.getData()
681 for (title, url) in feeds:
682 self.listing.addFeed(title, url)
683 self.displayListing()
685 def button_organize_clicked(self, button):
686 org = SortList(self.window, self.listing)
689 self.listing.saveConfig()
690 self.displayListing()
692 def button_update_clicked(self, button, key):
693 if not type(self.downloadDialog).__name__=="DownloadBar":
694 self.downloadDialog = DownloadBar(self.window, self.listing, self.listing.getListOfFeeds(), self.config )
695 self.downloadDialog.connect("download-done", self.onDownloadsDone)
696 self.mainVbox.pack_end(self.downloadDialog, expand=False, fill=False)
697 self.mainVbox.show_all()
698 #self.displayListing()
700 def onDownloadsDone(self, *widget):
701 self.downloadDialog.destroy()
702 self.downloadDialog = False
703 #self.displayListing()
706 def button_preferences_clicked(self, button):
707 dialog = self.config.createDialog()
708 dialog.connect("destroy", self.prefsClosed)
710 def show_confirmation_note(self, parent, title):
711 note = hildon.Note("confirmation", parent, "Are you sure you want to delete " + title +"?")
713 retcode = gtk.Dialog.run(note)
716 if retcode == gtk.RESPONSE_OK:
721 def displayListing(self):
723 self.mainVbox.remove(self.pannableListing)
726 self.vboxListing = gtk.VBox(False,10)
727 self.pannableListing = hildon.PannableArea()
728 self.pannableListing.add_with_viewport(self.vboxListing)
731 list = self.listing.getListOfFeeds()[:]
734 #button = gtk.Button(item)
735 button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT,
736 hildon.BUTTON_ARRANGEMENT_VERTICAL)
737 button.set_text(self.listing.getFeedTitle(key), self.listing.getFeedUpdateTime(key) + " / "
738 + str(self.listing.getFeedNumberOfUnreadItems(key)) + " Unread Items")
739 button.set_alignment(0,0,1,1)
740 button.connect("clicked", self.buttonFeedClicked, self, self.window, key)
741 self.vboxListing.pack_start(button, expand=False)
742 self.buttons[key] = button
744 #if type(self.downloadDialog).__name__=="DownloadBar":
745 # self.vboxListing.pack_start(self.downloadDialog)
746 self.mainVbox.pack_start(self.pannableListing)
747 self.window.show_all()
749 def refreshList(self):
750 for key in self.buttons.keys():
751 button = self.buttons[key]
752 button.set_text(self.listing.getFeedTitle(key), self.listing.getFeedUpdateTime(key) + " / "
753 + str(self.listing.getFeedNumberOfUnreadItems(key)) + " Unread Items")
755 def buttonFeedClicked(widget, button, self, window, key):
756 disp = DisplayFeed(self.listing, self.listing.getFeed(key), self.listing.getFeedTitle(key), key, self.config)
757 disp.connect("feed-closed", self.onFeedClosed)
759 def onFeedClosed(self, object, key):
760 #self.displayListing()
762 #self.buttons[key].set_text(self.listing.getFeedTitle(key), self.listing.getFeedUpdateTime(key) + " / "
763 # + str(self.listing.getFeedNumberOfUnreadItems(key)) + " Unread Items")
764 #self.buttons[key].show()
767 self.window.connect("destroy", gtk.main_quit)
769 for key in self.listing.getListOfFeeds():
770 self.listing.getFeed(key).saveFeed(CONFIGDIR)
771 self.listing.saveConfig()
773 def prefsClosed(self, *widget):
774 self.orientation.set_mode(self.config.getOrientation())
775 self.checkAutoUpdate()
777 def checkAutoUpdate(self, *widget):
778 interval = int(self.config.getUpdateInterval()*3600000)
779 if self.config.isAutoUpdateEnabled():
780 if self.autoupdate == False:
781 self.autoupdateId = gobject.timeout_add(interval, self.automaticUpdate)
782 self.autoupdate = interval
783 elif not self.autoupdate == interval:
784 # If auto-update is enabled, but not at the right frequency
785 gobject.source_remove(self.autoupdateId)
786 self.autoupdateId = gobject.timeout_add(interval, self.automaticUpdate)
787 self.autoupdate = interval
789 if not self.autoupdate == False:
790 gobject.source_remove(self.autoupdateId)
791 self.autoupdate = False
793 def automaticUpdate(self, *widget):
794 # Need to check for internet connection
795 # If no internet connection, try again in 10 minutes:
796 # gobject.timeout_add(int(5*3600000), self.automaticUpdate)
797 self.button_update_clicked(None, None)
802 for key in self.listing.getListOfFeeds():
803 if self.listing.getFeedNumberOfUnreadItems(key) > 0:
804 status += self.listing.getFeedTitle(key) + ": \t" + str(self.listing.getFeedNumberOfUnreadItems(key)) + " Unread Items\n"
806 status = "No unread items"
809 if __name__ == "__main__":
810 gobject.signal_new("feed-closed", DisplayFeed, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
811 gobject.signal_new("article-closed", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
812 gobject.signal_new("article-next", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
813 gobject.signal_new("article-previous", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
814 gobject.signal_new("download-done", DownloadBar, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
815 gobject.threads_init()
816 if not isdir(CONFIGDIR):
820 print "Error: Can't create configuration directory"
823 dbusHandler = ServerObject(app)