psa: adding toggle to show/hide specific feed on Event Feed stream
[feedingit] / psa_harmattan / feedingit / pysrc / feedingit.py
index 01c7b51..b401a0c 100644 (file)
@@ -7,16 +7,22 @@ from PySide import QtDeclarative
 import os
 from os import mkdir, remove, stat, environ
 from os.path import isfile, isdir, exists
+import codecs
+import dbus
+# import python dbus GLib mainloop support
+import dbus.mainloop.glib
+# Enable glib main loop support
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
 # Comment the line below if you don't want to use OpenGL for QML rendering or if it is not supported
 from PySide import QtOpenGL,  QtCore
 
 from rss_sqlite import Listing
-CONFIGDIR = environ.get("HOME", "/home/user") + "/.feedingit"
+CONFIGDIR = environ.get("HOME", "/home/user") + "/.feedingit/"
 #CONFIGDIR = "/home/user/.feedingit"
 
 import logging
-#logger = logging.getLogger(__name__)
+logger = logging.getLogger(__name__)
 
 import debugging
 debugging.init(dot_directory=".feedingit", program_name="feedingit-pyside")
@@ -24,115 +30,40 @@ debugging.init(dot_directory=".feedingit", program_name="feedingit-pyside")
 from cgi import escape
 from re import sub
 
-class FeedWrapper(QtCore.QObject):
-    def __init__(self, key):
-        QtCore.QObject.__init__(self)
-        self._key = key
-    def _name(self):
-        return listing.getFeedTitle(self._key)
-    def _unread(self):
-        return listing.getFeedNumberOfUnreadItems(self._key)
-    def _updatedDate(self):
-        return listing.getFeedUpdateTime(self._key)
-    def _icon(self):
-        return listing.getFavicon(self._key)
-    def _feedid(self):
-        return self._key
-    def _updating(self):
-        return false
-    changed = QtCore.Signal()
-    title = QtCore.Property(unicode, _name, notify=changed)
-    feedid = QtCore.Property(unicode, _feedid, notify=changed)
-    unread = QtCore.Property(unicode, _unread, notify=changed)
-    updatedDate= QtCore.Property(unicode, _updatedDate, notify=changed)
-    icon = QtCore.Property(unicode, _icon, notify=changed)
-    updating = QtCore.Property(unicode, _icon, notify=changed)
-
-class FeedsModel(QtCore.QAbstractListModel):
-    COLUMNS = ('feed', )
-    _category = None
-    def __init__(self):
-        QtCore.QAbstractListModel.__init__(self)
-        self._feeds = listing.getListOfFeeds(self._category)
-        self.setRoleNames(dict(enumerate(FeedsModel.COLUMNS)))
-    def rowCount(self, parent=QtCore.QModelIndex()):
-        return len(self._feeds)
-    def data(self, index, role):
-        if index.isValid() and role == FeedsModel.COLUMNS.index('feed'):
-            print self._feeds[index.row()]
-            return FeedWrapper(self._feeds[index.row()])
-        return None
-
-class ArticleWrapper(QtCore.QObject):
-    def __init__(self, feed,  articleid):
-        QtCore.QObject.__init__(self)
-        self._feed = feed
-        self._articleid = articleid
-    def _name(self):
-        return self.fix_title(self._feed.getTitle(self._articleid))
-    def _unread(self):
-        return str(self._feed.isEntryRead(self._articleid))
-    def _getarticleid(self):
-        return self._articleid
-    def _updatedDate(self):
-        return self._feed.getDateStamp(self._articleid)
-    def _path(self):
-        return self._feed.getContentLink(self._articleid)
-    changed = QtCore.Signal()
-    title = QtCore.Property(unicode, _name, notify=changed)
-    articleid = QtCore.Property(unicode, _getarticleid, notify=changed)
-    unread = QtCore.Property(unicode, _unread, notify=changed)
-    updatedDate= QtCore.Property(unicode, _updatedDate, notify=changed)
-    path = QtCore.Property(unicode, _path, notify=changed)
-
-class ArticlesModel(QtCore.QAbstractListModel):
-    COLUMNS = ('article', )
-    _articles = []
-    _key = None
-    _feed = None
-    def __init__(self,):
-        QtCore.QAbstractListModel.__init__(self)
-        self.setRoleNames(dict(enumerate(ArticlesModel.COLUMNS)))
-        
-    def updateModel(self,  key):
-        self._key = key
-        self._feed = listing.getFeed(self._key)
-        self._articles = self._feed.getIds()
-    def rowCount(self, parent=QtCore.QModelIndex()):
-        print "art " + str(len(self._articles))
-        return len(self._articles)
-    def data(self, index, role):
-        print "data" + str(index) + " " + str(role)
-        if index.isValid() and role == ArticlesModel.COLUMNS.index('article'):
-            return ArticleWrapper(self._articles[index.row()])
-        return None
-
 class Controller(QtCore.QObject):
