Source

feedreader / feeds.py

Full commit
# -*- coding:utf-8 -*-

from PyQt4 import QtGui, QtCore

import feedparser
import itertools

class EntryListModel(QtCore.QAbstractItemModel):
    headers = (QtCore.QVariant(u'Title'), QtCore.QVariant(u'Date'))
    def __init__(self, parent):
        super(EntryListModel, self).__init__(parent)
        self._entries = []

    def columnCount(self, parent):
        return len(self.headers)

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self.headers[section]

        return QtCore.QVariant()
            
    def rowCount(self, parent):
        if parent.isValid():
            return 0
        return len(self._entries)

    def index(self, row, column, parent):
        return self.createIndex(row, column, self._entries[row])

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if not index.isValid():
            return QtCore.QVariant()
        if role != QtCore.Qt.DisplayRole:
            return QtCore.QVariant()
        entry = self._entries[index.row()]
        if index.column() == 0:
            return QtCore.QVariant(entry.title)
        elif index.column() == 1:
            return QtCore.QVariant(entry.date)
        else:
            return QtCore.QVariant()

    def parent(self, item):
        return QtCore.QModelIndex()


    def set_entries(self, entries):
        self._entries = entries
        self.emit(QtCore.SIGNAL('modelReset()'))

    def get_entries(self):
        return self._entries



class Feed(object):
    def __init__(self, name=None, url=None):
        self.name = name
        self.url = url
        self.category = None

    @property
    def entries(self):
        d = feedparser.parse(self.url)
        return d.entries

    @property
    def children(self):
        return []


    @property
    def index(self):
        for i in xrange(len(self.category.children)):
            if self.category.children[i] == self:
                return i

    @property
    def level(self):
        return self.category.level + 1

class FeedCategory(object):
    def __init__(self, name=None, feeds=None):
        self.name = name
        self.category = None
        if not feeds:
            self.feeds = []
        else:
            self.feeds = feeds
            for f in self.feeds:
                f.category = self

    @property
    def index(self):
        if not self.category:
            return 0
        for i in xrange(len(self.category.children)):
            if self.category.children[i] == self:
                return i

    @property
    def children(self):
        return self.feeds

    @property
    def url(self):
        return u''

    @property
    def entries(self):
        return itertools.chain(*[c.entries for c in self.children])

    @property
    def level(self):

        if not self.category:
            return 0
        return self.category.level + 1


class FeedListModel(QtCore.QAbstractItemModel):
    def __init__(self, feeds, parent=None):
        super(FeedListModel, self).__init__(parent)
        self.headers = [QtCore.QVariant('Name'),
                        QtCore.QVariant('URL')]
        self.feeds = feeds


    def columnCount(self, parent):
        return 2

    def index(self, row, column, parent=QtCore.QModelIndex()):

        if not parent.isValid():
            return self.createIndex(row, column, self.feeds[row])
        else:
            parentItem = parent.internalPointer()
            if len(parentItem.children) > row:
                return self.createIndex(row, column, parentItem.children[row])
            else:
                return self.createIndex(row, column)
                
            

    def parent(self, index):
        if index.internalPointer() in self.feeds:
            
            return QtCore.QModelIndex()

        item = index.internalPointer()
        if item is None:
            return QtCore.QModelIndex()
        if item.category is None:
            return QtCore.QModelIndex()
            
        parent = item.category
        
        return self.createIndex(parent.index, max(parent.level, 0), parent)

    def rowCount(self, parent):
        item = parent.internalPointer()
        if item:
            return len(item.children)

        return len(self.feeds)

    def data(self, index, role=QtCore.Qt.DisplayRole):

        if role != QtCore.Qt.DisplayRole:
            return QtCore.QVariant()

        item = index.internalPointer()
        if item is None:
            return QtCore.QVariant()

        if index.column() == 0:
            return QtCore.QVariant(item.name)
        elif index.column() == 1:
            return QtCore.QVariant(item.url)
        else:
            return QtCore.QVariant()

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self.headers[section]

        return QtCore.QVariant()
            
        

if __name__ == '__main__':
    import sys, os
    app = QtGui.QApplication(sys.argv)
    v = QtGui.QTreeView()
    urls = [
        (u'Aodag Blog', 'http://feeds.feedburner.jp/AodagBlog'),
        (u'aodagの日記', 'http://d.hatena.ne.jp/aodag/rss'),
        ]
    blog = FeedCategory('blog', [Feed(n, u) for n, u in urls])
    root = FeedCategory('root', [blog])

    model = FeedListModel(root, v)
    v.setModel(model)
    v.show()
    
    sys.exit(app.exec_())