# ============================================================================
import gtk
-from pango import FontDescription
import pango
import hildon
#import gtkhtml2
import gobject
from aboutdialog import HeAboutDialog
from portrait import FremantleRotation
-from threading import Thread, activeCount
from feedingitdbus import ServerObject
from config import Config
from cgi import escape
get_iface()
doit()
+def open_in_browser(link):
+ bus = dbus.SessionBus()
+ b_proxy = bus.get_object("com.nokia.osso_browser",
+ "/com/nokia/osso_browser/request")
+ b_iface = dbus.Interface(b_proxy, 'com.nokia.osso_browser')
+
+ notify("Opening %s" % link)
+
+ # We open the link asynchronously: if the web browser is not
+ # already running, this can take a while.
+ def error_handler():
+ """
+ Something went wrong opening the URL.
+ """
+ def e(exception):
+ notify("Error opening %s: %s" % (link, str(exception)))
+ return e
+
+ b_iface.open_new_window(link,
+ reply_handler=lambda *args: None,
+ error_handler=error_handler())
+
##
# Removes HTML or XML character references and entities from a text string.
#
self.downloadbars.append(weakref.ref (self))
self.set_fraction(0)
self.__class__.update_bars()
- self.show_all()
@classmethod
def downloading(cls):
if link == None:
link = self.currentUrl
- bus = dbus.SessionBus()
- b_proxy = bus.get_object("com.nokia.osso_browser",
- "/com/nokia/osso_browser/request")
- b_iface = dbus.Interface(b_proxy, 'com.nokia.osso_browser')
-
- notify("Opening %s" % link)
-
- # We open the link asynchronously: if the web browser is not
- # already running, this can take a while.
- def error_handler():
- """
- Something went wrong opening the URL.
- """
- def e(exception):
- notify("Error opening %s: %s" % (link, str(exception)))
- return e
-
- b_iface.open_new_window(link,
- reply_handler=lambda *args: None,
- error_handler=error_handler())
+ open_in_browser(link)
class DisplayFeed(hildon.StackableWindow):
- def __init__(self, listing, feed, title, key, config):
+ def __init__(self, listing, config):
hildon.StackableWindow.__init__(self)
+ self.connect('configure-event', self.on_configure_event)
+ self.connect("delete_event", self.delete_window)
+ self.connect("destroy", self.destroyWindow)
+
self.listing = listing
- self.feed = feed
- self.feedTitle = title
- self.set_title(title)
- self.key=key
+ self.config = config
+
# Articles to show.
#
# If hide read articles is set, this is set to the set of
# but then decides to move back, previous should select the
# just read article.
self.articles = list()
- self.config = config
self.downloadDialog = False
button.set_label("Mark all as read")
button.connect("clicked", self.buttonReadAllClicked)
menu.append(button)
-
- if key=="ArchivedArticles":
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Delete read articles")
- button.connect("clicked", self.buttonPurgeArticles)
- menu.append(button)
+
+ button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+ button.set_label("Delete read articles")
+ button.connect("clicked", self.buttonPurgeArticles)
+ menu.append(button)
+ self.archived_article_buttons = [button]
self.set_app_menu(menu)
menu.show_all()
- self.main_vbox = gtk.VBox(False, 0)
- self.add(self.main_vbox)
+ self.feedItems = gtk.ListStore(str, str)
- self.pannableFeed = None
- self.displayFeed()
+ self.feedList = hildon.GtkTreeView(gtk.HILDON_UI_MODE_NORMAL)
+ self.feedList.set_model(self.feedItems)
+ self.feedList.set_rules_hint(True)
+ self.feedList.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_HORIZONTAL)
+ self.feedList.set_hover_selection(False)
+ self.feedList.connect('hildon-row-tapped',
+ self.on_feedList_row_activated)
- if DownloadBar.downloading ():
- self.show_download_bar ()
+ self.markup_renderer = gtk.CellRendererText()
+ self.markup_renderer.set_property('wrap-mode', pango.WRAP_WORD_CHAR)
+ self.markup_renderer.set_property('background', bg_color) #"#333333")
+ (width, height) = self.get_size()
+ self.markup_renderer.set_property('wrap-width', width-20)
+ self.markup_renderer.set_property('ypad', 8)
+ self.markup_renderer.set_property('xpad', 5)
+ markup_column = gtk.TreeViewColumn('', self.markup_renderer, \
+ markup=FEED_COLUMN_MARKUP)
+ self.feedList.append_column(markup_column)
+
+ vbox = gtk.VBox(False, 10)
+ vbox.pack_start(self.feedList)
- self.connect('configure-event', self.on_configure_event)
- self.connect("destroy", self.destroyWindow)
+ self.pannableFeed = hildon.PannableArea()
+ self.pannableFeed.set_property('hscrollbar-policy', gtk.POLICY_NEVER)
+ self.pannableFeed.add_with_viewport(vbox)
+
+ self.main_vbox = gtk.VBox(False, 0)
+ self.main_vbox.pack_start(self.pannableFeed)
+
+ self.add(self.main_vbox)
+
+ self.main_vbox.show_all()
def on_configure_event(self, window, event):
if getattr(self, 'markup_renderer', None) is None:
self.feedItems.set_value(it, FEED_COLUMN_MARKUP, markup)
it = self.feedItems.iter_next(it)
+ def delete_window(self, *args):
+ """
+ Prevent the window from being deleted.
+ """
+ self.hide()
+
+ try:
+ key = self.key
+ except AttributeError:
+ key = None
+
+ if key is not None:
+ self.listing.updateUnread(key)
+ self.emit("feed-closed", key)
+ self.key = None
+ self.feedItems.clear()
+
+ return True
+
def destroyWindow(self, *args):
- #self.feed.saveUnread(CONFIGDIR)
- self.listing.updateUnread(self.key)
- self.emit("feed-closed", self.key)
+ try:
+ key = self.key
+ except AttributeError:
+ key = None
+
self.destroy()
- #gobject.idle_add(self.feed.saveFeed, CONFIGDIR)
- #self.listing.closeCurrentlyDisplayedFeed()
def fix_title(self, title):
return escape(unescape(title).replace("<em>","").replace("</em>","").replace("<nobr>","").replace("</nobr>","").replace("<wbr>",""))
- def displayFeed(self):
- if self.pannableFeed:
- self.pannableFeed.destroy()
+ def displayFeed(self, key=None):
+ """
+ Select and display a feed. If feed, title and key are None,
+ reloads the current feed.
+ """
+ if key:
+ try:
+ old_key = self.key
+ except AttributeError:
+ old_key = None
- self.pannableFeed = hildon.PannableArea()
+ if old_key:
+ self.listing.updateUnread(self.key)
+ self.emit("feed-closed", self.key)
- self.pannableFeed.set_property('hscrollbar-policy', gtk.POLICY_NEVER)
+ self.feed = self.listing.getFeed(key)
+ self.feedTitle = self.listing.getFeedTitle(key)
+ self.key = key
- self.feedItems = gtk.ListStore(str, str)
- #self.feedList = gtk.TreeView(self.feedItems)
- self.feedList = hildon.GtkTreeView(gtk.HILDON_UI_MODE_NORMAL)
- self.feedList.set_rules_hint(True)
+ self.set_title(self.feedTitle)
- selection = self.feedList.get_selection()
- selection.set_mode(gtk.SELECTION_NONE)
- #selection.connect("changed", lambda w: True)
-
- self.feedList.set_model(self.feedItems)
- self.feedList.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_HORIZONTAL)
+ selection = self.feedList.get_selection()
+ if selection is not None:
+ selection.set_mode(gtk.SELECTION_NONE)
+ for b in self.archived_article_buttons:
+ if key == "ArchivedArticles":
+ b.show()
+ else:
+ b.hide()
- self.feedList.set_hover_selection(False)
- #self.feedList.set_property('enable-grid-lines', True)
- #self.feedList.set_property('hildon-mode', 1)
- #self.pannableFeed.connect("motion-notify-event", lambda w,ev: True)
-
- #self.feedList.connect('row-activated', self.on_feedList_row_activated)
-
- vbox= gtk.VBox(False, 10)
- vbox.pack_start(self.feedList)
-
- self.pannableFeed.add_with_viewport(vbox)
-
- self.markup_renderer = gtk.CellRendererText()
- self.markup_renderer.set_property('wrap-mode', pango.WRAP_WORD_CHAR)
- self.markup_renderer.set_property('background', bg_color) #"#333333")
- (width, height) = self.get_size()
- self.markup_renderer.set_property('wrap-width', width-20)
- self.markup_renderer.set_property('ypad', 8)
- self.markup_renderer.set_property('xpad', 5)
- markup_column = gtk.TreeViewColumn('', self.markup_renderer, \
- markup=FEED_COLUMN_MARKUP)
- self.feedList.append_column(markup_column)
-
#self.pannableFeed.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
hideReadArticles = self.config.getHideReadArticles()
if hideReadArticles:
else:
articles = self.feed.getIds()
- hasArticle = False
self.articles[:] = []
+
+ self.feedItems.clear()
for id in articles:
- isRead = False
try:
isRead = self.feed.isEntryRead(id)
- except:
- pass
+ except Exception:
+ isRead = False
if not ( isRead and hideReadArticles ):
title = self.fix_title(self.feed.getTitle(id))
self.articles.append(id)
markup = ENTRY_TEMPLATE_UNREAD % (self.config.getFontSize(), title)
self.feedItems.append((markup, id))
- hasArticle = True
- if hasArticle:
- self.feedList.connect('hildon-row-tapped', self.on_feedList_row_activated)
- else:
+ if not articles:
+ # No articles.
markup = ENTRY_TEMPLATE % (self.config.getFontSize(), "No Articles To Display")
self.feedItems.append((markup, ""))
- self.main_vbox.pack_start(self.pannableFeed)
- self.show_all()
+ self.show()
def clear(self):
self.pannableFeed.destroy()
#self.remove(self.pannableFeed)
def on_feedList_row_activated(self, treeview, path): #, column):
+ if not self.articles:
+ # There are not actually any articles. Ignore.
+ return False
+
selection = self.feedList.get_selection()
selection.set_mode(gtk.SELECTION_SINGLE)
self.feedList.get_selection().select_path(path)
self.downloadDialog.connect("download-done", self.onDownloadDone)
self.main_vbox.pack_end(self.downloadDialog,
expand=False, fill=False)
- self.show_all()
-
+ self.downloadDialog.show()
+
def onDownloadDone(self, widget, feed):
- if feed == self.feed:
+ if feed is not None and hasattr(self, 'feed') and feed == self.feed:
self.feed = self.listing.getFeed(self.key)
self.displayFeed()
self.listing = Listing(self.config, CONFIGDIR)
self.downloadDialog = False
-
- menu = hildon.AppMenu()
- # Create a button and add it to the menu
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Update feeds")
- button.connect("clicked", self.button_update_clicked, "All")
- menu.append(button)
-
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Mark all as read")
- button.connect("clicked", self.button_markAll)
- menu.append(button)
-
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Add new feed")
- button.connect("clicked", lambda b: self.addFeed())
- menu.append(button)
-
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Manage subscriptions")
- button.connect("clicked", self.button_organize_clicked)
- menu.append(button)
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Settings")
- button.connect("clicked", self.button_preferences_clicked)
- menu.append(button)
-
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("About")
- button.connect("clicked", self.button_about_clicked)
- menu.append(button)
-
- self.window.set_app_menu(menu)
- menu.show_all()
-
- #self.feedWindow = hildon.StackableWindow()
- #self.articleWindow = hildon.StackableWindow()
self.introLabel.destroy()
self.pannableListing = hildon.PannableArea()
+
+ # The main area is a view consisting of an icon and two
+ # strings. The view is bound to the Listing's database via a
+ # TreeStore.
+
self.feedItems = gtk.TreeStore(gtk.gdk.Pixbuf, str, str)
self.feedList = gtk.TreeView(self.feedItems)
self.feedList.connect('row-activated', self.on_feedList_row_activated)
- #self.feedList.set_enable_tree_lines(True)
- #self.feedList.set_show_expanders(True)
+
self.pannableListing.add(self.feedList)
icon_renderer = gtk.CellRendererPixbuf()
self.mainVbox.show_all()
self.displayListing()
- self.autoupdate = False
- self.checkAutoUpdate()
hildon.hildon_gtk_window_set_progress_indicator(self.window, 0)
gobject.idle_add(self.late_init)
-
+
def update_progress(self, percent_complete,
completed, in_progress, queued,
bytes_downloaded, bytes_updated, bytes_per_second,
self.downloadDialog = DownloadBar(self.window)
self.downloadDialog.connect("download-done", self.onDownloadDone)
self.mainVbox.pack_end(self.downloadDialog, expand=False, fill=False)
- self.mainVbox.show_all()
+ self.downloadDialog.show()
if self.__dict__.get ('disp', None):
self.disp.show_download_bar ()
self.displayListing()
def late_init(self):
+ # Finish building the GUI.
+ menu = hildon.AppMenu()
+ # Create a button and add it to the menu
+ button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+ button.set_label("Update feeds")
+ button.connect("clicked", self.button_update_clicked, "All")
+ menu.append(button)
+
+ button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+ button.set_label("Mark all as read")
+ button.connect("clicked", self.button_markAll)
+ menu.append(button)
+
+ button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+ button.set_label("Add new feed")
+ button.connect("clicked", lambda b: self.addFeed())
+ menu.append(button)
+
+ button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+ button.set_label("Manage subscriptions")
+ button.connect("clicked", self.button_organize_clicked)
+ menu.append(button)
+
+ button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+ button.set_label("Settings")
+ button.connect("clicked", self.button_preferences_clicked)
+ menu.append(button)
+
+ button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
+ button.set_label("About")
+ button.connect("clicked", self.button_about_clicked)
+ menu.append(button)
+
+ self.window.set_app_menu(menu)
+ menu.show_all()
+
+ # Initialize the DBus interface.
self.dbusHandler = ServerObject(self)
bus = dbus.SessionBus()
bus.add_signal_receiver(handler_function=self.update_progress,
dbus_interface='org.marcoz.feedingit',
path='/org/marcoz/feedingit/update')
+ # Check whether auto-update is enabled.
+ self.autoupdate = False
+ #self.checkAutoUpdate()
+
+ gobject.idle_add(self.build_feed_display)
+ gobject.idle_add(self.check_for_woodchuck)
+
+ def build_feed_display(self):
+ if not hasattr(self, 'disp'):
+ self.disp = DisplayFeed(self.listing, self.config)
+ self.disp.connect("feed-closed", self.onFeedClosed)
+
+ def check_for_woodchuck(self):
+ if self.config.getAskedAboutWoodchuck():
+ return
+
+ try:
+ import woodchuck
+ # It is already installed successfully.
+ self.config.setAskedAboutWoodchuck(True)
+ return
+ except ImportError:
+ pass
+
+ note = hildon.hildon_note_new_confirmation(
+ self.window,
+ "\nFeedingIt can use Woodchuck, a network transfer "
+ + "daemon, to schedule transfers more intelligently.\n"
+ + "You can also use the FeedingIt widget for time-based\n"
+ + "updates.\n\n"
+ + "Install Woodchuck?\n")
+ note.set_button_texts("Install", "Cancel")
+ note.add_button("Learn More", 42)
+
+ while True:
+ response = gtk.Dialog.run(note)
+ if response == 42:
+ open_in_browser("http://hssl.cs.jhu.edu/~neal/woodchuck")
+ continue
+
+ break
+
+ note.destroy()
+
+ if response == gtk.RESPONSE_OK:
+ open_in_browser("http://maemo.org/downloads/product/raw/Maemo5/murmeltier?get_installfile")
+ self.config.setAskedAboutWoodchuck(True)
+
def button_markAll(self, button):
for key in self.listing.getListOfFeeds():
feed = self.listing.getFeed(key)
unreadItems = self.listing.getFeedNumberOfUnreadItems(key)
title = xml.sax.saxutils.escape(self.listing.getFeedTitle(key))
updateTime = self.listing.getFeedUpdateTime(key)
- if updateTime == 0:
- updateTime = "Never"
subtitle = '%s / %d unread items' % (updateTime, unreadItems)
if unreadItems:
markup = FEED_TEMPLATE_UNREAD % (title, subtitle)
def openFeed(self, key):
if key != None:
- self.disp = DisplayFeed(
- self.listing, self.listing.getFeed(key),
- self.listing.getFeedTitle(key), key,
- self.config)
- self.disp.connect("feed-closed", self.onFeedClosed)
+ self.build_feed_display()
+ self.disp.displayFeed(key)
def openArticle(self, key, id):
if key != None:
self.disp.button_clicked(None, id)
def onFeedClosed(self, object, key):
- self.displayListing()
+ gobject.idle_add(self.displayListing)
def quit(self, *args):
self.window.hide()