Package screenlets :: Module backend
[hide private]
[frames] | no frames]

Source Code for Module screenlets.backend

  1  # This application is released under the GNU General Public License  
  2  # v3 (or, at your option, any later version). You can find the full  
  3  # text of the license under http://www.gnu.org/licenses/gpl.txt.  
  4  # By using, editing and/or distributing this software you agree to  
  5  # the terms and conditions of this license.  
  6  # Thank you for using free software! 
  7  # 
  8  # screenlets.backend (c) RYX (aka Rico Pfaus) 2007 <ryx@ryxperience.com> 
  9  # 
 10  # INFO: 
 11  # - The backend offers an abstracted way of saving a Screenlet's data 
 12  # 
 13  # TODO:  
 14  # - add "type"-argument to save_option and read_option to be able to correctly 
 15  #   set the values in GconfBackend (instead of storing only strings). 
 16  # 
 17   
 18  import glob 
 19  import os 
 20  import gtk 
 21  import gobject 
 22  import gettext 
 23   
 24  gettext.textdomain('screenlets') 
 25  gettext.bindtextdomain('screenlets', '/usr/share/locale') 
 26   
27 -def _(s):
28 return gettext.gettext(s)
29 30 31 try: 32 import gconf 33 except: 34 print "GConf python module not found. GConf settings backend is disabled." 35 36
37 -class ScreenletsBackend(object):
38 """The backend performs the loading/saving of the 'key=value'-strings. 39 Extend this superclass to implement different saving-backends.""" 40
41 - def __init__ (self):
42 pass
43
44 - def delete_instance (self, id):
45 """Delete an instance's configuration by its id.""" 46 pass
47
48 - def flush (self):
49 """Immediately store all values to disk (in case the backend doesn't 50 save in realtime anyway.""" 51 pass
52
53 - def load_option (self, id, name):
54 """Load one option for the instance with the given id.""" 55 pass
56
57 - def load_instance (self, id):
58 """Load all options for the instance with the given id.""" 59 pass
60
61 - def save_option (self, id, name, value):
62 """Save one option for the instance with the given id.""" 63 pass
64 65
66 -class GconfBackend (ScreenletsBackend):
67 """Backend for storing settings in the GConf registry""" 68 69 gconf_dir = '/apps/screenlets/' 70
71 - def __init__ (self):
72 ScreenletsBackend.__init__(self) 73 print 'GConfBackend: initializing' 74 self.client = gconf.client_get_default()
75
76 - def delete_instance (self, id):
77 """Delete an instance's configuration by its id.""" 78 os.system('gconftool-2 --recursive-unset ' + self.key + id) 79 return True
80
81 - def flush (self):
82 """Immediately store all values to disk (in case the backend doesn't 83 save in realtime anyway.""" 84 pass #No need, GConf saves in realtime
85
86 - def load_option (self, id, name):
87 """Load one option for the instance with the given id.""" 88 return self.client.get_string(self.gconf_dir + id + '/' + name)
89
90 - def load_instance (self, id):
91 """Load all options for the instance with the given id.""" 92 keys = [] 93 vals = [] 94 for i in self.client.all_entries(self.gconf_dir + id): 95 keys.append(i.key.split('/')[4]) 96 vals.append(self.client.get_string(i.key)) 97 return dict(zip(keys, vals)) 98 return None
99
100 - def save_option (self, id, name, value):
101 """Save one option for the instance with the given id.""" 102 self.client.set_string(self.gconf_dir + id + '/' + name, value) 103 print 'Saved option %s%s/%s = %s' % (self.gconf_dir, id, name, value)
104 105
106 -class CachingBackend (ScreenletsBackend):
107 """A backend that stores the settings in arrays and saves after a short 108 interval to avoid overhead when multiple values are set within a short time. 109 The data gets saved into $HOME/.config/Screenlets/<Screenletname>/, in a 110 file for each element (named like its id with the extension '.ini').""" 111 112 # internals 113 __instances = {} # a dict with (id:dict)-entries cntaining the data 114 __delay_time = 3000 # delay to wait before performing save 115 __timeout = None # the id of the timeout-function 116 __queue = [] # list with ids of instances that need saving 117 118 # attribs 119 path = '' # the path to store the files 120 121 # Constructor
122 - def __init__ (self, path):
123 ScreenletsBackend.__init__(self) 124 self.path = path 125 self.__load_cache()
126
127 - def delete_instance (self, id):
128 """Delete an instance from the list and from the filesystem.""" 129 if self.__instances.has_key(id): 130 del self.__instances[id] 131 try: 132 import os 133 os.remove(self.path + id + '.ini') 134 except Exception,ex: 135 print ex 136 print "Temporary file didn't exist - nothing to remove." 137 return False 138 print "CachingBackend: <#%s> removed!" % id 139 return True
140
141 - def flush (self):
142 """Immediately save all pending data.""" 143 self.__save_cache()
144
145 - def save_option (self, id, name, value):
146 """Save option for an instance to cache and start saving-timeout 147 for that element (value must be of type string).""" 148 # create key for option, if not existent yet 149 if self.__instances.has_key(id) == False: 150 self.__instances[id] = {} 151 # set option in array 152 self.__instances[id][name] = str(value) 153 #print "CachingBackend.save_option: "+name+"="+self.__instances[id][name] 154 # if id is not already in queue, add the id to the queue 155 if self.__queue.count(id) == 0: 156 self.__queue.append(id) 157 # reset timeout and start new 158 if self.__timeout: 159 gobject.source_remove(self.__timeout) 160 self.__timeout = gobject.timeout_add(self.__delay_time, 161 self.__save_cache)#, id)
162
163 - def load_option (self, id, name):
164 """TODO: Load option from the backend (returned as str).""" 165 return self.__instances[id][name]
166
167 - def load_instance (self, id):
168 """Load all options for the instance with the given id.""" 169 #print "Load element: "+id 170 if self.__instances.has_key(id): 171 return self.__instances[id] 172 return None
173
174 - def __load_cache (self):
175 """Load all cached files from path.""" 176 # perform saving 177 print "CachingBackend: Loading instances from cache" 178 # get dir content of self.path 179 dirname = self.path 180 dirlst = glob.glob(dirname + '*') 181 tdlen = len(dirname) 182 lst = [] 183 for fname in dirlst: 184 dname = fname[tdlen:] 185 if dname.endswith('.ini'): 186 id = dname[:-4] 187 print "CachingBackend: Loading <%s>" % id 188 #print "ID: "+id 189 if self.__instances.has_key(id) == False: 190 self.__instances[id] = {} 191 # open file 192 try: 193 f = open(fname, 'r') 194 lines = f.readlines() 195 # read all options for this element from file 196 for line in lines: 197 #print "LOAD: "+line[:-1] 198 parts = line[:-1].split('=', 1) 199 if len(parts) > 1: 200 # undocumented feature to resize screenlet dynamically on first launch 201 # by boamaod for Estobuntu 202 if parts[0] == 'rel_x': 203 parts[0] = 'x' 204 parts[1] = str(int(gtk.gdk.screen_width()*float(parts[1]))) 205 if parts[0] == 'rel_y': 206 parts[0] = 'y' 207 parts[1] = str(int(gtk.gdk.screen_height()*float(parts[1]))) 208 if parts[0] == 'rel_scale': 209 parts[0] = 'scale' 210 parts[1] = str(gtk.gdk.screen_height()/float(parts[1])) 211 print "%s='%s'" % (parts[0], parts[1]) 212 self.__instances[id][parts[0]] = parts[1] 213 f.close() 214 except Exception, ex: 215 print "Error while loading options: %s" % str(ex)
216
217 - def __save_cache (self):
218 """Save the cache (for all pending instances in queue) to self.path.""" 219 # loop through all instances in queue: 220 for id in self.__queue: 221 # if element with id not exists, remove it and break 222 if self.__instances.has_key(id) == False: 223 print "Queue-element <%s> not found (already removed?)!" % id 224 self.__queue.remove(id) 225 break 226 # create list with options 227 #print "CachingBackend: Saving <#%s> :) ..." % id 228 lst = [] 229 for oname in self.__instances[id]: 230 lst.append([oname, self.__instances[id][oname]]) 231 # and save them (if any) 232 if len(lst) > 0: 233 self.__save_settings (self.path + id + '.ini', lst) 234 # clear queue 235 self.__queue = [] 236 # NOT continue the timeout-function (!!!!!) 237 return False
238
239 - def __save_settings (self, filename, lst):
240 """ Try to save settings in a file, first save this to a temporal file avoid encodings a disk full errors """ 241 filenametmp = filename + '.tmp' 242 isOk = True 243 newini = '' 244 try: 245 # Is posible to fail with encoding error? 246 for el in lst: 247 newini += "%s=%s\n" % (el[0], el[1]) 248 except: 249 isOk = False 250 print "error while convert config to string (encoding error?), I lose your last changes :'(" 251 252 if isOk: 253 # Write the new settings to a temporal file, disk full, encoding, rights may fails at this point. 254 try: 255 open(filenametmp, 'w').write(newini) 256 except: 257 isOk = False 258 print "error while saving configuration to a temporal file %s, disk full?" % filenametmp 259 260 if isOk: 261 # Move saved settings to definitive configuration file, disk error o incorrect rights may fails at this point. 262 try: 263 import shutil 264 shutil.move(filenametmp, filename) 265 except: 266 print "error while moving temporal file to configuration file, %s > %s, sorry, I lose your settings. :'(" % (filenametmp, filename)
267