+    cachedList = None
     
     def __init__(self, listing):
         QtCore.QObject.__init__(self)
         from XmlHandler import XmlHandler
         self._handler = XmlHandler(listing)
+        
+    def update_progress(self, percent_complete,
+                        completed, in_progress, queued,
+                        bytes_downloaded, bytes_updated, bytes_per_second,
+                        feed_updated):
+        total = completed + in_progress + queued
+        root.updateProgress(int(total), int(completed))
+        
+    def articleCountUpdated(self):
+        #print "article updated"
+        pass
+    
+    def update_started(self):
+        root.updateStarted()
+    
+    def update_finished(self):
+        root.updateFinished()
 
     @QtCore.Slot(str,str, result=str)
     def getArticle(self, key, article):
        feed = listing.getFeed(key)
        try:
-          file = open(feed.getContentLink(article))
+          file = codecs.open(feed.getContentLink(article), "r", "utf-8")
           html = file.read().replace("body", "body bgcolor='#ffffff'", 1)
           file.close()
        except:
-          html = "<html><body>Error retrieving article</body></html>"
+          html = u"<html><body>Error retrieving article</body></html>"
        return html
     
     @QtCore.Slot(str, result=str)
@@ -141,8 +72,30 @@ class Controller(QtCore.QObject):
     
     @QtCore.Slot(str,result=str)
     def getArticlesXml(self, key):
+        feed = listing.getFeed(key)
+        self.cachedList = feed.getIds(onlyUnread=True)
         #onlyUnread = arguments.get("onlyUnread","False")
-        return self._handler.generateArticlesXml(key, "False")
+        return self._handler.generateArticlesXml(key, config.getHideReadArticles())
+    
+    @QtCore.Slot(str,str,bool,result=str)
+    def getNextId(self, key, articleid, onlyUnread):
+        if (onlyUnread):
+            #print self.cachedList, articleid
+            index = self.cachedList.index(articleid)
+            return self.cachedList[(index + 1) % len(self.cachedList)]
+        else:
+            feed = listing.getFeed(key)
+            return feed.getNextId(articleid)
+        
+    @QtCore.Slot(str,str,bool,result=str)
+    def getPreviousId(self, key, articleid, onlyUnread):
+        if (onlyUnread):
+            #print self.cachedList, articleid
+            index = self.cachedList.index(articleid)
+            return self.cachedList[(index - 1) % len(self.cachedList)]
+        else:
+            feed = listing.getFeed(key)
+            return feed.getPreviousId(articleid)
     
     @QtCore.Slot(result=str)
     def getCategoryXml(self):
@@ -156,14 +109,19 @@ class Controller(QtCore.QObject):
         
     @QtCore.Slot(str)
     def updateFeed(self, key):
-        print 'updating feed ',  key
         listing.updateFeed(key)
         
     @QtCore.Slot()
     def updateAll(self):
-        for feed in listing.getListOfFeeds("Manual"):
-            listing.updateFeed(feed)
-            
+        for catid in listing.getListOfCategories():
+            for feed in listing.getSortedListOfKeys("Manual", category=catid):
+                listing.updateFeed(feed)
+
+    @QtCore.Slot(str)
+    def updateCategory(self, catid):
+        for feed in listing.getSortedListOfKeys("Manual", category=catid):
+            listing.updateFeed(feed)           
+
     @QtCore.Slot(str,str,str)
     def addFeed(self, title, url, catid):
         listing.addFeed(title,url, category=catid)
