Let's play it safe when restoring state in select_node.
[straw.git] / straw / ImageCache.py
blob9273739b4ba291ec3cff88ce6c5e10fd43b9cef0
1 """ ImageCache.py
3 Module for handling images
4 """
5 __copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc."
6 __license__ = """
7 Straw is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2 of the License, or (at your option) any later
10 version.
12 Straw is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along with
17 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 Place - Suite 330, Boston, MA 02111-1307, USA. """
20 from straw import helpers
21 import Config
22 import Constants
23 import error
24 import gobject
25 import straw.defs
27 STATUS_IMAGE_WAITING = None
28 STATUS_IMAGE_BROKEN = None
30 class CacheEntry(object):
31 def __init__(self, image, count, pollstopper = None, restore = False):
32 self._image = image
33 self._count = count
34 self._pollstopper = pollstopper
35 if not restore:
36 self._save_count()
38 @apply
39 def image():
40 doc="The image object that is associated with this class"
41 def fget(self):
42 return self._image
43 def fset(self, image):
44 self._image = image
45 return property(**locals())
47 @apply
48 def count():
49 doc="image ref count"
50 def fget(self):
51 return self._count
52 def fset(self, count):
53 self._count = count
54 self._save_count()
55 return property(**locals())
57 @apply
58 def pollstopper():
59 doc="the stopper object for this cache entry"
60 def fget(self):
61 return self._pollstopper
62 def fset(self, pollstopper):
63 self._pollstopper = pollstopper
64 if pollstopper:
65 pollstopper.connect('stopped', self._polling_stopped)
66 return property(**locals())
68 def incr_count(self): self._count += 1
69 def decr_count(self): self._count -= 1
71 def _polling_stopped(self, poller):
72 self._pollstopper = None
74 def _save_count(self):
75 pass
76 #ItemStore.get_instance().set_image_count(self._image.url, self._count)
79 class Cache(gobject.GObject):
80 """Image cache with explicit reference counting."""
82 __gsignals__ = {
83 'image-updated' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
84 (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT))
87 def __init__(self):
88 gobject.GObject.__init__(self)
89 # self.__cache contains items of the form [Image, refcount]
90 self.__cache = dict()
92 def __getitem__(self, key):
93 print "got getitem for %s" % key
94 print "cache is %s" % self.__cache
95 return self.__cache[key].image
97 def add_refer(self, key, restore = False, item = None):
98 if key not in self.__cache:
99 if not restore:
100 # fetch image
101 image = Image(key, Image.WAITING)
102 ic = ImageConsumer(image)
103 headers = {}
104 stopper = None
105 if item and item.feed:
106 headers['Referer'] = item.feed.location
107 try:
108 stopper = URLFetch.get_instance().request(
109 key, ic,
110 priority=Constants.PRIORITY_IMAGE,
111 headers=headers)
112 #except URLFetch.RequestSchemeException, e:
113 # ic.http_failed(e)
114 except Exception, e:
115 error.logtb("ImageCache.add_refer: ", str(e))
116 ic.http_failed(e)
117 self.__cache[key] = CacheEntry(
118 image, 1, PollManager.PollStopper(stopper, image), restore=restore)
119 else:
120 image = Image(key, Image.DATA_IN_DB)
121 self.__cache[key] = CacheEntry(image, 1, pollstopper=None, restore=restore)
122 elif key in self.__cache and not restore:
123 self.__cache[key].incr_count()
125 def remove_refer(self, key):
126 if self.__cache.has_key(key):
127 entry = self.__cache[key]
128 entry.decr_count()
129 if entry.count == 0:
130 del self.__cache[key]
131 ItemStore.get_instance().update_image(key, None)
132 self.emit('image-updated', key, None)
134 def image_updated(self, url, data):
135 self.__cache[url].pollstopper = None
136 self.set_image(url,data)
137 ItemStore.get_instance().update_image(url,data)
138 self.emit('image-updated', url, data)
140 def set_image(self, url, image):
141 if self.__cache.has_key(url):
142 self.__cache[url].incr_count()
143 else:
144 self.__cache[url] = CacheEntry(image, 1)
146 def set_image_with_count(self, url, image, count, restore=False):
147 self.__cache[url] = CacheEntry(image, count, restore=restore)
149 def stop_transfer(self, url):
150 image = self.__cache.get(url, None)
151 if image and image.pollstopper:
152 self.__cache[url].pollstopper.stop()
153 self.__cache[url].pollstopper = None
155 class Image:
156 WAITING = 1
157 DATA_IN_DB = 2
158 FAILED = 3
160 def __init__(self, url, status = DATA_IN_DB):
161 self.url = url
162 self.status = status
164 def get_data(self):
165 if self.status == self.WAITING:
166 return STATUS_IMAGE_WAITING
167 elif self.status == self.DATA_IN_DB:
168 data = self.read_data()
169 if data is None:
170 self.status = self.FAILED
171 return STATUS_IMAGE_BROKEN
172 return data
173 else:
174 self.status = self.FAILED
175 return STATUS_IMAGE_BROKEN
177 def set_data(self, data):
178 cache.image_updated(self.url, data)
179 self.status = self.DATA_IN_DB
181 def set_failed(self):
182 self.status = self.FAILED
184 def read_data(self):
185 istore = ItemStore.get_instance()
186 return istore.read_image(self.url)
188 def _return_id(self):
189 return "%d %s" % (id(self), self.url)
191 cache = Cache()
193 class ImageConsumer:
194 def __init__(self, imobj):
195 self._imobj = imobj
197 def http_results(self, status, data):
198 if status[1] == 200:
199 self._imobj.set_data(data)
200 else:
201 self._imobj.set_failed()
203 def http_failed(self, exception):
204 self._imobj.set_failed()
206 def operation_stopped(self):
207 # XXX operation stopped is not really failed
208 self._imobj.set_failed()
210 def initialize():
211 global STATUS_IMAGE_WAITING
212 global STATUS_IMAGE_BROKEN
213 STATUS_IMAGE_WAITING = open(
214 straw.defs.STRAW_DATA_DIR + "/image-loading.svg").read()
215 STATUS_IMAGE_BROKEN = open(
216 straw.defs.STRAW_DATA_DIR + "/image-missing.svg").read()