# ============================================================================
#import sys
+import sqlite3
+from re import sub
+from htmlentitydefs import name2codepoint
+
import gtk, pickle, gobject, dbus
import hildondesktop, hildon
#from rss import Listing
from os import environ, remove
bus = dbus.bus.BusConnection(environ["DBUS_SESSION_BUS_ADDRESS"])
from os.path import isfile
+from cgi import escape
-color_style = gtk.rc_get_style_by_paths(gtk.settings_get_default() , 'GtkButton', 'osso-logical-colors', gtk.Button)
+settings = gtk.settings_get_default()
+color_style = gtk.rc_get_style_by_paths( settings, 'GtkButton', 'osso-logical-colors', gtk.Button)
active_color = color_style.lookup_color('ActiveTextColor')
default_color = color_style.lookup_color('DefaultTextColor')
+font_desc = gtk.rc_get_style_by_paths(settings, 'HomeSystemFont', None, None).font_desc
+
del color_style
CONFIGDIR="/home/user/.feedingit/"
#libc = ctypes.CDLL('libc.so.6')
#libc.printf('Hello world!')
+def get_font_desc(logicalfontname):
+ settings = gtk.settings_get_default()
+ font_style = gtk.rc_get_style_by_paths(settings, logicalfontname, \
+ None, None)
+ font_desc = font_style.font_desc
+ return font_desc
+
+def unescape(text):
+ def fixup(m):
+ text = m.group(0)
+ if text[:2] == "&#":
+ # character reference
+ try:
+ if text[:3] == "&#x":
+ return unichr(int(text[3:-1], 16))
+ else:
+ return unichr(int(text[2:-1]))
+ except ValueError:
+ pass
+ else:
+ # named entity
+ try:
+ text = unichr(name2codepoint[text[1:-1]])
+ except KeyError:
+ pass
+ return text # leave as is
+ return sub("&#?\w+;", fixup, text)
+
+def fix_title(title):
+ return escape(unescape(title).replace("<em>","").replace("</em>","").replace("<nobr>","").replace("</nobr>","").replace("<wbr>",""))
+
+
class FeedingItHomePlugin(hildondesktop.HomePluginItem):
def __init__(self):
__gsignals__ = {
self.connect("show-settings", self.show_settings)
self.feed_list = {}
self.total = 0
+ self.status = 0 # 0=Showing feeds, 1=showing articles
+ self.updateStatus = 0 # 0=Not updating, 1=Update in progress
+ self.pageStatus = 0
if isfile(SOURCE):
file = open(SOURCE)
self.autoupdateId = int(file.read())
vbox = gtk.VBox(False, 0)
+ ## Prepare the main HBox
+ self.hbox1 = gtk.HBox(False, 0)
#self.button = gtk.Button()
- self.button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
- self.button.set_text("FeedingIt","")
- self.button.set_sensitive(False)
- self.label1 = self.button.child.child.get_children()[0].get_children()[0]
- self.label2 = self.button.child.child.get_children()[0].get_children()[1]
- self.label1.modify_fg(gtk.STATE_INSENSITIVE, default_color)
- self.label2.modify_fg(gtk.STATE_INSENSITIVE, active_color)
+ self.buttonApp = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ #self.buttonApp.set_text("FeedingIt","")
+ #self.button.set_sensitive(False)
+ #self.label1 = self.buttonApp.child.child.get_children()[0].get_children()[0]
+ #self.label2 = self.button.child.child.get_children()[0].get_children()[1]
+ #self.label1.modify_fg(gtk.STATE_INSENSITIVE, default_color)
+ #self.label1.modify_font(font_desc)
+ #self.label2.modify_fg(gtk.STATE_INSENSITIVE, active_color)
icon_theme = gtk.icon_theme_get_default()
- pixbuf = icon_theme.load_icon("feedingit", 48, gtk.ICON_LOOKUP_USE_BUILTIN )
+ pixbuf = icon_theme.load_icon("feedingit", 20, gtk.ICON_LOOKUP_USE_BUILTIN )
image = gtk.Image()
image.set_from_pixbuf(pixbuf)
- self.button.set_image(image)
- self.button.set_image_position(gtk.POS_LEFT)
-
+ self.buttonApp.set_image(image)
+ self.buttonApp.set_image_position(gtk.POS_RIGHT)
#button = gtk.Button("Update")
- self.button.connect("clicked", self.button_clicked)
+ self.buttonApp.connect("clicked", self.button_clicked)
+
+ self.buttonUpdate = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ self.buttonUpdate.set_image(gtk.image_new_from_icon_name('general_refresh', gtk.ICON_SIZE_BUTTON))
+ self.buttonUpdate.connect("clicked", self.buttonUpdate_clicked)
+
+ self.buttonUp = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ self.buttonUp.set_image(gtk.image_new_from_icon_name('keyboard_move_up', gtk.ICON_SIZE_BUTTON))
+ self.buttonUp.set_sensitive(False)
+ self.buttonUp.connect("clicked", self.buttonUp_clicked)
+
+ self.buttonDown = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ self.buttonDown.set_image(gtk.image_new_from_icon_name('keyboard_move_down', gtk.ICON_SIZE_BUTTON))
+ self.buttonDown.set_sensitive(False)
+ self.buttonDown.connect("clicked", self.buttonDown_clicked)
+
+ self.hbox1.pack_start(self.buttonUpdate, expand=False)
+ self.hbox1.pack_start(self.buttonUp, expand=False)
+ self.hbox1.pack_start(self.buttonDown, expand=False)
+ self.hbox1.pack_start(self.buttonApp, expand=False)
+
#button.show_all()
- vbox.pack_start(self.button, expand=False)
+
#for feed in ["Slashdot", "Engadget", "Cheez"]:
# self.treestore.append([feed, "0"])
self.treeview = gtk.TreeView()
self.update_list()
- self.treeview.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
- self.treeview.append_column(gtk.TreeViewColumn('Unread Items', gtk.CellRendererText(), text = 1))
+ name_renderer = gtk.CellRendererText()
+ name_renderer.set_property("font-desc", font_desc)
+ name_renderer.set_property('background', "#333333")
+ self.unread_renderer = gtk.CellRendererText()
+ self.unread_renderer.set_property("font-desc", font_desc)
+ self.unread_renderer.set_property("xalign", 1.0)
+ self.unread_renderer.set_property('background', "#333333")
+ column_unread = gtk.TreeViewColumn('Unread Items', self.unread_renderer, text = 1)
+ column_unread.set_expand(False)
+ column_name = gtk.TreeViewColumn('Feed Name', name_renderer, text = 0)
+ column_name.set_expand(True)
+ self.treeview.append_column(column_name)
+ self.treeview.append_column(column_unread)
+ #selection = self.treeview.get_selection()
+ #selection.set_mode(gtk.SELECTION_NONE)
#self.treeview.get_selection().set_mode(gtk.SELECTION_NONE)
#hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview, gtk.HILDON_UI_MODE_NORMAL)
vbox.pack_start(self.treeview)
+ vbox.pack_start(self.hbox1, expand=False)
self.add(vbox)
- self.treeview.connect("row-activated", self.row_activated)
+ self.treeview.connect("hildon-row-tapped", self.row_activated)
+ #self.treeview.connect("cursor-changed", self.cursor_changed)
vbox.show_all()
self.setupDbus()
#gobject.timeout_add_seconds(30*60, self.update_list)
except:
import traceback
- file = open("/home/user/.feedingit/feedingit_widget.log", "a")
+ file = open("/home/user/feedingit_widget.log", "a")
traceback.print_exc(file=file)
file.close()
def do_destroy(self):
- file = open("/home/user/.feedingit/feedingit_widget.log", "a")
- file.write("Do_destroy: ")
+ #file = open("/home/user/.feedingit/feedingit_widget.log", "a")
+ #file.write("Do_destroy: ")
if (not self.autoupdateId==False):
gobject.source_remove(self.autoupdateId)
self.autoupdateId=False
- file.write("Destroyed %s\n" %self.autoupdateId)
+ #file.write("Destroyed %s\n" %self.autoupdateId)
remove(SOURCE)
hildondesktop.HomePluginItem.do_destroy(self)
- file.write("End destroy\n")
- file.close()
+ #file.write("End destroy\n")
+ #file.close()
def button_clicked(self, *widget):
- self.button.set_sensitive(False)
- self.label1.modify_fg(gtk.STATE_NORMAL, default_color)
- self.label2.modify_fg(gtk.STATE_NORMAL, active_color)
- self.update_label("Stopping")
+ #self.button.set_sensitive(False)
+ #self.label1.modify_fg(gtk.STATE_NORMAL, default_color)
+ #self.label2.modify_fg(gtk.STATE_NORMAL, active_color)
+ #self.update_label("Stopping")
+ if self.status == 0:
+ remote_object = bus.get_object("org.maemo.feedingit", # Connection name
+ "/org/maemo/feedingit" # Object's path
+ )
+ iface = dbus.Interface(remote_object, 'org.maemo.feedingit')
+ iface.OpenFeed(None)
+ else:
+ self.status = 0
+ self.pageStatus = 0
+ self.buttonUp.set_sensitive(False)
+ self.buttonDown.set_sensitive(False)
+ self.treeview.append_column(gtk.TreeViewColumn('Unread Items', self.unread_renderer, text = 1))
+ self.update_list()
+ #iface.StopUpdate()
+
+ def buttonUpdate_clicked(self, *widget):
remote_object = bus.get_object("org.marcoz.feedingit", # Connection name
- "/org/marcoz/feedingit/update" # Object's path
- )
+ "/org/marcoz/feedingit/update" # Object's path
+ )
iface = dbus.Interface(remote_object, 'org.marcoz.feedingit')
- iface.StopUpdate()
+ if self.updateStatus == 0:
+ iface.UpdateAll()
+ else:
+ iface.StopUpdate()
+
+ def buttonUp_clicked(self, *widget):
+ if self.pageStatus > 0:
+ self.pageStatus -= 1
+ self.show_articles()
+
+ def buttonDown_clicked(self, *widget):
+ self.pageStatus += 1
+ self.show_articles()
- def update_label(self, title, value=None):
- self.button.set_title(title)
+ def update_label(self, value=None):
if value != None:
- self.button.set_value(value)
+ self.buttonApp.set_title(str(value))
else:
- self.button.set_value("")
+ self.buttonApp.set_title("")
- def row_activated(self, treeview, treepath, column):
- (model, iter) = self.treeview.get_selection().get_selected()
- key = model.get_value(iter, 2)
+ #def row_activated(self, treeview, treepath): #, column):
+ # (model, iter) = self.treeview.get_selection().get_selected()
+ # key = model.get_value(iter, 2)
# Create an object that will proxy for a particular remote object.
- remote_object = bus.get_object("org.maemo.feedingit", # Connection name
- "/org/maemo/feedingit" # Object's path
- )
- iface = dbus.Interface(remote_object, 'org.maemo.feedingit')
- iface.OpenFeed(key)
+ # remote_object = bus.get_object("org.maemo.feedingit", # Connection name
+ # "/org/maemo/feedingit" # Object's path
+ # )
+ # iface = dbus.Interface(remote_object, 'org.maemo.feedingit')
+ # iface.OpenFeed(key)
+
+ def show_articles(self):
+ db = sqlite3.connect(CONFIGDIR+self.key+".d/"+self.key+".db")
+ count = db.execute("SELECT count(*) FROM feed WHERE read=0;").fetchone()[0]
+ if count>0:
+ maxPage = count/10
+ if self.pageStatus > maxPage:
+ self.pageStatus = maxPage
+ rows = db.execute("SELECT id, title FROM feed WHERE read=0 ORDER BY date DESC LIMIT 10 OFFSET ?;", (self.pageStatus*10,) )
+ treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
+ for row in rows:
+ title = fix_title(row[1][0:32])
+ id = row[0]
+ treestore.append((title, id))
+ self.treeview.set_model(treestore)
+
+ def row_activated(self, treeview, treepath):
+ if self.status == 0:
+ self.status = 1
+ self.pageStatus = 0
+ (model, iter) = self.treeview.get_selection().get_selected()
+ self.key = model.get_value(iter, 2)
+ treeviewcolumn = self.treeview.get_column(1)
+ self.treeview.remove_column(treeviewcolumn)
+ self.show_articles()
+ self.buttonApp.set_image(gtk.image_new_from_icon_name('general_back', gtk.ICON_SIZE_BUTTON))
+ self.buttonUp.set_sensitive(True)
+ self.buttonDown.set_sensitive(True)
+ else:
+ (model, iter) = self.treeview.get_selection().get_selected()
+ id = model.get_value(iter, 1)
+ # Create an object that will proxy for a particular remote object.
+ remote_object = bus.get_object("org.maemo.feedingit", # Connection name
+ "/org/maemo/feedingit" # Object's path
+ )
+ iface = dbus.Interface(remote_object, 'org.maemo.feedingit')
+ iface.OpenArticle(self.key, id)
+
def update_list(self, *widget):
#listing = Listing(CONFIGDIR)
- treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
-
- if self.feed_list == {}:
- self.load_config()
-
- list = []
- oldtotal = self.total
- self.total = 0
- #for key in listOfFeeds["feedingit-order"]:
- for key in self.feed_list.keys():
- try:
- file = open(CONFIGDIR+key+".d/unread", "r")
- readItems = pickle.load( file )
- file.close()
- countUnread = 0
- for id in readItems.keys():
- if readItems[id]==False:
- countUnread = countUnread + 1
- list.append([self.feed_list[key], countUnread, key])
- self.total += countUnread
- except:
- pass
- list = sorted(list, key=lambda item: item[1], reverse=True)
- for item in list[0:8]:
- treestore.append(item)
- self.treeview.set_model(treestore)
- self.treeview.get_selection().unselect_all()
- if self.total > oldtotal:
- self.update_label("%s Unread" %str(self.total), "%s more articles" %str(self.total-oldtotal))
- else:
- self.update_label("%s Unread" %str(self.total))
+ if self.status == 0:
+ treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
+
+ if self.feed_list == {}:
+ self.load_config()
+
+ if self.feed_list == None:
+ treestore.append(["No feeds added yet", "", None])
+ treestore.append(["Start Application", "", None])
+ #self.update_label("No feeds added yet")
+ self.treeview.set_model(treestore)
+
+ else:
+ list = []
+ oldtotal = self.total
+ self.total = 0
+ #for key in listOfFeeds["feedingit-order"]:
+ db = sqlite3.connect(CONFIGDIR+"feeds.db")
+ for key in self.feed_list.keys():
+ try:
+ countUnread = db.execute("SELECT unread FROM feeds WHERE id=?;", (key,)).fetchone()[0]
+ list.append([self.feed_list[key][0:25], countUnread, key])
+ self.total += countUnread
+ except:
+ pass
+ list = sorted(list, key=lambda item: item[1], reverse=True)
+ count = 0
+ for item in list[0:10]:
+ count += 1
+ treestore.append(item)
+ for i in range(count, 10):
+ treestore.append( ("", "", None) )
+ self.treeview.set_model(treestore)
+ self.buttonApp.set_image(gtk.image_new_from_icon_name('feedingit', gtk.ICON_SIZE_BUTTON))
+ #self.update_label(self.total)
return True
def create_selector(self, choices, setting):
return picker
def show_settings(self, widget):
- file = open(CONFIGDIR+"feeds.pickle")
- listOfFeeds = pickle.load(file)
- file.close()
- dialog = gtk.Dialog("Choose feeds to display", None, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
-
- self.pannableArea = hildon.PannableArea()
-
- #self.treestore_settings = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
- self.treeview_settings = gtk.TreeView()
-
- self.treeview_settings.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
- hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview_settings, gtk.HILDON_UI_MODE_EDIT)
- dialog.vbox.pack_start(self.pannableArea)
-
- self.treeview_settings.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
- self.treestore_settings = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
- self.treeview_settings.set_model(self.treestore_settings)
-
- for key in listOfFeeds["feedingit-order"]:
- title = listOfFeeds[key]["title"]
- item = self.treestore_settings.append([title, key])
- if key in self.feed_list:
- self.treeview_settings.get_selection().select_iter(item)
+ if isfile(CONFIGDIR+"feeds.db"):
+ db = sqlite3.connect(CONFIGDIR+"feeds.db")
- self.pannableArea.add(self.treeview_settings)
- self.pannableArea.show_all()
- dialog.set_default_size(-1, 600)
-
- dialog.action_area.pack_start(self.create_autoupdate_picker())
-
- dialog.show_all()
- response = dialog.run()
-
- if response == gtk.RESPONSE_ACCEPT:
- self.feed_list = self.getItems()
- dialog.destroy()
- self.save_config()
- self.update_list()
+ dialog = gtk.Dialog("Choose feeds to display", None, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
+
+ self.pannableArea = hildon.PannableArea()
+
+ #self.treestore_settings = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
+ self.treeview_settings = gtk.TreeView()
+
+ self.treeview_settings.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
+ hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview_settings, gtk.HILDON_UI_MODE_EDIT)
+ dialog.vbox.pack_start(self.pannableArea)
+
+ self.treeview_settings.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
+ self.treestore_settings = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
+ self.treeview_settings.set_model(self.treestore_settings)
+
+ feeds = db.execute("SELECT title, id FROM feeds;")
+
+ for feed in feeds:
+ # feed is (id, title)
+ item = self.treestore_settings.append(feed)
+ if feed[1] in self.feed_list:
+ self.treeview_settings.get_selection().select_iter(item)
+
+ self.pannableArea.add(self.treeview_settings)
+ self.pannableArea.show_all()
+ dialog.set_default_size(-1, 600)
+
+ dialog.action_area.pack_start(self.create_autoupdate_picker())
+
+ dialog.show_all()
+ response = dialog.run()
+
+ if response == gtk.RESPONSE_ACCEPT:
+ self.feed_list = self.getItems()
+ dialog.destroy()
+ self.save_config()
+ self.update_list()
+ else:
+ dialog = gtk.Dialog("Please add feeds first", None, gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_NO_SEPARATOR, (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+ label = gtk.Label("Please add feeds through the main application")
+ dialog.vbox.pack_start(label)
+ dialog.show_all()
+ response = dialog.run()
+ dialog.destroy()
#self.treeview_settings.get_selection().select_all()
def getItems(self):
signal_name="UpdateFinished", path="/org/marcoz/feedingit/update")
def update_started(self, *widget):
- self.button.set_sensitive(True)
- self.update_label("Updating...", "Click to stop update")
+ self.buttonUpdate.set_image(gtk.image_new_from_icon_name('general_stop', gtk.ICON_SIZE_BUTTON))
+ self.updateStatus = 1
def update_finished(self, *widget):
- self.button.set_sensitive(False)
- self.update_label("Update done")
+ self.updateStatus = 0
+ self.buttonUpdate.set_image(gtk.image_new_from_icon_name('general_refresh', gtk.ICON_SIZE_BUTTON))
def start_update(self):
try:
if self.autoupdate >0:
- file = open("/home/user/.feedingit/feedingit_widget.log", "a")
- from time import localtime, strftime
- import os
- file.write("Widget: pid:%s ppid:%s time:%s\n" % (os.getpid(), os.getppid(), strftime("%a, %d %b %Y %H:%M:%S +0000", localtime())))
- file.close()
+ #file = open("/home/user/.feedingit/feedingit_widget.log", "a")
+ #from time import localtime, strftime
+ #import os
+ #file.write("Widget: pid:%s ppid:%s time:%s\n" % (os.getpid(), os.getppid(), strftime("%a, %d %b %Y %H:%M:%S +0000", localtime())))
+ #file.close()
remote_object = bus.get_object("org.marcoz.feedingit", # Connection name
"/org/marcoz/feedingit/update" # Object's path
)
def setup_autoupdate(self):
if (float(self.autoupdate) > 0):
if (not self.autoupdateId==False):
- file = open("/home/user/.feedingit/feedingit_widget.log", "a")
- file.write("Disabling %s\n" % self.autoupdateId)
- file.close()
+ #file = open("/home/user/.feedingit/feedingit_widget.log", "a")
+ #file.write("Disabling %s\n" % self.autoupdateId)
+ #file.close()
gobject.source_remove(self.autoupdateId)
remove(SOURCE)
self.autoupdateId = gobject.timeout_add_seconds(int(float(self.autoupdate)*3600), self.start_update)
file = open(SOURCE, "w")
file.write(str(self.autoupdateId))
file.close()
- file = open("/home/user/.feedingit/feedingit_widget.log", "a")
- file.write("Started %s\n" % self.autoupdateId)
- file.close()
+ #file = open("/home/user/.feedingit/feedingit_widget.log", "a")
+ #file.write("Started %s\n" % self.autoupdateId)
+ #file.close()
else:
if (not self.autoupdateId==False):
gobject.source_remove(self.autoupdateId)
remove(SOURCE)
def load_config(self):
- try:
+ if isfile(CONFIGDIR+"widget"):
file = open(CONFIGDIR+"widget", "r")
self.feed_list = pickle.load( file )
self.autoupdate = pickle.load( file )
file.close()
self.setup_autoupdate()
- except:
- file = open(CONFIGDIR+"feeds.pickle")
- listOfFeeds = pickle.load(file)
- file.close()
+ elif isfile(CONFIGDIR+"feeds.db"):
+ db = sqlite3.connect(CONFIGDIR+"feeds.db")
+ feeds = db.execute("SELECT id, title FROM feeds;")
- #self.feed_list = listOfFeeds["feedingit-order"]
- for key in listOfFeeds["feedingit-order"]:
- self.feed_list[key] = listOfFeeds[key]["title"]
- del listOfFeeds
+ for feed in feeds:
+ self.feed_list[feed[0]] = feed[1]
self.autoupdate = 0
+ else:
+ self.feed_list = None
hd_plugin_type = FeedingItHomePlugin