5b28e2dfab9ff9cefe90ab6951fb631034dfa993
[feedingit] / src / config.py
1 #!/usr/bin/env python2.5
2
3
4 # Copyright (c) 2007-2008 INdT.
5 # Copyright (c) 2011 Neal H. Walfield.
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU Lesser General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 #  This program is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #  GNU Lesser General Public License for more details.
15 #
16 #  You should have received a copy of the GNU Lesser General Public License
17 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19
20 # ============================================================================
21 # Name        : FeedingIt.py
22 # Author      : Yves Marcoz
23 # Version     : 0.6.1
24 # Description : Simple RSS Reader
25 # ============================================================================
26 #try:
27 #    import gtk
28 #    import hildon
29 #    from gobject import idle_add
30 #except:
31 #    pass
32
33 from ConfigParser import RawConfigParser
34 from gconf import client_get_default
35 from urllib2 import ProxyHandler
36 from mainthread import mainthread
37 import logging
38 logger = logging.getLogger(__name__)
39
40 VERSION = "52"
41
42 section = "FeedingIt"
43 ranges = { "updateInterval":[0.5, 1, 2, 4, 8, 12, 24], "expiry":[24, 48, 72, 144, 288], "fontSize":range(12,24), "orientation":["Automatic", "Landscape", "Portrait"], "artFontSize":[10, 12, 14, 16, 18, 20], "feedsort":["Manual", "Most unread", "Least unread", "Most recent", "Least recent"] }
44 titles = {"updateInterval":"Auto-update interval", "expiry":"Delete articles", "fontSize":"List font size", "orientation":"Display orientation", "artFontSize":"Article font size","feedsort":"Feed sort order"}
45 subtitles = {"updateInterval":"Every %s hours", "expiry":"After %s hours", "fontSize":"%s pixels", "orientation":"%s", "artFontSize":"%s pixels", "feedsort":"%s"}
46
47 class Config():
48     def __init__(self, parent, configFilename):
49         self.configFilename = configFilename
50         self.parent = parent
51         # Load config
52         self.loadConfig()
53
54         # Backup current settings for later restore
55         self.config_backup = dict(self.config)
56         self.do_restore_backup = True
57
58     def on_save_button_clicked(self, button):
59         self.do_restore_backup = False
60         self.window.destroy()
61
62     def createDialog(self):
63         import gtk
64         import hildon
65         from gobject import idle_add
66         self.window = gtk.Dialog("Settings", self.parent)
67         self.window.set_geometry_hints(min_height=600)
68
69         save_button = self.window.add_button(gtk.STOCK_SAVE, gtk.RESPONSE_OK)
70         save_button.connect('clicked', self.on_save_button_clicked)
71         #self.window.set_default_size(-1, 600)
72         panArea = hildon.PannableArea()
73         
74         vbox = gtk.VBox(False, 2)
75         self.buttons = {}
76
77         def heading(text):
78             l = gtk.Label()
79             l.set_size_request(-1, 6)
80             vbox.pack_start(l, expand=False)
81             vbox.pack_start(gtk.Frame(text), expand=False)
82
83         def add_setting(setting):
84             picker = hildon.PickerButton(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
85             selector = self.create_selector(ranges[setting], setting)
86             picker.set_selector(selector)
87             picker.set_title(titles[setting])
88             picker.set_text(titles[setting], subtitles[setting] % self.config[setting])
89             picker.set_name('HildonButton-finger')
90             picker.set_alignment(0,0,1,1)
91             self.buttons[setting] = picker
92             vbox.pack_start(picker, expand=False)
93
94         button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
95         button.set_label("View Known Issues and Tips")
96         button.connect("clicked", self.button_tips_clicked)
97         button.set_alignment(0,0,1,1)
98         vbox.pack_start(button, expand=False)  
99
100         heading('Display')
101         add_setting('fontSize')
102         add_setting('artFontSize')
103         add_setting('orientation')
104         add_setting('feedsort')
105         button = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
106         button.set_label("Hide read feeds")
107         button.set_active(self.config["hidereadfeeds"])
108         button.connect("toggled", self.button_toggled, "hidereadfeeds")
109         vbox.pack_start(button, expand=False)
110
111         button = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
112         button.set_label("Hide read articles")
113         button.set_active(self.config["hidereadarticles"])
114         button.connect("toggled", self.button_toggled, "hidereadarticles")
115         vbox.pack_start(button, expand=False)
116
117
118         heading('Updating')
119         button = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
120         button.set_label("Time-Based Automatic Update\n"
121                          + "(requires use of FeedingIt widget)")
122         button.set_active(self.config["autoupdate"])
123         button.connect("toggled", self.button_toggled, "autoupdate")
124         vbox.pack_start(button, expand=False)
125         button = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
126         button.set_label("Woodchuck-Based Automatic Update")
127         button.set_active(self.config["woodchuck"])
128         button.connect("toggled", self.button_toggled, "woodchuck")
129         vbox.pack_start(button, expand=False)
130
131         try:
132             import woodchuck
133             woodchuck_installed = True
134         except ImportError:
135             woodchuck_installed = False
136
137         if not woodchuck_installed:
138             def install_woodchuck_clicked(button):
139                 from FeedingIt import open_in_browser
140                 open_in_browser("http://maemo.org/downloads/product/raw/Maemo5/murmeltier?get_installfile")
141
142             button = hildon.Button(gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
143             button.set_label("Install Woodchuck")
144             button.connect("clicked", install_woodchuck_clicked)
145             button.set_alignment(0,0,1,1)
146             vbox.pack_start(button, expand=False)
147
148         add_setting('updateInterval')
149         add_setting('expiry')
150
151         heading('Network')
152         button = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
153         button.set_label('Cache images')
154         button.set_active(self.config["imageCache"])
155         button.connect("toggled", self.button_toggled, "imageCache")
156         vbox.pack_start(button, expand=False)
157
158         button = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
159         button.set_label("Use HTTP proxy")
160         button.set_active(self.config["proxy"])
161         button.connect("toggled", self.button_toggled, "proxy")
162         vbox.pack_start(button, expand=False)
163         
164         button = hildon.CheckButton(gtk.HILDON_SIZE_FINGER_HEIGHT)
165         button.set_label('Open links in external browser')
166         button.set_active(self.config["extBrowser"])
167         button.connect("toggled", self.button_toggled, "extBrowser")
168         vbox.pack_start(button, expand=False)
169         
170         panArea.add_with_viewport(vbox)
171         
172         self.window.vbox.add(panArea)
173         self.window.connect("destroy", self.onExit)
174         #self.window.add(self.vbox)
175         self.window.set_default_size(-1, 600)
176         self.window.show_all()
177         return self.window
178
179     def button_tips_clicked(self, *widget):
180         import dbus
181         bus = dbus.SessionBus()
182         proxy = bus.get_object("com.nokia.osso_browser", "/com/nokia/osso_browser/request")
183         iface = dbus.Interface(proxy, 'com.nokia.osso_browser')
184         iface.open_new_window("http://feedingit.marcoz.org/news/?page_id=%s" % VERSION)
185
186     def onExit(self, *widget):
187         # When the dialog is closed without hitting
188         # the "Save" button, restore the configuration
189         if self.do_restore_backup:
190             logger.debug('Restoring configuration')
191             self.config = self.config_backup
192
193         self.saveConfig()
194         self.window.destroy()
195
196     def button_toggled(self, widget, configName):
197         #print "widget", widget.get_active()
198         if (widget.get_active()):
199             self.config[configName] = True
200         else:
201             self.config[configName] = False
202         #print "autoup",  self.autoupdate
203
204         if configName == 'woodchuck':
205             try:
206                 from wc import wc_disable_set
207                 wc_disable_set(not self.config['woodchuck'])
208             except Exception:
209                 logger.exception("Disabling Woodchuck")
210
211         self.saveConfig()
212         
213     def selection_changed(self, selector, button, setting):
214         from gobject import idle_add
215         current_selection = selector.get_current_text()
216         if current_selection:
217             self.config[setting] = current_selection
218         idle_add(self.updateButton, setting)
219         self.saveConfig()
220         
221     def updateButton(self, setting):
222         self.buttons[setting].set_text(titles[setting], subtitles[setting] % self.config[setting])
223         
224     def loadConfig(self):
225         self.config = {}
226
227         configParser = RawConfigParser()
228         try:
229             configParser.read(self.configFilename)
230         except Exception:
231             logger.exception("Reading %s", self.configFilename)
232
233         # The function to use to fetch the parameter, the parameter's
234         # name and the default value.
235         values = ((configParser.getint, "fontSize", 17),
236                   (configParser.getint, "artFontSize", 14),
237                   (configParser.getint, "expiry", 24),
238                   (configParser.getboolean, "autoupdate", False),
239                   (configParser.getboolean, "woodchuck", True),
240                   (configParser.getint, "updateInterval", 4),
241                   (configParser.get, "orientation", "Automatic"),
242                   (configParser.getboolean, "imageCache", False),
243                   (configParser.getboolean, "proxy", True),
244                   (configParser.getboolean, "hidereadfeeds", False),
245                   (configParser.getboolean, "hidereadarticles", False),
246                   (configParser.getboolean, "extBrowser", False),
247                   (configParser.get, "feedsort", "Manual"))
248
249         for fetcher, name, default in values:
250             try:
251                 v = fetcher(section, name)
252             except Exception:
253                 logger.exception("Reading config variable %s", name)
254                 v = default
255             self.config[name] = v
256
257     def saveConfig(self):
258         configParser = RawConfigParser()
259         configParser.add_section(section)
260         configParser.set(section, 'fontSize', str(self.config["fontSize"]))
261         configParser.set(section, 'artFontSize', str(self.config["artFontSize"]))
262         configParser.set(section, 'expiry', str(self.config["expiry"]))
263         configParser.set(section, 'autoupdate', str(self.config["autoupdate"]))
264         configParser.set(section, 'updateInterval', str(self.config["updateInterval"]))
265         configParser.set(section, 'woodchuck', str(self.config["woodchuck"]))
266         configParser.set(section, 'orientation', str(self.config["orientation"]))
267         configParser.set(section, 'imageCache', str(self.config["imageCache"]))
268         configParser.set(section, 'proxy', str(self.config["proxy"]))
269         configParser.set(section, 'hidereadfeeds', str(self.config["hidereadfeeds"]))
270         configParser.set(section, 'hidereadarticles', str(self.config["hidereadarticles"]))
271         configParser.set(section, 'extBrowser', str(self.config["extBrowser"]))
272         configParser.set(section, 'feedsort', str(self.config["feedsort"]))
273
274         # Writing our configuration file
275         file = open(self.configFilename, 'wb')
276         configParser.write(file)
277         file.close()
278
279     def create_selector(self, choices, setting):
280         import gtk
281         import hildon
282         from gobject import idle_add
283         #self.pickerDialog = hildon.PickerDialog(self.parent)
284         selector = hildon.TouchSelector(text=True)
285         index = 0
286         for item in choices:
287             iter = selector.append_text(str(item))
288             if str(self.config[setting]) == str(item): 
289                 selector.set_active(0, index)
290             index += 1
291         selector.connect("changed", self.selection_changed, setting)
292         #self.pickerDialog.set_selector(selector)
293         return selector
294         #self.pickerDialog.show_all()
295
296     def getFontSize(self):
297         return self.config["fontSize"]
298     def getArtFontSize(self):
299         return self.config["artFontSize"]
300     def getExpiry(self):
301         return self.config["expiry"]
302     def isAutoUpdateEnabled(self):
303         return self.config["autoupdate"]
304     def getWoodchuckEnabled(self):
305         return self.config["woodchuck"]
306     def getUpdateInterval(self):
307         return float(self.config["updateInterval"])
308     def getReadFont(self):
309         return "sans italic %s" % self.config["fontSize"]
310     def getUnreadFont(self):
311         return "sans %s" % self.config["fontSize"]
312     def getOrientation(self):
313         return ranges["orientation"].index(self.config["orientation"])
314     def getImageCache(self):
315         return self.config["imageCache"]
316     @mainthread
317     def getProxy(self):
318         if self.config["proxy"] == False:
319             return (False, None)
320         if client_get_default().get_bool('/system/http_proxy/use_http_proxy'):
321             port = client_get_default().get_int('/system/http_proxy/port')
322             http = client_get_default().get_string('/system/http_proxy/host')
323             proxy = ProxyHandler( {"http":"http://%s:%s/"% (http,port)} )
324             return (True, proxy)
325         return (False, None)
326     def getHideReadFeeds(self):
327         return self.config["hidereadfeeds"]
328     def getHideReadArticles(self):
329         return self.config["hidereadarticles"]
330     def getOpenInExternalBrowser(self):
331         return self.config["extBrowser"]
332     def getFeedSortOrder(self):
333         return self.config["feedsort"]