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 # ============================================================================
27 import gtk, pickle, gobject, dbus
28 import hildondesktop, hildon
29 #from rss import Listing
31 # Create a session bus.
33 from dbus.mainloop.glib import DBusGMainLoop
34 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
35 #bus = dbus.SessionBus()
37 from os import environ, remove
38 bus = dbus.bus.BusConnection(environ["DBUS_SESSION_BUS_ADDRESS"])
39 from os.path import isfile
41 settings = gtk.settings_get_default()
42 color_style = gtk.rc_get_style_by_paths( settings, 'GtkButton', 'osso-logical-colors', gtk.Button)
43 active_color = color_style.lookup_color('ActiveTextColor')
44 default_color = color_style.lookup_color('DefaultTextColor')
45 font_desc = gtk.rc_get_style_by_paths(settings, 'HomeSystemFont', None, None).font_desc
49 CONFIGDIR="/home/user/.feedingit/"
50 SOURCE=CONFIGDIR + "source"
52 #DBusConnection *hd_home_plugin_item_get_dbus_connection ( HDHomePluginItem *item, DBusBusType type, DBusError *error);
54 #libc = ctypes.CDLL('libc.so.6')
55 #libc.printf('Hello world!')
57 def get_font_desc(logicalfontname):
58 settings = gtk.settings_get_default()
59 font_style = gtk.rc_get_style_by_paths(settings, logicalfontname, \
61 font_desc = font_style.font_desc
64 class FeedingItHomePlugin(hildondesktop.HomePluginItem):
67 'destroy' : 'override'
71 hildondesktop.HomePluginItem.__init__(self)
72 self.set_settings(True)
73 self.connect("show-settings", self.show_settings)
78 self.autoupdateId = int(file.read())
81 self.autoupdateId=False
83 vbox = gtk.VBox(False, 0)
85 #self.button = gtk.Button()
86 self.button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
87 self.button.set_text("FeedingIt","")
88 self.button.set_sensitive(False)
89 self.label1 = self.button.child.child.get_children()[0].get_children()[0]
90 self.label2 = self.button.child.child.get_children()[0].get_children()[1]
91 self.label1.modify_fg(gtk.STATE_INSENSITIVE, default_color)
92 self.label1.modify_font(font_desc)
93 self.label2.modify_fg(gtk.STATE_INSENSITIVE, active_color)
94 icon_theme = gtk.icon_theme_get_default()
95 pixbuf = icon_theme.load_icon("feedingit", 32, gtk.ICON_LOOKUP_USE_BUILTIN )
97 image.set_from_pixbuf(pixbuf)
98 self.button.set_image(image)
99 self.button.set_image_position(gtk.POS_LEFT)
101 #button = gtk.Button("Update")
102 self.button.connect("clicked", self.button_clicked)
104 vbox.pack_start(self.button, expand=False)
106 #for feed in ["Slashdot", "Engadget", "Cheez"]:
107 # self.treestore.append([feed, "0"])
108 self.treeview = gtk.TreeView()
110 name_renderer = gtk.CellRendererText()
111 name_renderer.set_property("font-desc", font_desc)
112 unread_renderer = gtk.CellRendererText()
113 unread_renderer.set_property("font-desc", font_desc)
114 self.treeview.append_column(gtk.TreeViewColumn('Feed Name', name_renderer, text = 0))
115 self.treeview.append_column(gtk.TreeViewColumn('Unread Items', unread_renderer, text = 1))
116 selection = self.treeview.get_selection()
117 #selection.set_mode(gtk.SELECTION_NONE)
118 #self.treeview.get_selection().set_mode(gtk.SELECTION_NONE)
119 #hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview, gtk.HILDON_UI_MODE_NORMAL)
121 vbox.pack_start(self.treeview)
124 self.treeview.connect("hildon-row-tapped", self.row_activated)
125 #self.treeview.connect("cursor-changed", self.cursor_changed)
128 #gobject.timeout_add_seconds(30*60, self.update_list)
131 file = open("/home/user/.feedingit/feedingit_widget.log", "a")
132 traceback.print_exc(file=file)
135 def do_destroy(self):
136 #file = open("/home/user/.feedingit/feedingit_widget.log", "a")
137 #file.write("Do_destroy: ")
138 if (not self.autoupdateId==False):
139 gobject.source_remove(self.autoupdateId)
140 self.autoupdateId=False
141 #file.write("Destroyed %s\n" %self.autoupdateId)
143 hildondesktop.HomePluginItem.do_destroy(self)
144 #file.write("End destroy\n")
147 def button_clicked(self, *widget):
148 self.button.set_sensitive(False)
149 self.label1.modify_fg(gtk.STATE_NORMAL, default_color)
150 self.label2.modify_fg(gtk.STATE_NORMAL, active_color)
151 self.update_label("Stopping")
152 remote_object = bus.get_object("org.marcoz.feedingit", # Connection name
153 "/org/marcoz/feedingit/update" # Object's path
155 iface = dbus.Interface(remote_object, 'org.marcoz.feedingit')
158 def update_label(self, title, value=None):
159 self.button.set_title(title)
161 self.button.set_value(value)
163 self.button.set_value("")
165 def row_activated(self, treeview, treepath): #, column):
166 (model, iter) = self.treeview.get_selection().get_selected()
167 key = model.get_value(iter, 2)
168 # Create an object that will proxy for a particular remote object.
169 remote_object = bus.get_object("org.maemo.feedingit", # Connection name
170 "/org/maemo/feedingit" # Object's path
172 iface = dbus.Interface(remote_object, 'org.maemo.feedingit')
175 def update_list(self, *widget):
176 #listing = Listing(CONFIGDIR)
177 treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
179 if self.feed_list == {}:
183 oldtotal = self.total
185 #for key in listOfFeeds["feedingit-order"]:
186 for key in self.feed_list.keys():
188 file = open(CONFIGDIR+key+".d/unread", "r")
189 readItems = pickle.load( file )
192 for id in readItems.keys():
193 if readItems[id]==False:
194 countUnread = countUnread + 1
195 list.append([self.feed_list[key][0:18], countUnread, key])
196 self.total += countUnread
199 list = sorted(list, key=lambda item: item[1], reverse=True)
200 for item in list[0:8]:
201 treestore.append(item)
202 self.treeview.set_model(treestore)
203 if self.total > oldtotal:
204 self.update_label("%s Unread" %str(self.total), "%s more articles" %str(self.total-oldtotal))
206 self.update_label("%s Unread" %str(self.total))
209 def create_selector(self, choices, setting):
210 #self.pickerDialog = hildon.PickerDialog(self.parent)
211 selector = hildon.TouchSelector(text=True)
214 iter = selector.append_text(str(item))
215 if str(self.autoupdate) == str(item):
216 selector.set_active(0, index)
218 selector.connect("changed", self.selection_changed, setting)
219 #self.pickerDialog.set_selector(selector)
222 def selection_changed(self, selector, button, setting):
223 tmp = selector.get_current_text()
224 if tmp == "Disabled":
227 self.autoupdate = tmp
228 #current_selection = selector.get_current_text()
229 #if current_selection:
230 # self.config[setting] = current_selection
231 #gobject.idle_add(self.updateButton, setting)
234 def create_autoupdate_picker(self):
235 picker = hildon.PickerButton(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
236 selector = self.create_selector(["Disabled", 0.5, 1, 2, 4, 12, 24], "autoupdate")
237 picker.set_selector(selector)
238 picker.set_title("Frequency of updates from the widget")
239 picker.set_text("Setup Feed Auto-updates","Update every %s hours" %str(self.autoupdate) )
240 picker.set_name('HildonButton-finger')
241 picker.set_alignment(0,0,1,1)
242 #self.buttons[setting] = picker
243 #vbox.pack_start(picker, expand=False)
246 def show_settings(self, widget):
247 file = open(CONFIGDIR+"feeds.pickle")
248 listOfFeeds = pickle.load(file)
250 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))
252 self.pannableArea = hildon.PannableArea()
254 #self.treestore_settings = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
255 self.treeview_settings = gtk.TreeView()
257 self.treeview_settings.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
258 hildon.hildon_gtk_tree_view_set_ui_mode(self.treeview_settings, gtk.HILDON_UI_MODE_EDIT)
259 dialog.vbox.pack_start(self.pannableArea)
261 self.treeview_settings.append_column(gtk.TreeViewColumn('Feed Name', gtk.CellRendererText(), text = 0))
262 self.treestore_settings = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
263 self.treeview_settings.set_model(self.treestore_settings)
265 for key in listOfFeeds["feedingit-order"]:
266 title = listOfFeeds[key]["title"]
267 item = self.treestore_settings.append([title, key])
268 if key in self.feed_list:
269 self.treeview_settings.get_selection().select_iter(item)
271 self.pannableArea.add(self.treeview_settings)
272 self.pannableArea.show_all()
273 dialog.set_default_size(-1, 600)
275 dialog.action_area.pack_start(self.create_autoupdate_picker())
278 response = dialog.run()
280 if response == gtk.RESPONSE_ACCEPT:
281 self.feed_list = self.getItems()
285 #self.treeview_settings.get_selection().select_all()
289 treeselection = self.treeview_settings.get_selection()
290 (model, pathlist) = treeselection.get_selected_rows()
291 for path in pathlist:
292 list[model.get_value(model.get_iter(path),1)] = model.get_value(model.get_iter(path),0)
296 bus.add_signal_receiver(self.update_list, dbus_interface="org.marcoz.feedingit",
297 signal_name="ArticleCountUpdated", path="/org/marcoz/feedingit/update")
298 bus.add_signal_receiver(self.update_started, dbus_interface="org.marcoz.feedingit",
299 signal_name="UpdateStarted", path="/org/marcoz/feedingit/update")
300 bus.add_signal_receiver(self.update_finished, dbus_interface="org.marcoz.feedingit",
301 signal_name="UpdateFinished", path="/org/marcoz/feedingit/update")
303 def update_started(self, *widget):
304 self.button.set_sensitive(True)
305 self.update_label("Updating...", "Click to stop update")
307 def update_finished(self, *widget):
308 self.button.set_sensitive(False)
309 self.update_label("Update done")
311 def start_update(self):
313 if self.autoupdate >0:
314 #file = open("/home/user/.feedingit/feedingit_widget.log", "a")
315 #from time import localtime, strftime
317 #file.write("Widget: pid:%s ppid:%s time:%s\n" % (os.getpid(), os.getppid(), strftime("%a, %d %b %Y %H:%M:%S +0000", localtime())))
319 remote_object = bus.get_object("org.marcoz.feedingit", # Connection name
320 "/org/marcoz/feedingit/update" # Object's path
322 iface = dbus.Interface(remote_object, 'org.marcoz.feedingit')
327 file = open("/home/user/.feedingit/feedingit_widget.log", "a")
328 traceback.print_exc(file=file)
331 def save_config(self):
332 from os.path import isdir
333 if not isdir(CONFIGDIR):
336 file = open(CONFIGDIR+"widget", "w")
337 pickle.dump(self.feed_list, file )
338 pickle.dump(self.autoupdate, file)
340 self.setup_autoupdate()
342 def setup_autoupdate(self):
343 if (float(self.autoupdate) > 0):
344 if (not self.autoupdateId==False):
345 #file = open("/home/user/.feedingit/feedingit_widget.log", "a")
346 #file.write("Disabling %s\n" % self.autoupdateId)
348 gobject.source_remove(self.autoupdateId)
350 self.autoupdateId = gobject.timeout_add_seconds(int(float(self.autoupdate)*3600), self.start_update)
351 file = open(SOURCE, "w")
352 file.write(str(self.autoupdateId))
354 #file = open("/home/user/.feedingit/feedingit_widget.log", "a")
355 #file.write("Started %s\n" % self.autoupdateId)
358 if (not self.autoupdateId==False):
359 gobject.source_remove(self.autoupdateId)
360 self.autoupdateId=False
363 def load_config(self):
365 file = open(CONFIGDIR+"widget", "r")
366 self.feed_list = pickle.load( file )
367 self.autoupdate = pickle.load( file )
369 self.setup_autoupdate()
371 file = open(CONFIGDIR+"feeds.pickle")
372 listOfFeeds = pickle.load(file)
375 #self.feed_list = listOfFeeds["feedingit-order"]
376 for key in listOfFeeds["feedingit-order"]:
377 self.feed_list[key] = listOfFeeds[key]["title"]
382 hd_plugin_type = FeedingItHomePlugin
384 # The code below is just for testing purposes.
385 # It allows to run the widget as a standalone process.
386 if __name__ == "__main__":
388 gobject.type_register(hd_plugin_type)
389 obj = gobject.new(hd_plugin_type, plugin_id="plugin_id")