[go: up one dir, main page]

Menu

[r1450]: / mcomix / thumbnail_view.py  Maximize  Restore  History

Download this file

133 lines (107 with data), 5.2 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
""" gtk.IconView subclass for dynamically generated thumbnails. """
import Queue
import gtk
import gobject
from mcomix.preferences import prefs
from mcomix.worker_thread import WorkerThread
class ThumbnailViewBase(object):
""" This class provides shared functionality for gtk.TreeView and
gtk.IconView. Instantiating this class directly is *impossible*,
as it depends on methods provided by the view classes. """
def __init__(self, uid_column, pixbuf_column, status_column):
""" Constructs a new ThumbnailView.
@param uid_column: index of unique identifer column.
@param pixbuf_column: index of pixbuf column.
@param status_column: index of status boolean column
(True if pixbuf is not temporary filler)
"""
#: Keep track of already generated thumbnails.
self._uid_column = uid_column
self._pixbuf_column = pixbuf_column
self._status_column = status_column
#: Ignore updates when this flag is True.
self._updates_stopped = True
#: Worker thread
self._thread = WorkerThread(self._pixbuf_worker,
name='thumbview',
unique_orders=True,
max_threads=prefs["max threads"])
def generate_thumbnail(self, uid):
""" This function must return the thumbnail for C{uid}. """
raise NotImplementedError()
def get_visible_range(self):
""" See L{gtk.IconView.get_visible_range}. """
raise NotImplementedError()
def stop_update(self):
""" Stops generation of pixbufs. """
self._updates_stopped = True
self._thread.stop()
def draw_thumbnails_on_screen(self, *args):
""" Prepares valid thumbnails for currently displayed icons.
This method is supposed to be called from the expose-event
callback function. """
visible = self.get_visible_range()
if not visible:
# No valid paths available
return
pixbufs_needed = []
start = visible[0][0]
end = visible[1][0]
# Read ahead/back and start caching a few more icons. Currently invisible
# icons are always cached only after the visible icons have been completed.
additional = (end - start) // 2
required = range(start, end + additional + 1) + \
range(max(0, start - additional), start)
model = self.get_model()
# Filter invalid paths.
required = [path for path in required if 0 <= path < len(model)]
with self._thread:
# Flush current pixmap generation orders.
self._thread.clear_orders()
for path in required:
iter = model.get_iter(path)
uid, generated = model.get(iter,
self._uid_column,
self._status_column)
# Do not queue again if thumbnail was already created.
if not generated:
pixbufs_needed.append((uid, iter))
if len(pixbufs_needed) > 0:
self._updates_stopped = False
self._thread.extend_orders(pixbufs_needed)
def _pixbuf_worker(self, order):
""" Run by a worker thread to generate the thumbnail for a path."""
uid, iter = order
pixbuf = self.generate_thumbnail(uid)
if pixbuf is not None:
gobject.idle_add(self._pixbuf_finished, iter, pixbuf)
def _pixbuf_finished(self, iter, pixbuf):
""" Executed when a pixbuf was created, to actually insert the pixbuf
into the view store. C{pixbuf_info} is a tuple containing
(index, pixbuf). """
if self._updates_stopped:
return 0
model = self.get_model()
model.set(iter, self._status_column, True, self._pixbuf_column, pixbuf)
# Remove this idle handler.
return 0
class ThumbnailIconView(gtk.IconView, ThumbnailViewBase):
def __init__(self, model, uid_column, pixbuf_column, status_column):
assert gtk.TREE_MODEL_ITERS_PERSIST == (model.get_flags() & gtk.TREE_MODEL_ITERS_PERSIST)
super(ThumbnailIconView, self).__init__(model)
ThumbnailViewBase.__init__(self, uid_column, pixbuf_column, status_column)
self.set_pixbuf_column(pixbuf_column)
# Connect events
self.connect('expose-event', self.draw_thumbnails_on_screen)
def get_visible_range(self):
return gtk.IconView.get_visible_range(self)
class ThumbnailTreeView(gtk.TreeView, ThumbnailViewBase):
def __init__(self, model, uid_column, pixbuf_column, status_column):
assert gtk.TREE_MODEL_ITERS_PERSIST == (model.get_flags() & gtk.TREE_MODEL_ITERS_PERSIST)
super(ThumbnailTreeView, self).__init__(model)
ThumbnailViewBase.__init__(self, uid_column, pixbuf_column, status_column)
# Connect events
self.connect('expose-event', self.draw_thumbnails_on_screen)
def get_visible_range(self):
return gtk.TreeView.get_visible_range(self)
# vim: expandtab:sw=4:ts=4