class AddWidgetWizard(gtk.Dialog):
- def __init__(self, parent, urlIn, titleIn=None, isEdit=False):
+ def __init__(self, parent, listing, urlIn, categories, titleIn=None, isEdit=False, currentCat=1):
gtk.Dialog.__init__(self)
self.set_transient_for(parent)
+
+ #self.category = categories[0]
+ self.category = currentCat
if isEdit:
self.set_title('Edit RSS feed')
self.urlEntry.select_region(-1, -1)
self.urlEntry.set_activates_default(True)
- self.table = gtk.Table(2, 2, False)
+ self.table = gtk.Table(3, 2, False)
self.table.set_col_spacings(5)
label = gtk.Label('Name:')
label.set_alignment(1., .5)
label.set_alignment(1., .5)
self.table.attach(label, 0, 1, 1, 2, gtk.FILL)
self.table.attach(self.urlEntry, 1, 2, 1, 2)
+ selector = self.create_selector(categories, listing)
+ picker = hildon.PickerButton(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ picker.set_selector(selector)
+ picker.set_title("Select category")
+ #picker.set_text(listing.getCategoryTitle(self.category), None) #, "Subtitle")
+ picker.set_name('HildonButton-finger')
+ picker.set_alignment(0,0,1,1)
+
+ self.table.attach(picker, 0, 2, 2, 3, gtk.FILL)
+
self.vbox.pack_start(self.table)
self.show_all()
def getData(self):
- return (self.nameEntry.get_text(), self.urlEntry.get_text())
-
- def some_page_func(self, nb, current, userdata):
- # Validate data for 1st page
- if current == 0:
- return len(self.nameEntry.get_text()) != 0
- elif current == 1:
- # Check the url is not null, and starts with http
- return ( (len(self.urlEntry.get_text()) != 0) and (self.urlEntry.get_text().lower().startswith("http")) )
- elif current != 2:
- return False
+ return (self.nameEntry.get_text(), self.urlEntry.get_text(), self.category)
+
+ def create_selector(self, choices, listing):
+ #self.pickerDialog = hildon.PickerDialog(self.parent)
+ selector = hildon.TouchSelector(text=True)
+ index = 0
+ self.map = {}
+ for item in choices:
+ title = listing.getCategoryTitle(item)
+ iter = selector.append_text(str(title))
+ if self.category == item:
+ selector.set_active(0, index)
+ self.map[title] = item
+ index += 1
+ selector.connect("changed", self.selection_changed)
+ #self.pickerDialog.set_selector(selector)
+ return selector
+
+ def selection_changed(self, selector, button):
+ current_selection = selector.get_current_text()
+ if current_selection:
+ self.category = self.map[current_selection]
+
+class AddCategoryWizard(gtk.Dialog):
+ def __init__(self, parent, titleIn=None, isEdit=False):
+ gtk.Dialog.__init__(self)
+ self.set_transient_for(parent)
+
+ if isEdit:
+ self.set_title('Edit Category')
else:
- return True
+ self.set_title('Add Category')
+
+ 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('Category name')
+ if not titleIn == None:
+ self.nameEntry.set_text(titleIn)
+ self.nameEntry.select_region(-1, -1)
+
+ self.table = gtk.Table(1, 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)
+
+ self.show_all()
+
+ def getData(self):
+ return self.nameEntry.get_text()
class Download(Thread):
def __init__(self, listing, key, config):
class SortList(hildon.StackableWindow):
- def __init__(self, parent, listing, feedingit, after_closing):
+ def __init__(self, parent, listing, feedingit, after_closing, category=None):
hildon.StackableWindow.__init__(self)
self.set_transient_for(parent)
- self.set_title('Subscriptions')
+ if category:
+ self.isEditingCategories = False
+ self.category = category
+ self.set_title(listing.getCategoryTitle(category))
+ else:
+ self.isEditingCategories = True
+ self.set_title('Categories')
self.listing = listing
self.feedingit = feedingit
self.after_closing = after_closing
- self.connect('destroy', lambda w: self.after_closing())
+ if after_closing:
+ self.connect('destroy', lambda w: self.after_closing())
self.vbox2 = gtk.VBox(False, 2)
button = hildon.GtkButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
#rect = self.treeview.get_visible_rect()
#y = rect.y+rect.height
self.treestore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
- for key in self.listing.getListOfFeeds():
- item = self.treestore.append([self.listing.getFeedTitle(key), key])
- if key == selected:
- selectedItem = item
+ if self.isEditingCategories:
+ for key in self.listing.getListOfCategories():
+ item = self.treestore.append([self.listing.getCategoryTitle(key), key])
+ if key == selected:
+ selectedItem = item
+ else:
+ for key in self.listing.getListOfFeeds(category=self.category):
+ item = self.treestore.append([self.listing.getFeedTitle(key), key])
+ if key == selected:
+ selectedItem = item
self.treeview.set_model(self.treestore)
if not selected == None:
self.treeview.get_selection().select_iter(selectedItem)
def buttonUp(self, button):
key = self.getSelectedItem()
if not key == None:
- self.listing.moveUp(key)
+ if self.isEditingCategories:
+ self.listing.moveCategoryUp(key)
+ else:
+ self.listing.moveUp(key)
self.refreshList(key, -10)
def buttonDown(self, button):
key = self.getSelectedItem()
if not key == None:
- self.listing.moveDown(key)
+ if self.isEditingCategories:
+ self.listing.moveCategoryDown(key)
+ else:
+ self.listing.moveDown(key)
self.refreshList(key, 10)
def buttonDelete(self, button):
response = dlg.run()
dlg.destroy()
if response == gtk.RESPONSE_OK:
- self.listing.removeFeed(key)
+ if self.isEditingCategories:
+ self.listing.removeCategory(key)
+ else:
+ self.listing.removeFeed(key)
self.refreshList()
def buttonEdit(self, button):
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()
+ if self.isEditingCategories:
+ if key is not None:
+ SortList(self.parent, self.listing, self.feedingit, None, category=key)
+ else:
+ if key is not None:
+ wizard = AddWidgetWizard(self, self.listing, self.listing.getFeedUrl(key), self.listing.getListOfCategories(), self.listing.getFeedTitle(key), True, currentCat=self.category)
+ ret = wizard.run()
+ if ret == 2:
+ (title, url, category) = wizard.getData()
+ if (not title == '') and (not url == ''):
+ self.listing.editFeed(key, title, url, category=category)
+ self.refreshList()
+ wizard.destroy()
def buttonDone(self, *args):
self.destroy()
def buttonAdd(self, button, urlIn="http://"):
- wizard = AddWidgetWizard(self, urlIn)
- ret = wizard.run()
- if ret == 2:
- (title, url) = wizard.getData()
- if (not title == '') and (not url == ''):
- self.listing.addFeed(title, url)
+ if self.isEditingCategories:
+ wizard = AddCategoryWizard(self)
+ ret = wizard.run()
+ if ret == 2:
+ title = wizard.getData()
+ if (not title == ''):
+ self.listing.addCategory(title)
+ else:
+ wizard = AddWidgetWizard(self, self.listing, urlIn, self.listing.getListOfCategories())
+ ret = wizard.run()
+ if ret == 2:
+ (title, url, category) = wizard.getData()
+ if (not title == '') and (not url == ''):
+ self.listing.addFeed(title, url, category=category)
wizard.destroy()
self.refreshList()
gobject.idle_add(self.createWindow)
def createWindow(self):
+ self.category = 0
+
self.app_lock = get_lock("app_lock")
if self.app_lock == None:
try:
#self.articleWindow = hildon.StackableWindow()
self.introLabel.destroy()
self.pannableListing = hildon.PannableArea()
- self.feedItems = gtk.ListStore(gtk.gdk.Pixbuf, str, str)
+ 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.displayListing()
self.autoupdate = False
self.checkAutoUpdate()
+
hildon.hildon_gtk_window_set_progress_indicator(self.window, 0)
gobject.idle_add(self.enableDbus)
self.displayListing()
def addFeed(self, urlIn="http://"):
- wizard = AddWidgetWizard(self.window, urlIn)
+ wizard = AddWidgetWizard(self.window, self.listing, urlIn, self.listing.getListOfCategories())
ret = wizard.run()
if ret == 2:
(title, url) = wizard.getData()
else:
return False
+ def saveExpandedLines(self):
+ self.expandedLines = []
+ model = self.feedList.get_model()
+ model.foreach(self.checkLine)
+
+ def checkLine(self, model, path, iter, data = None):
+ if self.feedList.row_expanded(path):
+ self.expandedLines.append(path)
+
+ def restoreExpandedLines(self):
+ model = self.feedList.get_model()
+ model.foreach(self.restoreLine)
+
+ def restoreLine(self, model, path, iter, data = None):
+ if path in self.expandedLines:
+ self.feedList.expand_row(path, False)
+
def displayListing(self):
icon_theme = gtk.icon_theme_get_default()
default_pixbuf = icon_theme.load_icon(ABOUT_ICON, LIST_ICON_SIZE, \
gtk.ICON_LOOKUP_USE_BUILTIN)
+ self.saveExpandedLines()
+
self.feedItems.clear()
hideReadFeed = self.config.getHideReadFeeds()
order = self.config.getFeedSortOrder()
- keys = self.listing.getSortedListOfKeys(order, onlyUnread=hideReadFeed)
-
- for key in keys:
- 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)
- else:
- markup = FEED_TEMPLATE % (title, subtitle)
-
- try:
- icon_filename = self.listing.getFavicon(key)
- pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon_filename, \
- LIST_ICON_SIZE, LIST_ICON_SIZE)
- except:
- pixbuf = default_pixbuf
+
+ categories = self.listing.getListOfCategories()
+ if len(categories) > 1:
+ showCategories = True
+ else:
+ showCategories = False
+
+ for categoryId in categories:
+
+ title = self.listing.getCategoryTitle(categoryId)
+ keys = self.listing.getSortedListOfKeys(order, onlyUnread=hideReadFeed, category=categoryId)
+
+ if showCategories and len(keys)>0:
+ category = self.feedItems.append(None, (None, title, categoryId))
+ #print "catID" + str(categoryId) + " " + str(self.category)
+ if categoryId == self.category:
+ #print categoryId
+ expandedRow = category
- self.feedItems.append((pixbuf, markup, key))
+ for key in keys:
+ 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)
+ else:
+ markup = FEED_TEMPLATE % (title, subtitle)
+
+ try:
+ icon_filename = self.listing.getFavicon(key)
+ pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon_filename, \
+ LIST_ICON_SIZE, LIST_ICON_SIZE)
+ except:
+ pixbuf = default_pixbuf
+
+ if showCategories:
+ self.feedItems.append(category, (pixbuf, markup, key))
+ else:
+ self.feedItems.append(None, (pixbuf, markup, key))
+
+
+ self.restoreExpandedLines()
+ #try:
+
+ # self.feedList.expand_row(self.feeItems.get_path(expandedRow), True)
+ #except:
+ # pass
def on_feedList_row_activated(self, treeview, path, column):
model = treeview.get_model()
iter = model.get_iter(path)
key = model.get_value(iter, COLUMN_KEY)
- self.openFeed(key)
+
+ try:
+ #print "Key: " + str(key)
+ catId = int(key)
+ self.category = catId
+ if treeview.row_expanded(path):
+ treeview.collapse_row(path)
+ #else:
+ # treeview.expand_row(path, True)
+ #treeview.collapse_all()
+ #treeview.expand_row(path, False)
+ #for i in range(len(path)):
+ # self.feedList.expand_row(path[:i+1], False)
+ #self.show_confirmation_note(self.window, "Working")
+ #return True
+ except:
+ if key:
+ self.openFeed(key)
def openFeed(self, key):
try:
try:
table = self.db.execute("SELECT sql FROM sqlite_master").fetchone()
if table == None:
- self.db.execute("CREATE TABLE feeds(id text, url text, title text, unread int, updateTime float, rank int, etag text, modified text, widget int);")
+ self.db.execute("CREATE TABLE feeds(id text, url text, title text, unread int, updateTime float, rank int, etag text, modified text, widget int, category int);")
+ self.db.execute("CREATE TABLE categories(id text, title text, unread int, rank int);")
+ self.addCategory("Default Category")
if isfile(self.configdir+"feeds.pickle"):
self.importOldFormatFeeds()
else:
self.db.execute("ALTER TABLE feeds ADD COLUMN widget int;")
self.db.execute("UPDATE feeds SET widget=1;")
self.db.commit()
+ if find(upper(table[0]), "CATEGORY")<0:
+ self.db.execute("CREATE TABLE categories(id text, title text, unread int, rank int);")
+ self.addCategory("Default Category")
+ self.db.execute("ALTER TABLE feeds ADD COLUMN category int;")
+ self.db.execute("UPDATE feeds SET category=1;")
+ self.db.commit()
except:
pass
try:
rank += 1
values = (id, listing.getFeedTitle(id) , listing.getFeedUrl(id), 0, time.time(), rank, None, "None", 1)
- self.db.execute("INSERT INTO feeds (id, title, url, unread, updateTime, rank, etag, modified, widget) VALUES (?, ?, ? ,? ,? ,?, ?, ?, ?);", values)
+ self.db.execute("INSERT INTO feeds (id, title, url, unread, updateTime, rank, etag, modified, widget, category) VALUES (?, ?, ? ,? ,? ,?, ?, ?, ?, 1);", values)
self.db.commit()
feed = listing.getFeed(id)
return ArchivedArticles(self.configdir, key)
return Feed(self.configdir, key)
- def editFeed(self, key, title, url):
- self.db.execute("UPDATE feeds SET title=?, url=? WHERE id=?;", (title, url, key))
+ def editFeed(self, key, title, url, category=None):
+ if category:
+ self.db.execute("UPDATE feeds SET title=?, url=?, category=? WHERE id=?;", (title, url, category, key))
+ else:
+ self.db.execute("UPDATE feeds SET title=?, url=? WHERE id=?;", (title, url, key))
self.db.commit()
def getFeedUpdateTime(self, key):
def getFeedUrl(self, key):
return self.db.execute("SELECT url FROM feeds WHERE id=?;", (key,)).fetchone()[0]
- def getListOfFeeds(self):
- rows = self.db.execute("SELECT id FROM feeds ORDER BY rank;" )
+ def getListOfFeeds(self, category=None):
+ if category:
+ rows = self.db.execute("SELECT id FROM feeds WHERE category=? ORDER BY rank;", (category, ) )
+ else:
+ rows = self.db.execute("SELECT id FROM feeds ORDER BY rank;" )
+ keys = []
+ for row in rows:
+ if row[0]:
+ keys.append(row[0])
+ return keys
+
+ def getListOfCategories(self):
+ rows = self.db.execute("SELECT id FROM categories ORDER BY rank;" )
keys = []
for row in rows:
if row[0]:
keys.append(row[0])
return keys
- def getSortedListOfKeys(self, order, onlyUnread=False):
+ def getCategoryTitle(self, id):
+ print id
+ row = self.db.execute("SELECT title FROM categories WHERE id=?;", (id, )).fetchone()
+ return row[0]
+
+ def getSortedListOfKeys(self, order, onlyUnread=False, category=1):
if order == "Most unread":
tmp = "ORDER BY unread DESC"
#keyorder = sorted(feedInfo, key = lambda k: feedInfo[k][1], reverse=True)
tmp = "ORDER BY rank"
#keyorder = sorted(feedInfo, key = lambda k: feedInfo[k][0])
if onlyUnread:
- sql = "SELECT id FROM feeds WHERE unread>0 " + tmp
+ sql = "SELECT id FROM feeds WHERE unread>0 WHERE category=%s" %category + tmp
else:
- sql = "SELECT id FROM feeds " + tmp
+ sql = "SELECT id FROM feeds WHERE category=%s " %category + tmp
rows = self.db.execute(sql)
keys = []
for row in rows:
db.execute("UPDATE feeds SET unread=? WHERE id=?;", (feed.getNumberOfUnreadItems(), key))
db.commit()
- def addFeed(self, title, url, id=None):
+ def addFeed(self, title, url, id=None, category=1):
if not id:
id = getId(title)
count = self.db.execute("SELECT count(*) FROM feeds WHERE id=?;", (id,) ).fetchone()[0]
max_rank = self.db.execute("SELECT MAX(rank) FROM feeds;").fetchone()[0]
if max_rank == None:
max_rank = 0
- values = (id, title, url, 0, 0, max_rank+1, None, "None", 1)
- self.db.execute("INSERT INTO feeds (id, title, url, unread, updateTime, rank, etag, modified, widget) VALUES (?, ?, ? ,? ,? ,?, ?, ?, ?);", values)
+ values = (id, title, url, 0, 0, max_rank+1, None, "None", 1, category)
+ self.db.execute("INSERT INTO feeds (id, title, url, unread, updateTime, rank, etag, modified, widget, category) VALUES (?, ?, ? ,? ,? ,?, ?, ?, ?,?);", values)
self.db.commit()
# Ask for the feed object, it will create the necessary tables
self.getFeed(id)
return True
else:
return False
+
+ def addCategory(self, title):
+ rank = self.db.execute("SELECT MAX(rank)+1 FROM categories;").fetchone()[0]
+ if rank==None:
+ rank=1
+ id = self.db.execute("SELECT MAX(id)+1 FROM categories;").fetchone()[0]
+ if id==None:
+ id=1
+ self.db.execute("INSERT INTO categories (id, title, unread, rank) VALUES (?, ?, 0, ?)", (id, title, rank))
+ self.db.commit()
def removeFeed(self, key):
rank = self.db.execute("SELECT rank FROM feeds WHERE id=?;", (key,) ).fetchone()[0]
if isdir(self.configdir+key+".d/"):
rmtree(self.configdir+key+".d/")
- #self.saveConfig()
+
+ def removeCategory(self, key):
+ if self.db.execute("SELECT count(*) FROM categories;").fetchone()[0] > 1:
+ rank = self.db.execute("SELECT rank FROM categories WHERE id=?;", (key,) ).fetchone()[0]
+ self.db.execute("DELETE FROM categories WHERE id=?;", (key, ))
+ self.db.execute("UPDATE categories SET rank=rank-1 WHERE rank>?;", (rank,) )
+ self.db.execute("UPDATE feeds SET category=1 WHERE category=?;", (key,) )
+ self.db.commit()
#def saveConfig(self):
# self.listOfFeeds["feedingit-order"] = self.sortedKeys
self.db.execute("UPDATE feeds SET rank=? WHERE rank=?;", (rank, rank-1) )
self.db.execute("UPDATE feeds SET rank=? WHERE id=?;", (rank-1, key) )
self.db.commit()
+
+ def moveCategoryUp(self, key):
+ rank = self.db.execute("SELECT rank FROM categories WHERE id=?;", (key,)).fetchone()[0]
+ if rank>0:
+ self.db.execute("UPDATE categories SET rank=? WHERE rank=?;", (rank, rank-1) )
+ self.db.execute("UPDATE categories SET rank=? WHERE id=?;", (rank-1, key) )
+ self.db.commit()
def moveDown(self, key):
rank = self.db.execute("SELECT rank FROM feeds WHERE id=?;", (key,)).fetchone()[0]
self.db.execute("UPDATE feeds SET rank=? WHERE id=?;", (rank+1, key) )
self.db.commit()
+ def moveCategoryDown(self, key):
+ rank = self.db.execute("SELECT rank FROM categories WHERE id=?;", (key,)).fetchone()[0]
+ max_rank = self.db.execute("SELECT MAX(rank) FROM categories;").fetchone()[0]
+ if rank<max_rank:
+ self.db.execute("UPDATE categories SET rank=? WHERE rank=?;", (rank, rank+1) )
+ self.db.execute("UPDATE categories SET rank=? WHERE id=?;", (rank+1, key) )
+ self.db.commit()