psa: improve selection of items not to be displayed on event feed
[feedingit] / psa_harmattan / feedingit / pysrc / feedingit.py
1 #!/usr/bin/python
2
3 import sys
4
5 from PySide import QtGui
6 from PySide import QtDeclarative
7 import os
8 from os import mkdir, remove, stat, environ
9 from os.path import isfile, isdir, exists
10 import codecs
11 import dbus
12 # import python dbus GLib mainloop support
13 import dbus.mainloop.glib
14 # Enable glib main loop support
15 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
16
17 # Comment the line below if you don't want to use OpenGL for QML rendering or if it is not supported
18 from PySide import QtOpenGL,  QtCore
19
20 from rss_sqlite import Listing
21 CONFIGDIR = environ.get("HOME", "/home/user") + "/.feedingit/"
22 #CONFIGDIR = "/home/user/.feedingit"
23
24 import logging
25 logger = logging.getLogger(__name__)
26
27 import debugging
28 debugging.init(dot_directory=".feedingit", program_name="feedingit-pyside")
29
30 from cgi import escape
31 from re import sub
32
33 class Controller(QtCore.QObject):
34     cachedList = None
35     
36     def __init__(self, listing):
37         QtCore.QObject.__init__(self)
38         from XmlHandler import XmlHandler
39         self._handler = XmlHandler(listing)
40         
41     def update_progress(self, percent_complete,
42                         completed, in_progress, queued,
43                         bytes_downloaded, bytes_updated, bytes_per_second,
44                         feed_updated):
45         total = completed + in_progress + queued
46         root.updateProgress(int(total), int(completed))
47         
48     def articleCountUpdated(self):
49         #print "article updated"
50         pass
51     
52     def update_started(self):
53         root.updateStarted()
54     
55     def update_finished(self):
56         root.updateFinished()
57
58     @QtCore.Slot(str,str, result=str)
59     def getArticle(self, key, article):
60        feed = listing.getFeed(key)
61        try:
62           file = codecs.open(feed.getContentLink(article), "r", "utf-8")
63           html = file.read().replace("body", "body bgcolor='#ffffff'", 1)
64           file.close()
65        except:
66           html = u"<html><body>Error retrieving article</body></html>"
67        return html
68     
69     @QtCore.Slot(str, result=str)
70     def getFeedsXml(self, catid):
71         return self._handler.generateFeedsXml(catid)
72     
73     @QtCore.Slot(str,result=str)
74     def getArticlesXml(self, key):
75         feed = listing.getFeed(key)
76         self.cachedList = feed.getIds(onlyUnread=True)
77         #onlyUnread = arguments.get("onlyUnread","False")
78         return self._handler.generateArticlesXml(key, config.getHideReadArticles())
79     
80     @QtCore.Slot(str,str,bool,result=str)
81     def getNextId(self, key, articleid, onlyUnread):
82         if (onlyUnread):
83             #print self.cachedList, articleid
84             index = self.cachedList.index(articleid)
85             return self.cachedList[(index + 1) % len(self.cachedList)]
86         else:
87             feed = listing.getFeed(key)
88             return feed.getNextId(articleid)
89         
90     @QtCore.Slot(str,str,bool,result=str)
91     def getPreviousId(self, key, articleid, onlyUnread):
92         if (onlyUnread):
93             #print self.cachedList, articleid
94             index = self.cachedList.index(articleid)
95             return self.cachedList[(index - 1) % len(self.cachedList)]
96         else:
97             feed = listing.getFeed(key)
98             return feed.getPreviousId(articleid)
99     
100     @QtCore.Slot(result=str)
101     def getCategoryXml(self):
102         return self._handler.generateCategoryXml()
103     
104     @QtCore.Slot(QtCore.QObject)
105     def feedClicked(self, wrapper):
106         #print 'User clicked on:', wrapper._key
107         #articlesModel.updateModel(wrapper._key)
108         pass
109         
110     @QtCore.Slot(str)
111     def updateFeed(self, key):
112         listing.updateFeed(key)
113         
114     @QtCore.Slot()
115     def updateAll(self):
116         for catid in listing.getListOfCategories():
117             for feed in listing.getSortedListOfKeys("Manual", category=catid):
118                 listing.updateFeed(feed)
119
120     @QtCore.Slot(str)
121     def updateCategory(self, catid):
122         for feed in listing.getSortedListOfKeys("Manual", category=catid):
123             listing.updateFeed(feed)           
124
125     @QtCore.Slot(str,str,str)
126     def addFeed(self, title, url, catid):
127         listing.addFeed(title,url, category=catid)
128         
129     @QtCore.Slot(str)
130     def addCategory(self, name):
131         listing.addCategory(name)
132
133     @QtCore.Slot(str)
134     def removeFeed(self, key):
135         listing.removeFeed(key)
136
137     @QtCore.Slot(str)
138     def removeCategory(self, catid):
139         listing.removeCategory(catid)
140
141     @QtCore.Slot(str)
142     def markAllAsRead(self, key):
143         feed = listing.getFeed(key)
144         feed.markAllAsRead()
145         listing.updateUnread(key)
146
147     @QtCore.Slot(str, str)
148     def setEntryRead(self, key, articleid):
149         feed = listing.getFeed(key)
150         feed.setEntryRead(articleid)
151         listing.updateUnread(key)
152
153     @QtCore.Slot(str, result=str)
154     def getConfig(self, item):
155         if (item == "hideReadFeed"):
156             return "True"
157         if (item == "hideReadArticles"):
158             return "False"
159         return ""
160     
161     @QtCore.Slot(str, str)
162     def populateFileDialog(self, path, type):
163         import glob
164         import os.path
165         for file in glob.glob(path+type):
166             logger.debug(file)
167             root.addFileNotification(file, os.path.basename(file))
168     
169     @QtCore.Slot(str, result=int)
170     def importOpml(self, filename):
171         from opml_lib import parseOpml
172         file = open(filename, "r")
173         feeds = parseOpml(file.read())
174         file.close()
175         for (title, url) in feeds:
176             listing.addFeed(title, url)
177         return len(feeds)
178     
179     @QtCore.Slot(str, result=str)
180     def exportOpml(self, filename="/home/user/MyDocs/feedingit-export.opml"):
181         logger.debug("ExportOpmlData: %s" % filename)
182         from opml_lib import getOpmlText
183         try:
184             str = getOpmlText(listing)
185             file = open(filename, "w")
186             file.write(str)
187             file.close()
188             return filename
189         except:
190             logger.debug("Error exporting: %s" % filename)
191             return "error"
192         
193     @QtCore.Slot(str, result=bool)
194     def getBooleanSetting(self, setting):
195         if (setting == "theme"):
196             return config.getTheme()
197         elif (setting == "imageCache" ):
198             return config.getImageCache()
199         elif (setting == "hideReadFeeds"):
200             return config.getHideReadFeeds()
201         elif (setting == "hideReadArticles"):
202             return config.getHideReadArticles()
203         elif (setting == "autoupdate"):
204             return config.isAutoUpdateEnabled()
205         else:
206             return 'True'
207         
208     @QtCore.Slot(str, result=int)
209     def getIntSetting(self, setting):
210         if (setting == "artFontSize"):
211             return config.getArtFontSize()
212         elif (setting == "fontSize" ):
213             return config.getFontSize()
214         else:
215             return -1
216         
217     @QtCore.Slot(str, bool)
218     def setBooleanSetting(self, setting, value):
219         if (setting == "theme"):
220             config.setTheme(value)
221         elif (setting == "imageCache" ):
222             config.setImageCache(value)
223         elif (setting == "hideReadFeeds"):
224             config.setHideReadFeeds(value)
225         elif (setting == "hideReadArticles"):
226             config.setHideReadArticles(value)
227         elif (setting == "autoupdate"):
228             config.setAutoUpdateEnabled(value)
229         config.saveConfig()
230         
231     @QtCore.Slot(str, int)
232     def setIntSetting(self, setting, value):
233         if (setting == "artFontSize"):
234             config.setArtFontSize(value)
235         elif (setting == "fontSize" ):
236             config.setFontSize(value)
237         config.saveConfig()
238     
239     @QtCore.Slot(str, str)
240     def openSettings(self):
241         bus = dbus.SessionBus()
242         settingService = bus.get_object('com.nokia.DuiControlPanel', '/')
243         setting = shareService.get_dbus_method('appletPage', 'com.nokia.DuiControlPanelIf')
244         setting("FeedingIt")
245
246     @QtCore.Slot(str, str)
247     def share(self, key, articleid):
248         feed = listing.getFeed(key)
249         title = feed.getTitle(articleid)
250         link = feed.getExternalLink(articleid)
251         description = 'Shared%20via%20FeedingIt%20on%20Meego'
252         import urllib
253         bus = dbus.SessionBus()
254         shareService = bus.get_object('com.nokia.ShareUi', '/')
255         share = shareService.get_dbus_method('share', 'com.nokia.maemo.meegotouch.ShareUiInterface')
256         #share([u'data:text/x-url;description=Support%20for%20Nokia%20Developers;title=Forum%20Nokia,http%3A%2F%2Fforum.nokia.com',])
257         share( ['data:text/x-url;title=%s;description=%s,%s' %(urllib.quote(title), description, urllib.quote(link)),] )
258         
259     @QtCore.Slot(str, result=bool)
260     def getFeedEventStatus(self, key):
261         from gconf import client_get_default
262         return client_get_default().get_bool('/apps/ControlPanel/FeedingIt/EventFeed/Hide/'+key)
263     
264     @QtCore.Slot(str)
265     def switchEventFeedStatus(self, key):
266         from gconf import client_get_default
267         value = client_get_default().get_bool('/apps/ControlPanel/FeedingIt/EventFeed/Hide/'+key)
268         if value:
269             client_get_default().unset('/apps/ControlPanel/FeedingIt/EventFeed/Hide/'+key)
270         else:
271             client_get_default().set_bool('/apps/ControlPanel/FeedingIt/EventFeed/Hide/'+key, True)
272     
273
274 def main():
275     if not isdir(CONFIGDIR):
276         try:
277             mkdir(CONFIGDIR)
278         except:
279             logger.error("Error: Can't create configuration directory")
280             from sys import exit
281             exit(1)
282             
283     from config import Config
284     global config
285     config = Config(None,CONFIGDIR+"config.ini")
286
287     global listing
288     listing = Listing(config, CONFIGDIR)
289     
290     import mainthread
291     mainthread.init()
292
293     from jobmanager import JobManager
294     JobManager(True)
295
296     app = QtGui.QApplication(sys.argv)
297     view = QtDeclarative.QDeclarativeView()
298
299     controller = Controller(listing)
300  
301     # listen on dbus for download update progress
302     bus = dbus.SessionBus()
303     
304     bus.add_signal_receiver(handler_function=controller.update_progress,
305                             bus_name=None,
306                             signal_name='UpdateProgress',
307                             dbus_interface='org.marcoz.feedingit',
308                             path='/org/marcoz/feedingit/update')
309     
310     bus.add_signal_receiver(handler_function=controller.articleCountUpdated,
311                             bus_name=None,
312                             signal_name='ArticleCountUpdated',
313                             dbus_interface='org.marcoz.feedingit',
314                             path='/org/marcoz/feedingit/update')
315     bus.add_signal_receiver(handler_function=controller.update_started,
316                             bus_name=None,
317                             signal_name='UpdateStarted',
318                             dbus_interface='org.marcoz.feedingit',
319                             path='/org/marcoz/feedingit/update')
320     bus.add_signal_receiver(handler_function=controller.update_finished,
321                             bus_name=None,
322                             signal_name='UpdateFinished',
323                             dbus_interface='org.marcoz.feedingit',
324                             path='/org/marcoz/feedingit/update')
325  
326     global root
327     rc = view.rootContext()
328  
329     rc.setContextProperty('controller', controller)
330
331     # Comment the two lines below if you don't want to use OpenGL for QML rendering or if it is not supported
332     #glw = QtOpenGL.QGLWidget()
333     #view.setViewport(glw)
334
335     if os.path.exists('/usr/share/feedingit/qml'):
336         glw = QtOpenGL.QGLWidget()
337         view.setViewport(glw)
338         view.setSource('/usr/share/feedingit/qml/main.qml')
339         view.showFullScreen()
340     else:
341         view.setSource(os.path.join('qml','main.qml'))
342         view.show()
343         #view.setSource(os.path.join('qml','FeedingIt.qml'))
344     root = view.rootObject()
345
346     #view.showFullScreen()
347     #view.show()
348     sys.exit(app.exec_())
349
350 if __name__ == "__main__": 
351     main()