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