# ============================================================================
__appname__ = 'FeedingIt'
__author__ = 'Yves Marcoz'
-__version__ = '0.6.2'
+__version__ = '0.7.0'
__description__ = 'A simple RSS Reader for Maemo 5'
# ============================================================================
import style
MARKUP_TEMPLATE= '<span font_desc="%s" foreground="%s">%%s</span>'
-MARKUP_TEMPLATE_ENTRY = '<span font_desc="%s %%s" foreground="%s">%%s</span>'
+MARKUP_TEMPLATE_ENTRY_UNREAD = '<span font_desc="%s %%s" foreground="%s">%%s</span>'
+MARKUP_TEMPLATE_ENTRY = '<span font_desc="%s italic %%s" foreground="%s">%%s</span>'
# Build the markup template for the Maemo 5 text style
head_font = style.get_font_desc('SystemFont')
active_head = MARKUP_TEMPLATE % (head_font.to_string(), active_color.to_string())
active_sub = MARKUP_TEMPLATE % (sub_font.to_string(), active_color.to_string())
-entry_active_head = MARKUP_TEMPLATE_ENTRY % (head_font.get_family(), active_color.to_string())
-entry_active_sub = MARKUP_TEMPLATE_ENTRY % (sub_font.get_family(), active_color.to_string())
+entry_active_head = MARKUP_TEMPLATE_ENTRY_UNREAD % (head_font.get_family(), active_color.to_string())
+entry_active_sub = MARKUP_TEMPLATE_ENTRY_UNREAD % (sub_font.get_family(), active_color.to_string())
FEED_TEMPLATE = '\n'.join((head, normal_sub))
FEED_TEMPLATE_UNREAD = '\n'.join((head, active_sub))
return sub("&#?\w+;", fixup, text)
-class AddWidgetWizard(hildon.WizardDialog):
-
- def __init__(self, parent, urlIn, titleIn=None):
- # Create a Notebook
- self.notebook = gtk.Notebook()
+class AddWidgetWizard(gtk.Dialog):
+ def __init__(self, parent, urlIn, titleIn=None, isEdit=False):
+ gtk.Dialog.__init__(self)
+ self.set_transient_for(parent)
+
+ if isEdit:
+ self.set_title('Edit RSS feed')
+ else:
+ self.set_title('Add new RSS feed')
+
+ if isEdit:
+ self.btn_add = self.add_button('Save', 2)
+ else:
+ self.btn_add = self.add_button('Add', 2)
+
+ self.set_default_response(2)
self.nameEntry = hildon.Entry(gtk.HILDON_SIZE_AUTO)
- self.nameEntry.set_placeholder("Enter Feed Name")
- vbox = gtk.VBox(False,10)
- label = gtk.Label("Enter Feed Name:")
- vbox.pack_start(label)
- vbox.pack_start(self.nameEntry)
+ self.nameEntry.set_placeholder('Feed name')
if not titleIn == None:
self.nameEntry.set_text(titleIn)
- self.notebook.append_page(vbox, None)
-
+ self.nameEntry.select_region(-1, -1)
+
self.urlEntry = hildon.Entry(gtk.HILDON_SIZE_AUTO)
- self.urlEntry.set_placeholder("Enter a URL")
+ self.urlEntry.set_placeholder('Feed URL')
self.urlEntry.set_text(urlIn)
- self.urlEntry.select_region(0,-1)
-
- vbox = gtk.VBox(False,10)
- label = gtk.Label("Enter Feed URL:")
- vbox.pack_start(label)
- vbox.pack_start(self.urlEntry)
- self.notebook.append_page(vbox, None)
+ self.urlEntry.select_region(-1, -1)
+ self.urlEntry.set_activates_default(True)
+
+ self.table = gtk.Table(2, 2, False)
+ self.table.set_col_spacings(5)
+ label = gtk.Label('Name:')
+ label.set_alignment(1., .5)
+ self.table.attach(label, 0, 1, 0, 1, gtk.FILL)
+ self.table.attach(self.nameEntry, 1, 2, 0, 1)
+ label = gtk.Label('URL:')
+ label.set_alignment(1., .5)
+ self.table.attach(label, 0, 1, 1, 2, gtk.FILL)
+ self.table.attach(self.urlEntry, 1, 2, 1, 2)
+ self.vbox.pack_start(self.table)
- labelEnd = gtk.Label("Success")
-
- self.notebook.append_page(labelEnd, None)
-
- hildon.WizardDialog.__init__(self, parent, "Add Feed", self.notebook)
-
- # Set a handler for "switch-page" signal
- #self.notebook.connect("switch_page", self.on_page_switch, self)
-
- # Set a function to decide if user can go to next page
- self.set_forward_page_func(self.some_page_func)
-
self.show_all()
-
+
def getData(self):
return (self.nameEntry.get_text(), self.urlEntry.get_text())
-
- def on_page_switch(self, notebook, page, num, dialog):
- return True
-
+
def some_page_func(self, nb, current, userdata):
# Validate data for 1st page
if current == 0:
def buttonDelete(self, button):
key = self.getSelectedItem()
- if not key == None:
+
+ message = 'Really remove this feed and its entries?'
+ dlg = hildon.hildon_note_new_confirmation(self, message)
+ response = dlg.run()
+ dlg.destroy()
+ if response == gtk.RESPONSE_OK:
self.listing.removeFeed(key)
- self.refreshList()
+ self.refreshList()
def buttonEdit(self, button):
key = self.getSelectedItem()
- if not key == None:
- wizard = AddWidgetWizard(self, self.listing.getFeedUrl(key), self.listing.getFeedTitle(key))
+
+ if key == 'ArchivedArticles':
+ message = 'Cannot edit the archived articles feed.'
+ hildon.hildon_banner_show_information(self, '', message)
+ return
+
+ if key is not None:
+ wizard = AddWidgetWizard(self, self.listing.getFeedUrl(key), self.listing.getFeedTitle(key), True)
ret = wizard.run()
if ret == 2:
(title, url) = wizard.getData()
if (not title == '') and (not url == ''):
self.listing.editFeed(key, title, url)
+ self.refreshList()
wizard.destroy()
- self.refreshList()
def buttonDone(self, *args):
self.destroy()
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://" + contentLink)
+ 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.connect("motion-notify-event", lambda w,ev: True)
self.view.connect('load-started', self.load_started)
self.view.connect('load-finished', self.load_finished)
- #else:
- #self.view.load_html_string(self.text, contentLink) # "text/html", "utf-8", self.link)
self.view.set_zoom_level(float(config.getArtFontSize())/10.)
- #else:
- # if not key == "ArchivedArticles":
- # Do not download images if the feed is "Archived Articles"
- # self.document.connect("request-url", self._signal_request_url)
-
- # self.document.clear()
- # self.document.open_stream("text/html")
- # self.document.write_stream(self.text)
- # self.document.close_stream()
menu = hildon.AppMenu()
# Create a button and add it to the menu
button = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
button.set_label("Open in browser")
- button.connect("clicked", self._signal_link_clicked, self.feed.getExternalLink(self.id))
+ button.connect("clicked", self.open_in_browser)
menu.append(button)
if key == "ArchivedArticles":
self.set_app_menu(menu)
menu.show_all()
- #self.event_box = gtk.EventBox()
- #self.event_box.add(self.pannable_article)
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)
- #self.timeout_handler_id = gobject.timeout_add(300, self.reloadArticle)
+
+ #def navigation_policy_decision(self, wv, fr, req, action, decision):
+ def navigation_requested(self, wv, fr, req):
+ if self.config.getOpenInExternalBrowser():
+ self.open_in_browser(None, req.get_uri())
+ return True
+ else:
+ return False
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()
+ if self.loadedArticle:
+ self.currentUrl = frame.get_uri()
+ else:
+ self.loadedArticle = True
def button_pressed(self, window, event):
#print event.x, event.y
self.emit("article-previous", self.id)
elif (x<-15):
self.emit("article-next", self.id)
- #print x, y
- #print "Released"
-
- #def gesture(self, widget, direction, startx, starty):
- # if (direction == 3):
- # self.emit("article-next", self.index)
- # if (direction == 2):
- # self.emit("article-previous", self.index)
- #print startx, starty
- #self.timeout_handler_id = gobject.timeout_add(200, self.destroyWindow)
def destroyWindow(self, *args):
self.disconnect(self.destroyId)
def remove_archive_button(self, *widget):
self.set_for_removal = True
-
- #def reloadArticle(self, *widget):
- # if threading.activeCount() > 1:
- # Image thread are still running, come back in a bit
- # return True
- # else:
- # for (stream, imageThread) in self.images:
- # imageThread.join()
- # stream.write(imageThread.data)
- # stream.close()
- # return False
- # self.show_all()
-
- def _signal_link_clicked(self, object, link):
+
+ def open_in_browser(self, object, link=None):
import dbus
bus = dbus.SessionBus()
proxy = bus.get_object("com.nokia.osso_browser", "/com/nokia/osso_browser/request")
iface = dbus.Interface(proxy, 'com.nokia.osso_browser')
- iface.open_new_window(link)
-
- #def _signal_request_url(self, object, url, stream):
- #print url
- # self.imageDownloader.queueImage(url, stream)
- #imageThread = GetImage(url)
- #imageThread.start()
- #self.images.append((stream, imageThread))
-
+ if link == None:
+ iface.open_new_window(self.currentUrl)
+ else:
+ iface.open_new_window(link)
class DisplayFeed(hildon.StackableWindow):
def __init__(self, listing, feed, title, key, config, updateDbusHandler):
self.feedTitle = title
self.set_title(title)
self.key=key
+ self.current = list()
self.config = config
self.updateDbusHandler = updateDbusHandler
# Fix up the column width for wrapping the text when the window is
# resized (i.e. orientation changed)
- self.markup_renderer.set_property('wrap-width', event.width-10)
+ self.markup_renderer.set_property('wrap-width', event.width-20)
+ it = self.feedItems.get_iter_first()
+ while it is not None:
+ markup = self.feedItems.get_value(it, FEED_COLUMN_MARKUP)
+ self.feedItems.set_value(it, FEED_COLUMN_MARKUP, markup)
+ it = self.feedItems.iter_next(it)
def destroyWindow(self, *args):
#self.feed.saveUnread(CONFIGDIR)
self.markup_renderer = gtk.CellRendererText()
self.markup_renderer.set_property('wrap-mode', pango.WRAP_WORD_CHAR)
- self.markup_renderer.set_property('wrap-width', 780)
+ self.markup_renderer.set_property('background', "#333333")
+ (width, height) = self.get_size()
+ self.markup_renderer.set_property('wrap-width', width-20)
self.markup_renderer.set_property('ypad', 5)
self.markup_renderer.set_property('xpad', 5)
markup_column = gtk.TreeViewColumn('', self.markup_renderer, \
#self.pannableFeed.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
hideReadArticles = self.config.getHideReadArticles()
hasArticle = False
+ self.current = list()
for id in self.feed.getIds():
isRead = False
try:
except:
pass
if not ( isRead and hideReadArticles ):
- #if not ( self.feed.isEntryRead(id) and self.config.getHideReadArticles() ):
- #title = self.feed.getTitle(id)
title = self.fix_title(self.feed.getTitle(id))
-
- #if self.feed.isEntryRead(id):
+ self.current.append(id)
if isRead:
markup = ENTRY_TEMPLATE % (self.config.getFontSize(), title)
else:
def nextArticle(self, object, index):
self.mark_item_read(index)
id = self.feed.getNextId(index)
- if self.config.getHideReadArticles():
- isRead = False
- try:
- isRead = self.feed.isEntryRead(id)
- except:
- pass
- while isRead and id != index:
- id = self.feed.getNextId(id)
- isRead = False
- try:
- isRead = self.feed.isEntryRead(id)
- except:
- pass
+ 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)
- if self.config.getHideReadArticles():
- isRead = False
- try:
- isRead = self.feed.isEntryRead(id)
- except:
- pass
- while isRead and id != index:
- id = self.feed.getPreviousId(id)
- isRead = False
- try:
- isRead = self.feed.isEntryRead(id)
- except:
- pass
+ 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 createWindow(self):
self.app_lock = get_lock("app_lock")
if self.app_lock == None:
+ try:
+ self.stopButton.set_sensitive(True)
+ except:
+ self.stopButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ self.stopButton.set_text("Stop update","")
+ self.stopButton.connect("clicked", self.stop_running_update)
+ self.mainVbox.pack_end(self.stopButton, expand=False, fill=False)
+ self.window.show_all()
self.introLabel.set_label("Update in progress, please wait.")
gobject.timeout_add_seconds(3, self.createWindow)
return False
+ try:
+ self.stopButton.destroy()
+ except:
+ pass
self.listing = Listing(CONFIGDIR)
self.downloadDialog = False
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)
hildon.hildon_gtk_window_set_progress_indicator(self.window, 0)
gobject.idle_add(self.enableDbus)
+ def stop_running_update(self, button):
+ self.stopButton.set_sensitive(False)
+ import dbus
+ bus=dbus.SessionBus()
+ remote_object = bus.get_object("org.marcoz.feedingit", # Connection name
+ "/org/marcoz/feedingit/update" # Object's path
+ )
+ iface = dbus.Interface(remote_object, 'org.marcoz.feedingit')
+ iface.StopUpdate()
+
def enableDbus(self):
self.dbusHandler = ServerObject(self)
self.updateDbusHandler = UpdateServerObject(self)
self.feed_lock
except:
# If feed_lock doesn't exist, we can open the feed, else we do nothing
- self.feed_lock = get_lock(key)
- self.disp = DisplayFeed(self.listing, self.listing.getFeed(key), \
- self.listing.getFeedTitle(key), key, \
- self.config, self.updateDbusHandler)
- self.disp.connect("feed-closed", self.onFeedClosed)
+ if key != None:
+ self.feed_lock = get_lock(key)
+ self.disp = DisplayFeed(self.listing, self.listing.getFeed(key), \
+ self.listing.getFeedTitle(key), key, \
+ self.config, self.updateDbusHandler)
+ self.disp.connect("feed-closed", self.onFeedClosed)
def onFeedClosed(self, object, key):