| Home | Trees | Indices | Help |
|
|---|
|
|
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
30
31
32 try:
33 import gconf
34 except:
35 print "GConf python module not found. GConf settings backend is disabled."
36
37
39 """The backend performs the loading/saving of the 'key=value'-strings.
40 Extend this superclass to implement different saving-backends."""
41
44
48
50 """Immediately store all values to disk (in case the backend doesn't
51 save in realtime anyway."""
52 pass
53
57
61
65
66
68 """Backend for storing settings in the GConf registry"""
69
70 gconf_dir = '/apps/screenlets/'
71
73 ScreenletsBackend.__init__(self)
74 print 'GConfBackend: initializing'
75 self.client = gconf.client_get_default()
76
78 """Delete an instance's configuration by its id."""
79 os.system('gconftool-2 --recursive-unset ' + self.key + id)
80 return True
81
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
88 """Load one option for the instance with the given id."""
89 return self.client.get_string(self.gconf_dir + id + '/' + name)
90
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
105
106
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
127
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
145
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
165 """TODO: Load option from the backend (returned as str)."""
166 return self.__instances[id][name]
167
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
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 features to resize screenlet dynamically on first launch
202 # width, height must precede rel_x and rel_y with "_"
203 # by boamaod for Estobuntu
204 if parts[0] == 'x':
205 if parts[1].startswith("*"): # if * is added, take distance from the opposite side
206 parts[1] = parts[1].strip("*")
207 add_width = 0
208 if parts[1].startswith("_"): # if _ is added, take it to be right corner
209 add_width = int(float(self.__instances[id]["width"])*float(self.__instances[id]["scale"]))
210 print "ADD W", add_width
211 parts[1] = str(gtk.gdk.screen_width() - int(parts[1].strip("_")) - add_width)
212 print ">>>X", parts[1]
213 if parts[0] == 'y':
214 if parts[1].startswith("*"): # if * is added, take distance from the opposite side
215 parts[1] = parts[1].strip("*")
216 add_height = 0
217 if parts[1].startswith("_"): # if _ is added, take it to be bottom corner
218 add_height = int(float(self.__instances[id]["height"])*float(self.__instances[id]["scale"]))
219 print "ADD H", add_height
220 parts[1] = str(gtk.gdk.screen_height() - int(parts[1].strip("_")) - add_height)
221 print ">>>Y", parts[1]
222 if parts[0] == 'rel_x':
223 parts[0] = 'x'
224 add_width = 0
225 if parts[1].startswith("_"): # if _ is added, take it to be right corner
226 add_width = int(float(self.__instances[id]["width"])*float(self.__instances[id]["scale"]))
227 print "ADD W", add_width
228 parts[1] = str(int(gtk.gdk.screen_width()*float(parts[1].strip("_"))) - add_width)
229 print ">>>X", parts[1]
230 if parts[0] == 'rel_y':
231 parts[0] = 'y'
232 add_height = 0
233 if parts[1].startswith("_"): # if _ is added, take it to be bottom corner
234 add_height = int(float(self.__instances[id]["height"])*float(self.__instances[id]["scale"]))
235 print "ADD H", add_height
236 parts[1] = str(int(gtk.gdk.screen_height()*float(parts[1].strip("_"))) - add_height)
237 print ">>>Y", parts[1]
238 if parts[0] == 'rel_scale':
239 parts[0] = 'scale'
240 scale = float(self.__instances[id]["scale"])
241 initial_scale = scale + float(gtk.gdk.screen_height()*gtk.gdk.screen_width())/float(parts[1])
242 if initial_scale < 1.5:
243 initial_scale = 1.5
244 if initial_scale > 3:
245 initial_scale = 3
246 parts[1] = str(initial_scale)
247 # parts[1] = str(gtk.gdk.screen_height()/float(parts[1]))
248 print ">>>SCALE", parts[1]
249 if parts[0] == 'rel_font_name':
250 parts[0] = 'font_name'
251 print "|||", parts[1]
252 font_parts = parts[1].split(" ")
253 parts[1]=""
254 for fp in font_parts:
255 if len(fp.strip("0123456789.")) == 0:
256 parts[1]+= str( round(float(fp)*float(self.__instances[id]["scale"]), 1) ) + " "
257 else:
258 parts[1]+= fp + " "
259 parts[1] = parts[1].strip(" ")
260 print ">>>FONT_NAME", parts[1]
261 # End of dynamic resize section
262 print "%s='%s'" % (parts[0], parts[1])
263 self.__instances[id][parts[0]] = parts[1]
264 f.close()
265 except Exception, ex:
266 print "Error while loading options: %s" % str(ex)
267
269 """Save the cache (for all pending instances in queue) to self.path."""
270 # loop through all instances in queue:
271 for id in self.__queue:
272 # if element with id not exists, remove it and break
273 if self.__instances.has_key(id) == False:
274 print "Queue-element <%s> not found (already removed?)!" % id
275 self.__queue.remove(id)
276 break
277 # create list with options
278 #print "CachingBackend: Saving <#%s> :) ..." % id
279 lst = []
280 for oname in self.__instances[id]:
281 lst.append([oname, self.__instances[id][oname]])
282 # and save them (if any)
283 if len(lst) > 0:
284 self.__save_settings (self.path + id + '.ini', lst)
285 # clear queue
286 self.__queue = []
287 # NOT continue the timeout-function (!!!!!)
288 return False
289
291 """ Try to save settings in a file, first save this to a temporal file avoid encodings a disk full errors """
292 filenametmp = filename + '.tmp'
293 isOk = True
294 newini = ''
295 try:
296 # Is posible to fail with encoding error?
297 for el in lst:
298 newini += "%s=%s\n" % (el[0], el[1])
299 except:
300 isOk = False
301 print "error while convert config to string (encoding error?), I lose your last changes :'("
302
303 if isOk:
304 # Write the new settings to a temporal file, disk full, encoding, rights may fails at this point.
305 try:
306 open(filenametmp, 'w').write(newini)
307 except:
308 isOk = False
309 print "error while saving configuration to a temporal file %s, disk full?" % filenametmp
310
311 if isOk:
312 # Move saved settings to definitive configuration file, disk error o incorrect rights may fails at this point.
313 try:
314 import shutil
315 shutil.move(filenametmp, filename)
316 except:
317 print "error while moving temporal file to configuration file, %s > %s, sorry, I lose your settings. :'(" % (filenametmp, filename)
318
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Jun 6 10:56:37 2011 | http://epydoc.sourceforge.net |