@@ -173,9 +131,18 @@ class Controller(QtCore.QObject):
         listing.addCategory(name)
 
     @QtCore.Slot(str)
+    def removeFeed(self, key):
+        listing.removeFeed(key)
+
+    @QtCore.Slot(str)
+    def removeCategory(self, catid):
+        listing.removeCategory(catid)
+
+    @QtCore.Slot(str)
     def markAllAsRead(self, key):
         feed = listing.getFeed(key)
         feed.markAllAsRead()
+        listing.updateUnread(key)
 
     @QtCore.Slot(str, str)
     def setEntryRead(self, key, articleid):
@@ -190,9 +157,121 @@ class Controller(QtCore.QObject):
         if (item == "hideReadArticles"):
             return "False"
         return ""
+    
+    @QtCore.Slot(str, str)
+    def populateFileDialog(self, path, type):
+        import glob
+        import os.path
+        for file in glob.glob(path+type):
+            logger.debug(file)
+            root.addFileNotification(file, os.path.basename(file))
+    
+    @QtCore.Slot(str, result=int)
+    def importOpml(self, filename):
+        from opml_lib import parseOpml
+        file = open(filename, "r")
+        feeds = parseOpml(file.read())
+        file.close()
+        for (title, url) in feeds:
+            listing.addFeed(title, url)
+        return len(feeds)
+    
+    @QtCore.Slot(str, result=str)
+    def exportOpml(self, filename="/home/user/MyDocs/feedingit-export.opml"):
+        logger.debug("ExportOpmlData: %s" % filename)
+        from opml_lib import getOpmlText
+        try:
+            str = getOpmlText(listing)
+            file = open(filename, "w")
+            file.write(str)
+            file.close()
+            return filename
+        except:
+            logger.debug("Error exporting: %s" % filename)
+            return "error"
+        
+    @QtCore.Slot(str, result=bool)
+    def getBooleanSetting(self, setting):
+        if (setting == "theme"):
+            return config.getTheme()
+        elif (setting == "imageCache" ):
+            return config.getImageCache()
+        elif (setting == "hideReadFeeds"):
+            return config.getHideReadFeeds()
+        elif (setting == "hideReadArticles"):
+            return config.getHideReadArticles()
+        elif (setting == "autoupdate"):
+            return config.isAutoUpdateEnabled()
+        else:
+            return 'True'
+        
+    @QtCore.Slot(str, result=int)
+    def getIntSetting(self, setting):
+        if (setting == "artFontSize"):
+            return config.getArtFontSize()
+        elif (setting == "fontSize" ):
+            return config.getFontSize()
+        else:
+            return -1
+        
+    @QtCore.Slot(str, bool)
+    def setBooleanSetting(self, setting, value):
+        if (setting == "theme"):
+            config.setTheme(value)
+        elif (setting == "imageCache" ):
+            config.setImageCache(value)
+        elif (setting == "hideReadFeeds"):
+            config.setHideReadFeeds(value)
+        elif (setting == "hideReadArticles"):
+            config.setHideReadArticles(value)
+        elif (setting == "autoupdate"):
+            config.setAutoUpdateEnabled(value)
+        config.saveConfig()
+        
+    @QtCore.Slot(str, int)
+    def setIntSetting(self, setting, value):
+        if (setting == "artFontSize"):
+            config.setArtFontSize(value)
+        elif (setting == "fontSize" ):
+            config.setFontSize(value)
+        config.saveConfig()
+    
+    @QtCore.Slot(str, str)
+    def openSettings(self):
+        bus = dbus.SessionBus()
+        settingService = bus.get_object('com.nokia.DuiControlPanel', '/')
+        setting = shareService.get_dbus_method('appletPage', 'com.nokia.DuiControlPanelIf')
+        setting("FeedingIt")
 
