1
'''module to define a class to present a list of thumbnails'''
2
# -*- coding: utf-8 -*-
4
# This file is part of emesene.
6
# emesene is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 3 of the License, or
9
# (at your option) any later version.
11
# emesene is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with emesene; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
# Class that holds the iconview from the avatar chooser dialog
29
class IconView(gtk.HBox):
30
''' class representing a listview in icon mode
31
(using gtk.IconView + gtk.ListStore) '''
32
TYPE_SYSTEM_PICS, TYPE_CONTACTS_PICS, TYPE_SELF_PICS = range(3)
33
def __init__(self, label, path_list, on_remove_cb, on_accept_cb, iconv_type):
34
gtk.HBox.__init__(self)
37
self.on_remove_cb = on_remove_cb
38
self.on_accept_cb = on_accept_cb
39
self.iconv_type = iconv_type
41
self.model = gtk.ListStore(gtk.gdk.Pixbuf, str)
42
self.iconview = gtk.IconView(self.model)
43
self.iconview.enable_model_drag_dest([('text/uri-list', 0, 0)],
44
gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_COPY)
45
self.iconview.connect("drag-data-received", self._drag_data_received)
46
self.iconview.set_pixbuf_column(0)
47
self.iconview.connect("item-activated", self._on_icon_activated)
48
self.iconview.connect("button_press_event", self.pop_up)
50
self.label = gtk.Label(label)
52
self.scroll = gtk.ScrolledWindow()
53
self.scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
54
self.scroll.set_shadow_type(gtk.SHADOW_IN)
55
self.scroll.add(self.iconview)
56
self.pack_start(self.scroll, True, True)
59
# Start a new thread to fill the iconview with images from path_list
60
thread.start_new_thread(self.fill, (path_list,))
62
def stop_and_clear(self):
63
''' stop the threads and clean the model '''
67
def fill(self, path_list):
68
'''fill the IconView with avatars from the list of pictures'''
69
for search_path in path_list:
70
if os.path.exists(search_path):
71
for path in os.listdir(search_path):
72
name = os.path.splitext(path)[0]
75
full_path = os.path.join(search_path, path)
76
if not name.endswith('_thumb') and \
77
not path.endswith(('tmp', 'xml', 'db', 'info',
78
'last', 'avatars')) and \
79
not os.path.isdir(full_path):
80
gtk.gdk.threads_enter()
81
self.add_picture(full_path)
82
# make update the iconview
83
self.iconview.queue_draw()
84
gtk.gdk.threads_leave()
86
# give some time to the main thread (for GUI updates)
88
# Force Garbage Collector to tidy objects
89
# see http://faq.pygtk.org/index.py?req=show&file=faq08.004.htp
92
def pop_up(self, iconview, event):
93
''' manage the context menu (?) '''
94
if event.button == 3 and self.iconv_type != IconView.TYPE_SYSTEM_PICS:
95
path = self.iconview.get_path_at_pos(event.x, event.y)
97
self.iconview.select_path(path)
98
remove_menu = gtk.Menu()
99
remove_item = gtk.ImageMenuItem(_('Delete'))
100
remove_item.set_image(gtk.image_new_from_stock(gtk.STOCK_REMOVE,
102
remove_item.connect('activate', self.on_remove_cb)
103
remove_menu.append(remove_item)
104
remove_menu.popup(None, None, None, event.button, event.time)
105
remove_menu.show_all()
107
def _drag_data_received(self, treeview, context, posx, posy, \
108
selection, info, timestamp):
109
'''method called on an image dragged to the view'''
110
urls = selection.data.split('\n')
112
path = url.replace('file://', '')
113
path = path.replace('\r', '')
115
# the '\x00' value makes an error
116
path = path.replace(chr(0), '')
118
# this seems to be an error on ntpath but we take care :S
120
if os.path.exists(path):
121
self.add_picture(path)
122
except TypeError, error:
123
print _("Could not add picture:\n %s") % (str(error),)
125
def add_picture(self, path):
126
'''Adds an avatar into the IconView'''
128
if os.path.exists(path) and os.access(path, os.R_OK)\
129
and not self.is_in_view(path):
131
animation = gtk.gdk.PixbufAnimation(path)
132
if animation.is_static_image():
133
pixbuf = gtk.gdk.pixbuf_new_from_file(path)
135
pixbuf = animation.get_static_image().scale_simple( \
136
64, 64, gtk.gdk.INTERP_BILINEAR)
137
except gobject.GError:
138
print _('image at %s could not be loaded') % (path, )
142
# On nt images are 128x128 (48x48 on xp)
143
# On kde, images are 64x64
144
if (self.iconv_type == IconView.TYPE_SYSTEM_PICS or \
145
self.iconv_type == IconView.TYPE_CONTACTS_PICS) and \
146
(pixbuf.get_width() != 96 or pixbuf.get_height() != 96):
147
pixbuf = pixbuf.scale_simple(96, 96, gtk.gdk.INTERP_BILINEAR)
149
if self.model != None and not self.stop:
150
self.model.append([pixbuf, path])
151
# Esplicitely delete gtkpixbuf
154
print path, 'not readable'
155
except gobject.GError:
156
print "image at %s could not be loaded" % path
158
def is_in_view(self, filename):
159
'''return True if filename already on the iconview'''
161
# nt doesn't include os.path.samefile
164
for (pixbuf, path) in self.model:
165
if os.path.samefile(filename, path):
172
def _on_icon_activated(self, *args):
173
'''method called when a picture is double clicked'''
174
self.on_accept_cb(None)
176
def get_selected_items(self):
177
''' gets the selected pictures '''
178
return self.iconview.get_selected_items()