class DisplayArticle(hildon.StackableWindow):
- def __init__(self, feed, id, key, config, listing):
+ """
+ A Widget for displaying an article.
+ """
+ def __init__(self, article_id, feed, feed_key, articles, config, listing):
+ """
+ article_id - The identifier of the article to load.
+
+ feed - The feed object containing the article (an
+ rss_sqlite:Feed object).
+
+ feed_key - The feed's identifier.
+
+ articles - A list of articles from the feed to display.
+ Needed for selecting the next/previous article (article_next).
+
+ config - A configuration object (config:Config).
+
+ listing - The listing object (rss_sqlite:Listing) that
+ contains the feed and article.
+ """
hildon.StackableWindow.__init__(self)
- #self.imageDownloader = ImageDownloader()
+
+ self.article_id = None
self.feed = feed
- self.listing=listing
- self.key = key
- self.id = id
- #self.set_title(feed.getTitle(id))
- self.set_title(self.listing.getFeedTitle(key))
+ self.feed_key = feed_key
+ self.articles = articles
self.config = config
- self.set_for_removal = False
-
+ self.listing = listing
+
+ self.set_title(self.listing.getFeedTitle(feed_key))
+
# Init the article display
- #if self.config.getWebkitSupport():
self.view = WebView()
- #self.view.set_editable(False)
- #else:
- # import gtkhtml2
- # self.view = gtkhtml2.View()
- # self.document = gtkhtml2.Document()
- # self.view.set_document(self.document)
- # self.document.connect("link_clicked", self._signal_link_clicked)
- self.pannable_article = hildon.PannableArea()
- self.pannable_article.add(self.view)
- #self.pannable_article.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
- #self.gestureId = self.pannable_article.connect('horizontal-movement', self.gesture)
-
- #if self.config.getWebkitSupport():
- contentLink = self.feed.getContentLink(self.id)
- self.feed.setEntryRead(self.id)
- #if key=="ArchivedArticles":
- self.loadedArticle = False
- if contentLink.startswith("/home/user/"):
- self.view.open("file://%s" % contentLink)
- self.currentUrl = self.feed.getExternalLink(self.id)
- else:
- self.view.load_html_string('This article has not been downloaded yet. Click <a href="%s">here</a> to view online.' % contentLink, contentLink)
- self.currentUrl = "%s" % contentLink
+ self.view.set_zoom_level(float(config.getArtFontSize())/10.)
self.view.connect("motion-notify-event", lambda w,ev: True)
self.view.connect('load-started', self.load_started)
self.view.connect('load-finished', self.load_finished)
+ self.view.connect('navigation-requested', self.navigation_requested)
+ self.view.connect("button_press_event", self.button_pressed)
+ self.gestureId = self.view.connect(
+ "button_release_event", self.button_released)
- self.view.set_zoom_level(float(config.getArtFontSize())/10.)
-
+ self.pannable_article = hildon.PannableArea()
+ self.pannable_article.add(self.view)
+
+ self.add(self.pannable_article)
+
+ self.pannable_article.show_all()
+
+ # Create the menu.
menu = hildon.AppMenu()
- # Create a button and add it to the menu
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Allow horizontal scrolling")
- button.connect("clicked", self.horiz_scrolling_button)
- menu.append(button)
-
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Open in browser")
- button.connect("clicked", self.open_in_browser)
- menu.append(button)
-
- if key == "ArchivedArticles":
+
+ def menu_button(label, callback):
button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Remove from archived articles")
- button.connect("clicked", self.remove_archive_button)
+ button.set_label(label)
+ button.connect("clicked", callback)
+ menu.append(button)
+
+ menu_button("Allow horizontal scrolling", self.horiz_scrolling_button)
+ menu_button("Open in browser", self.open_in_browser)
+ if feed_key == "ArchivedArticles":
+ menu_button(
+ "Remove from archived articles", self.remove_archive_button)
else:
- button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
- button.set_label("Add to archived articles")
- button.connect("clicked", self.archive_button)
- menu.append(button)
+ menu_button("Add to archived articles", self.archive_button)
self.set_app_menu(menu)
menu.show_all()
- self.add(self.pannable_article)
-
- self.pannable_article.show_all()
-
self.destroyId = self.connect("destroy", self.destroyWindow)
-
- #self.view.connect('navigation-policy-decision-requested', self.navigation_policy_decision)
- ## Still using an old version of WebKit, so using navigation-requested signal
- self.view.connect('navigation-requested', self.navigation_requested)
-
- self.view.connect("button_press_event", self.button_pressed)
- self.gestureId = self.view.connect("button_release_event", self.button_released)
- #def navigation_policy_decision(self, wv, fr, req, action, decision):
+ self.article_open(article_id)
+
+ def article_open(self, article_id):
+ """
+ Load the article with the specified id.
+ """
+ # If an article was open, close it.
+ if self.article_id is not None:
+ self.article_closed()
+
+ self.article_id = article_id
+ self.set_for_removal = False
+ self.loadedArticle = False
+ self.initial_article_load = True
+
+ contentLink = self.feed.getContentLink(self.article_id)
+ if contentLink.startswith("/home/user/"):
+ self.view.open("file://%s" % contentLink)
+ self.currentUrl = self.feed.getExternalLink(self.article_id)
+ else:
+ self.view.load_html_string('This article has not been downloaded yet. Click <a href="%s">here</a> to view online.' % contentLink, contentLink)
+ self.currentUrl = str(contentLink)
+
+ self.feed.setEntryRead(self.article_id)
+
+ def article_closed(self):
+ """
+ The user has navigated away from the article. Execute any
+ pending actions.
+ """
+ if self.set_for_removal:
+ self.emit("article-deleted", self.article_id)
+ else:
+ self.emit("article-closed", self.article_id)
+
+
def navigation_requested(self, wv, fr, req):
+ """
+ http://webkitgtk.org/reference/webkitgtk-webkitwebview.html#WebKitWebView-navigation-requested
+
+ wv - a WebKitWebView
+ fr - a WebKitWebFrame
+ req - WebKitNetworkRequest
+ """
+ if self.initial_article_load:
+ # Always initially load an article in the internal
+ # browser.
+ self.initial_article_load = False
+ return False
+
+ # When following a link, only use the internal browser if so
+ # configured. Otherwise, launch an external browser.
if self.config.getOpenInExternalBrowser():
self.open_in_browser(None, req.get_uri())
return True
def load_started(self, *widget):
hildon.hildon_gtk_window_set_progress_indicator(self, 1)
-
+
def load_finished(self, *widget):
hildon.hildon_gtk_window_set_progress_indicator(self, 0)
frame = self.view.get_main_frame()
self.loadedArticle = True
def button_pressed(self, window, event):
- #print event.x, event.y
+ """
+ The user pressed a "mouse button" (in our case, this means the
+ user likely started to drag with the finger).
+
+ We are only interested in whether the user performs a drag.
+ We record the starting position and when the user "releases
+ the button," we see how far the mouse moved.
+ """
self.coords = (event.x, event.y)
def button_released(self, window, event):
if (2*abs(y) < abs(x)):
if (x > 15):
- self.emit("article-previous", self.id)
+ self.article_next(forward=False)
elif (x<-15):
- self.emit("article-next", self.id)
+ self.article_next(forward=True)
+
+ # We handled the event. Don't propagate it further.
+ return True
+
+ def article_next(self, forward=True):
+ """
+ Advance to the next (or, if forward is false, the previous)
+ article.
+ """
+ first_id = None
+ id = self.article_id
+ i = 0
+ while True:
+ i += 1
+ id = self.feed.getNextId(id, forward)
+ if id == first_id:
+ # We looped.
+ break
+
+ if first_id is None:
+ first_id = id
+
+ if id in self.articles:
+ self.article_open(id)
+ break
def destroyWindow(self, *args):
+ self.article_closed()
self.disconnect(self.destroyId)
- if self.set_for_removal:
- self.emit("article-deleted", self.id)
- else:
- self.emit("article-closed", self.id)
- #self.imageDownloader.stopAll()
self.destroy()
def horiz_scrolling_button(self, *widget):
def archive_button(self, *widget):
# Call the listing.addArchivedArticle
- self.listing.addArchivedArticle(self.key, self.id)
+ self.listing.addArchivedArticle(self.feed_key, self.article_id)
def remove_archive_button(self, *widget):
self.set_for_removal = True
def open_in_browser(self, object, link=None):
+ """
+ Open the specified link using the system's browser. If not
+ link is specified, reopen the current page using the system's
+ browser.
+ """
if link == None:
link = self.currentUrl
self.feedTitle = title
self.set_title(title)
self.key=key
- self.current = list()
+ # Articles to show.
+ #
+ # If hide read articles is set, this is set to the set of
+ # unread articles at the time that feed is loaded. The last
+ # bit is important: when the user selects the next article,
+ # but then decides to move back, previous should select the
+ # just read article.
+ self.articles = list()
self.config = config
self.downloadDialog = False
articles = self.feed.getIds()
hasArticle = False
- self.current = list()
+ self.articles[:] = []
for id in articles:
isRead = False
try:
pass
if not ( isRead and hideReadArticles ):
title = self.fix_title(self.feed.getTitle(id))
- self.current.append(id)
+ self.articles.append(id)
if isRead:
markup = ENTRY_TEMPLATE % (self.config.getFontSize(), title)
else:
#return True
def button_clicked(self, button, index, previous=False, next=False):
- #newDisp = DisplayArticle(self.feedTitle, self.feed.getArticle(index), self.feed.getLink(index), index, self.key, self.listing, self.config)
- newDisp = DisplayArticle(self.feed, index, self.key, self.config, self.listing)
+ newDisp = DisplayArticle(index, self.feed, self.key, self.articles, self.config, self.listing)
stack = hildon.WindowStack.get_default()
if previous:
tmp = stack.peek()
if self.key == "ArchivedArticles":
self.ids.append(self.disp.connect("article-deleted", self.onArticleDeleted))
self.ids.append(self.disp.connect("article-closed", self.onArticleClosed))
- self.ids.append(self.disp.connect("article-next", self.nextArticle))
- self.ids.append(self.disp.connect("article-previous", self.previousArticle))
def buttonPurgeArticles(self, *widget):
self.clear()
break
it = self.feedItems.iter_next(it)
- def nextArticle(self, object, index):
- self.mark_item_read(index)
- id = self.feed.getNextId(index)
- while id not in self.current and id != index:
- id = self.feed.getNextId(id)
- if id != index:
- self.button_clicked(object, id, next=True)
-
- def previousArticle(self, object, index):
- self.mark_item_read(index)
- id = self.feed.getPreviousId(index)
- while id not in self.current and id != index:
- id = self.feed.getPreviousId(id)
- if id != index:
- self.button_clicked(object, id, previous=True)
-
def onArticleClosed(self, object, index):
selection = self.feedList.get_selection()
selection.set_mode(gtk.SELECTION_NONE)
gobject.signal_new("feed-closed", DisplayFeed, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("article-closed", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("article-deleted", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
- gobject.signal_new("article-next", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
- gobject.signal_new("article-previous", DisplayArticle, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.signal_new("download-done", DownloadBar, gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
gobject.threads_init()
if not isdir(CONFIGDIR):