-def main():
+    @QtCore.Slot(str, str)
+    def share(self, key, articleid):
+        feed = listing.getFeed(key)
+        title = feed.getTitle(articleid)
+        link = feed.getExternalLink(articleid)
+        description = 'Shared%20via%20FeedingIt%20on%20Meego'
+        import urllib
+        bus = dbus.SessionBus()
+        shareService = bus.get_object('com.nokia.ShareUi', '/')
+        share = shareService.get_dbus_method('share', 'com.nokia.maemo.meegotouch.ShareUiInterface')
+        #share([u'data:text/x-url;description=Support%20for%20Nokia%20Developers;title=Forum%20Nokia,http%3A%2F%2Fforum.nokia.com',])
+        share( ['data:text/x-url;title=%s;description=%s,%s' %(urllib.quote(title), description, urllib.quote(link)),] )
+        
+    @QtCore.Slot(str, result=bool)
+    def getFeedEventStatus(self, key):
+        from gconf import client_get_defaults
+        return client_get_default().get_bool('/apps/ControlPanel/FeedingIt/EnableFeed/'+key)
+    
+    @QtCore.Slot(str)
+    def switchEventFeedStatus(self, key):
+        from gconf import client_get_defaults
+        value = client_get_default().get_bool('/apps/ControlPanel/FeedingIt/EventFeed/Hide/'+key)
+        if value:
+            client_get_default().unset('/apps/ControlPanel/FeedingIt/EventFeed/Hide/'+key)
+        else:
+            client_get_default().set_bool('/apps/ControlPanel/FeedingIt/EventFeed/Hide/'+key, True)
+    
 
+def main():
     if not isdir(CONFIGDIR):
         try:
             mkdir(CONFIGDIR)
@@ -217,32 +296,56 @@ def main():
     app = QtGui.QApplication(sys.argv)
     view = QtDeclarative.QDeclarativeView()
 
-    global articlesModel
-    feedsModel = FeedsModel()
-    articlesModel = ArticlesModel()
-    
     controller = Controller(listing)
  
+    # listen on dbus for download update progress
+    bus = dbus.SessionBus()
+    
+    bus.add_signal_receiver(handler_function=controller.update_progress,
+                            bus_name=None,
+                            signal_name='UpdateProgress',
+                            dbus_interface='org.marcoz.feedingit',
+                            path='/org/marcoz/feedingit/update')
+    
+    bus.add_signal_receiver(handler_function=controller.articleCountUpdated,
+                            bus_name=None,
+                            signal_name='ArticleCountUpdated',
+                            dbus_interface='org.marcoz.feedingit',
+                            path='/org/marcoz/feedingit/update')
+    bus.add_signal_receiver(handler_function=controller.update_started,
+                            bus_name=None,
+                            signal_name='UpdateStarted',
+                            dbus_interface='org.marcoz.feedingit',
+                            path='/org/marcoz/feedingit/update')
+    bus.add_signal_receiver(handler_function=controller.update_finished,
+                            bus_name=None,
+                            signal_name='UpdateFinished',
+                            dbus_interface='org.marcoz.feedingit',
+                            path='/org/marcoz/feedingit/update')
+    global root
     rc = view.rootContext()
  
     rc.setContextProperty('controller', controller)
-    rc.setContextProperty('feedsModel', feedsModel)
-    rc.setContextProperty('articlesModel', articlesModel)
 
     # Comment the two lines below if you don't want to use OpenGL for QML rendering or if it is not supported
-    glw = QtOpenGL.QGLWidget()
-    view.setViewport(glw)
+    #glw = QtOpenGL.QGLWidget()
+    #view.setViewport(glw)
 
     if os.path.exists('/usr/share/feedingit/qml'):
+        glw = QtOpenGL.QGLWidget()
+        view.setViewport(glw)
         view.setSource('/usr/share/feedingit/qml/main.qml')
+        view.showFullScreen()
     else:
-        #view.setSource(os.path.join('qml','main.qml'))
-        view.setSource(os.path.join('qml','FeedingIt.qml'))
+        view.setSource(os.path.join('qml','main.qml'))
+        view.show()
+        #view.setSource(os.path.join('qml','FeedingIt.qml'))
+    root = view.rootObject()
 
     #view.showFullScreen()
-    view.show()
+    #view.show()
     sys.exit(app.exec_())
 
-if __name__ == "__main__":
-    
+if __name__ == "__main__": 
     main()