PyQt4で作るRSSリーダー

aodag2006-05-29

調子に乗ってRSSリーダーを作ってみましたよ。
RSSの解析には以下のスクリプトを使用しました。
http://www.mnot.net/python/RSS.py

これ、そのままではWindows上で動かない。
signalモジュールが引っかかってしまうのだけど、
今回はあえなくコメントアウトに。

30行目付近でsignalを使っている部分をコメントアウト

        #signal.signal(signal.SIGALRM, self._timeout)
        #signal.alarm(timeout)
        #try:
	p.parse(str(url))  # URIs are ascii
        #finally:
            #signal.alarm(0)
        return dh

RSSリーダーはやっぱ3ペインだよねーということで、
リストモデルも作ってしまった。
Qt4からは、ModelViewフレームワークがあるので、
結構楽チン。

from PyQt4 import QtCore, QtGui
from RSS import ns, CollectionChannel, TrackingChannel

import sys



class Site:

    def __init__(self, name, url):

	self.name = name
	self.url = url
	self.fetched = False
	self.items = 


    def listItems(self):

	if not self.fetched:

	    tc = TrackingChannel()
	    tc.parse(self.url)
	    RSS10_TITLE = (ns.rss10, 'title')
	    RSS10_DESC = (ns.rss10, 'description')
	    items = tc.listItems()

	    for item in items:

		item_data = tc.getItem(item)
		description = item_data.get(RSS10_DESC, "(none)")
		title = item_data.get(RSS10_TITLE, "(none)")
		self.items.append({'title':title,
				   'description':description})

	    self.fetched = True

	return self.items


class SiteListModel (QtCore.QAbstractListModel):

    def __init__(self,parent=None):

	QtCore.QAbstractListModel.__init__(self, parent)
	self.sites = 


    def addSite(self, site):

	self.sites.append(site)


    def removeSite(self, site):

	self.sites.remove(site)


    def rowCount(self, parentIndex):

	return len(self.sites)


    def data(self, index, role):

	if not index.isValid():

	    return QtCore.QVariant()

	if role == QtCore.Qt.DisplayRole:

	    site = self.sites[index.row()]
	    return QtCore.QVariant(site.name)

	return QtCore.QVariant()



class SiteItemModel (QtCore.QAbstractListModel):

    def __init__(self, site, parent=None):

	QtCore.QAbstractListModel.__init__(self, parent)
	self.site = site
	self.site.listItems()


    def rowCount(self, parentIndex):

	return len(self.site.items)
    

    def data(self, index, role):

	if not index.isValid():

	    return QtCore.QVariant()

	if role == QtCore.Qt.DisplayRole:

	    title = unicode(self.site.items[index.row()]["title"], 'utf-8')
	    return QtCore.QVariant(title)

	return QtCore.QVariant()


class MainWindow (QtGui.QMainWindow):

    def __init__(self, sites, parent=None):

	QtGui.QMainWindow.__init__(self, parent)
	self.mainSplitter = QtGui.QSplitter(QtCore.Qt.Vertical, self)
	self.splitter = QtGui.QSplitter(self.mainSplitter)
	self.mainSplitter.addWidget(self.splitter)
	self.rssView = QtGui.QTextEdit(self.mainSplitter)
	self.rssView.setReadOnly(True)
	self.mainSplitter.addWidget(self.rssView)
	self.setCentralWidget(self.mainSplitter)
	self.siteListModel = SiteListModel(self)
	self.siteListModel.sites = sites
	self.siteListView = QtGui.QListView(self.splitter)
	self.siteListView.setModel(self.siteListModel)
	self.rssListView = QtGui.QListView(self.splitter)
	self.splitter.addWidget(self.siteListView)
	self.splitter.addWidget(self.rssListView)
	self.connect(self.siteListView, 
		     QtCore.SIGNAL('activated(const QModelIndex &)'),
		     self.siteSelected)

	self.connect(self.rssListView, 
		     QtCore.SIGNAL('activated(const QModelIndex &)'),
		     self.rssSelected)



    def siteSelected(self, index):

	site = self.siteListModel.sites[index.row()]
	self.siteItemModel = SiteItemModel(site, self)
	self.rssListView.setModel(self.siteItemModel)


    def rssSelected(self, index):

	rss = self.siteItemModel.site.items[index.row()]
	self.rssView.setHtml(unicode(rss["description"], 'utf-8'))



def main():

    sites = [Site("vlog", 
	  "http://vlog.blog32.fc2.com/?xml"),
	  Site("python language web", 
	  "http://www.python.org/channews.rdf")]

    app = QtGui.QApplication(sys.argv)
    win = MainWindow(sites)
    win.show()
    sys.exit(app.exec_())

if __name__ == '__main__':

    main()


所要時間は1時間ちょい。

初出:http://vlog.blog32.fc2.com/blog-entry-34.html