Changes to the config system API to make it more flexible and lightweight, code clean up.
[straw.git] / straw / Config.py
blobee8f9fc2761ef088b6d9de11e0956bcc495a9574
1 """ Config.py
3 Module for Straw's configuration settings.
4 """
5 __copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc."
6 __license__ = """ GNU General Public License
8 This program is free software; you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 2 of the License, or (at your option) any later
11 version.
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along with
18 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 Place - Suite 330, Boston, MA 02111-1307, USA. """
21 from ConfigOptions import *
22 from error import log, logtb, logparam
23 import gconf
24 import gobject
25 import os
26 import pygtk
27 import urllib
28 pygtk.require('2.0')
30 GCONF_STRAW_ROOT = "/apps/straw"
32 # straw's home directory
33 def straw_home():
34 home = os.getenv('HOME')
35 if not home:
36 home = os.path.expanduser('~')
37 return os.path.join(home, '.straw')
39 def ensure_directory(strawdir):
40 if os.path.exists(strawdir):
41 if not os.path.isdir(strawdir):
42 raise Exception
43 return 0
44 os.mkdir(strawdir)
45 return 1
47 class ConfigGConfPersistence:
48 SAVERS = {OPTION_LAST_POLL: 'int',
49 OPTION_ITEMS_STORED: 'int',
50 OPTION_ITEM_ORDER: 'bool',
51 OPTION_BROWSER_CMD: 'string',
52 OPTION_WINDOW_SIZE_W: 'int',
53 OPTION_WINDOW_SIZE_H: 'int',
54 OPTION_MAIN_PANE_POS: 'int',
55 OPTION_SUB_PANE_POS: 'int',
56 OPTION_OFFLINE: 'bool',
57 OPTION_WINDOW_MAX: 'bool',
58 OPTION_MAGNIFICATION: 'float',
59 OPTION_POLL_FREQUENCY: 'int',
60 OPTION_PANE_LAYOUT: 'string',
63 def __init__(self, client):
64 self.client = client
66 def save_option(self, option, value):
67 getattr(self.client, 'set_' + self.SAVERS[option])(
68 GCONF_STRAW_ROOT + option, value)
70 def load_option(self, option):
71 return getattr(self.client, 'get_' + self.SAVERS[option])(
72 GCONF_STRAW_ROOT + option)
74 class ConfigPersistence:
75 def __init__(self, *backends):
76 self.backends = backends
78 def save_option(self, option, value):
79 for b in self.backends:
80 if option in b[1]:
81 b[0].save_option(option, value)
83 def load_option(self, option):
84 for b in self.backends:
85 if option in b[1]:
86 return b[0].load_option(option)
88 class ProxyConfig(object):
89 def __init__(self):
90 self._active = False
91 self._host = None
92 self._port = None
93 self._auth = None
94 self._username = None
95 self._password = None
97 @apply
98 def active():
99 doc = "this will be true when one of the subclasses is used"
100 def fget(self):
101 return self._active
102 def fset(self, active):
103 self._active = active
104 return property(**locals())
106 @apply
107 def host():
108 doc = "the host name where the proxy server lives"
109 def fget(self):
110 return self._host
111 def fset(self, host):
112 self._host = host
113 return property(**locals())
115 @apply
116 def port():
117 doc = "the port of the proxy server to connect to"
118 def fget(self):
119 return self._port
120 def fset(self, port):
121 self._port = port
122 return property(**locals())
124 @apply
125 def auth():
126 doc = "true if we need to authenticate to the proxy server"
127 def fget(self):
128 return self._auth
129 def fset(self, isauth):
130 self._auth = isauth
131 return property(**locals())
133 @apply
134 def username():
135 doc = "the username to use when authenticating to the proxy"
136 def fget(self):
137 return self._username
138 def fset(self, username):
139 self._username = username
140 return property(**locals())
142 @apply
143 def password():
144 doc = "the password to use when authenticating to the proxy"
145 def fget(self):
146 return self._password
147 def fset(self, password):
148 self._password = password
149 return property(**locals())
152 class GconfProxyConfig(ProxyConfig):
153 """Encapsulate proxy use and location information (host, port, ip),
154 gconf reading and name lookup logic"""
156 GCONF_HTTP_PROXY = "/system/http_proxy"
157 GCONF_HTTP_PROXY_USE = GCONF_HTTP_PROXY + "/use_http_proxy"
158 GCONF_HTTP_PROXY_HOST = GCONF_HTTP_PROXY + "/host"
159 GCONF_HTTP_PROXY_PORT = GCONF_HTTP_PROXY + "/port"
160 GCONF_HTTP_PROXY_AUTHENTICATION = GCONF_HTTP_PROXY + "/use_authentication"
161 GCONF_HTTP_PROXY_USER = GCONF_HTTP_PROXY + "/authentication_user"
162 GCONF_HTTP_PROXY_PASSWORD = GCONF_HTTP_PROXY + "/authentication_password"
164 def __init__(self):
165 ProxyConfig.__init__(self)
166 client = gconf.client_get_default()
167 self.active = client.dir_exists(self.GCONF_HTTP_PROXY)
168 if not self.active:
169 return
171 client.add_dir(self.GCONF_HTTP_PROXY, gconf.CLIENT_PRELOAD_RECURSIVE)
172 client.notify_add(self.GCONF_HTTP_PROXY_USE, self.proxy_mode_changed)
173 client.notify_add(self.GCONF_HTTP_PROXY_HOST, self.proxy_host_changed)
174 client.notify_add(self.GCONF_HTTP_PROXY_PORT, self.proxy_port_changed)
175 client.notify_add(self.GCONF_HTTP_PROXY_AUTHENTICATION, self.proxy_auth_changed)
176 client.notify_add(self.GCONF_HTTP_PROXY_USER, self.proxy_auth_username_changed)
177 client.notify_add(self.GCONF_HTTP_PROXY_PASSWORD, self.proxy_auth_password_changed)
179 self.active = client.get_bool(self.GCONF_HTTP_PROXY_USE)
180 self.host = client.get_string(self.GCONF_HTTP_PROXY_HOST)
181 self.port = client.get_int(self.GCONF_HTTP_PROXY_PORT)
182 self.auth = client.get_bool(self.GCONF_HTTP_PROXY_AUTHENTICATION)
183 if self.auth:
184 self.username = client.get_string(self.GCONF_HTTP_PROXY_USER)
185 self.password = client.get_string(self.GCONF_HTTP_PROXY_PASSWORD)
188 # here be gconf logic
189 def proxy_mode_changed(self, client, notify_id, entry, *args):
190 self.active = entry.value.get_bool()
192 def proxy_host_changed(self, client, notify_id, entry, *args):
193 value = entry.value.get_string()
194 if value:
195 self.host = value
196 else:
197 self.active = False
199 def proxy_port_changed(self, client, notify_id, entry, *args):
200 value = entry.value.get_int()
201 if value:
202 self.port = value
203 else:
204 self.active = False
206 def proxy_auth_changed(self, client, notify_id, entry, *args):
207 value = entry.value.get_bool()
208 if value:
209 self.auth = value
211 def proxy_auth_username_changed(self, client, notify_id, entry, *args):
212 value = entry.value.get_string()
213 self.username = value
215 def proxy_auth_password_changed(self, client, notify_id, entry, *args):
216 value = entry.value.get_string()
217 self.password = value
219 class EnvironmentProxyConfig(ProxyConfig):
220 """Encapsulate proxy use and location information, environment reading"""
222 def __init__(self):
223 ProxyConfig.__init__(self)
224 self._read_env()
226 def _read_env(self):
227 proxy = None
228 proxies = urllib.getproxies()
229 if not proxies:
230 return
232 for key, value in proxies.iteritems():
233 proxy = proxies.get(key)
234 user, authority = urllib.splituser(proxy)
235 if authority:
236 self.host, self.port = urllib.splitport(authority)
237 self.active = True
238 if user:
239 self.username, self.password = urllib.splitpasswd(user)
240 self.auth = True
241 return
243 class Config(gobject.GObject):
244 __gsignals__ = {
245 'item-order-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
246 'offline-mode-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
247 'refresh-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
248 'item-stored-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())
251 def __init__(self, persistence, defaults):
252 gobject.GObject.__init__(self)
254 self._defaults = defaults
255 self._options = defaults
256 self.persistence = persistence
258 self._apply_defaults()
260 def _apply_defaults(self):
261 pass
263 def initialize_proxy(self):
264 # EnvironmentProxy has precedence
265 self._proxy = EnvironmentProxyConfig()
266 if not self._proxy.active:
267 # .. defaults to GConfProxyConfig so we can listen for network
268 # setting changes (e.g, changes in network preference)
269 self._proxy = GconfProxyConfig()
271 def initialize_options(self):
272 # Call this after calling Config's constructor
273 self.first_time = ensure_directory(straw_home())
275 self._poll_freq = self.persistence.load_option(OPTION_POLL_FREQUENCY)
276 self._last_poll = self.persistence.load_option(OPTION_LAST_POLL)
277 self._items_stored = self.persistence.load_option(OPTION_ITEMS_STORED)
278 self._browser_cmd = self.persistence.load_option(OPTION_BROWSER_CMD)
279 self._item_order = self.persistence.load_option(OPTION_ITEM_ORDER)
281 if not self._poll_freq:
282 self.poll_frequency = 1800
283 if not self._items_stored:
284 self.number_of_items_stored = 30
285 if not self._item_order:
286 self.item_order = True
288 width = self.persistence.load_option(OPTION_WINDOW_SIZE_W)
289 height = self.persistence.load_option(OPTION_WINDOW_SIZE_H)
290 if not width:
291 width = 640
292 if not height:
293 height = 480
294 self._main_window_size = (width, height)
296 self._main_pane_position = self.persistence.load_option(OPTION_MAIN_PANE_POS)
297 self._sub_pane_position = self.persistence.load_option(OPTION_SUB_PANE_POS)
298 if not self._main_pane_position:
299 self._main_pane_position = 100
300 if not self._sub_pane_position:
301 self._sub_pane_position = 100
303 self._window_maximized = self.persistence.load_option(OPTION_WINDOW_MAX)
304 self._text_magnification = self.persistence.load_option(OPTION_MAGNIFICATION)
305 self._offline = self.persistence.load_option(OPTION_OFFLINE)
306 self._pane_layout = self.persistence.load_option(OPTION_PANE_LAYOUT)
308 def get(self, key):
309 if self._options.has_key(key) and self._options[key]:
310 return self._options[key]
311 else:
312 return self._defaults[key]
314 def set(self, key, value):
315 if self._options.has_key(key) and self._options[key] != value:
316 self.persistence.save_option(key, value)
318 def create_gconf_persistence():
319 client = gconf.client_get_default()
320 client.add_dir(GCONF_STRAW_ROOT, gconf.CLIENT_PRELOAD_ONELEVEL)
321 return ConfigGConfPersistence(client)
323 def create_instance():
324 defaults = config_options_defaults
326 cp = ConfigPersistence((create_gconf_persistence(), defaults.keys()))
327 config = Config(cp, defaults)
329 config.initialize_proxy()
330 config.initialize_options()
332 return config
334 config_instance = None
336 def _get_instance():
337 global config_instance
339 if not config_instance:
340 config_instance = create_instance()
342 return config_instance
344 def get(key):
345 config = _get_instance()
346 return config.get(key)
348 def set(key, value):
349 config = _get_instance()
350 return config.set(key, value)