~ubuntu-branches/ubuntu/oneiric/emesene/oneiric-proposed

« back to all changes in this revision

Viewing changes to emesene/gui/gtkui/IconView.py

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2011-03-03 14:49:13 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20110303144913-0adl9cmw2s35lvzo
Tags: 2.0~git20110303-0ubuntu1
* New upstream git revision (LP: #728469).
* Remove debian/watch, debian/emesene.xpm, debian/install and
  debian/README.source files.
* Remove 21_svn2451_fix_avatar and 20_dont_build_own_libmimic patches.
* debian/control: modify python to python (>= 2.5) in Build-Depends field.
* debian/control: remove python-libmimic from Recommends field.
* debian/control: modify python-gtk2 (>= 2.10) to python-gtk2 (>= 2.12) in
  Depends field.
* debian/control: add python-appindicator and python-xmpp to Recommends
  field.
* debian/control: add python-papyon (>= 0.5.4) and python-webkit to Depends
  field.
* debian/control: update Description field.
* debian/control: add python-setuptools to Build-Depends field.
* debian/control: move python-dbus and python-notify to Depends field.
* Update debian/copyright file.
* Update debian/links file.
* debian/menu: update description field.
* Bump Standards-Version to 3.9.1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
'''module to define a class to present a list of thumbnails'''
 
2
# -*- coding: utf-8 -*-
 
3
 
 
4
#    This file is part of emesene.
 
5
#
 
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.
 
10
#
 
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.
 
15
#
 
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
 
19
 
 
20
import os
 
21
import gtk
 
22
import gobject
 
23
 
 
24
import thread
 
25
import time
 
26
import gc
 
27
 
 
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)
 
35
        self.set_spacing(4)
 
36
        
 
37
        self.on_remove_cb = on_remove_cb
 
38
        self.on_accept_cb = on_accept_cb
 
39
        self.iconv_type = iconv_type
 
40
 
 
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)
 
49
 
 
50
        self.label = gtk.Label(label)
 
51
        
 
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)
 
57
 
 
58
        self.stop = False
 
59
        # Start a new thread to fill the iconview with images from path_list
 
60
        thread.start_new_thread(self.fill, (path_list,))
 
61
 
 
62
    def stop_and_clear(self):
 
63
        ''' stop the threads and clean the model '''
 
64
        self.stop = True
 
65
        self.model.clear()
 
66
 
 
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]
 
73
                    if self.stop:
 
74
                        return False
 
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()        
 
85
                        
 
86
                        # give some time to the main thread (for GUI updates)
 
87
                        time.sleep(0.001)
 
88
        # Force Garbage Collector to tidy objects
 
89
        # see http://faq.pygtk.org/index.py?req=show&file=faq08.004.htp
 
90
        gc.collect()
 
91
    
 
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)
 
96
            if path != None:
 
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,
 
101
                                      gtk.ICON_SIZE_MENU))
 
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()
 
106
 
 
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')
 
111
        for url in urls:
 
112
            path = url.replace('file://', '')
 
113
            path = path.replace('\r', '')
 
114
 
 
115
            # the '\x00' value makes an error
 
116
            path = path.replace(chr(0), '')
 
117
 
 
118
            # this seems to be an error on ntpath but we take care :S
 
119
            try:
 
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),)
 
124
 
 
125
    def add_picture(self, path):
 
126
        '''Adds an avatar into the IconView'''
 
127
        try:
 
128
            if os.path.exists(path) and os.access(path, os.R_OK)\
 
129
                    and not self.is_in_view(path):
 
130
                try:
 
131
                    animation = gtk.gdk.PixbufAnimation(path)
 
132
                    if animation.is_static_image():
 
133
                        pixbuf = gtk.gdk.pixbuf_new_from_file(path)
 
134
                    else:
 
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, )
 
139
                    print gobject.GError                      
 
140
                    return
 
141
 
 
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)
 
148
 
 
149
                if self.model != None and not self.stop:
 
150
                    self.model.append([pixbuf, path])
 
151
                    # Esplicitely delete gtkpixbuf
 
152
                    del pixbuf
 
153
            else:
 
154
                print path, 'not readable'
 
155
        except gobject.GError:
 
156
            print "image at %s could not be loaded" % path
 
157
 
 
158
    def is_in_view(self, filename):
 
159
        '''return True if filename already on the iconview'''
 
160
        if os.name == 'nt':
 
161
            # nt doesn't include os.path.samefile
 
162
            return False
 
163
        
 
164
        for (pixbuf, path) in self.model:
 
165
            if os.path.samefile(filename, path):
 
166
                return True
 
167
            if self.stop:
 
168
                return False
 
169
 
 
170
        return False
 
171
 
 
172
    def _on_icon_activated(self, *args):
 
173
        '''method called when a picture is double clicked'''
 
174
        self.on_accept_cb(None)
 
175
    
 
176
    def get_selected_items(self):
 
177
        ''' gets the selected pictures '''
 
178
        return self.iconview.get_selected_items()