/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
1
# Copyright (C) 2011 by Guillaume Hain (zedtux) <zedtux@zedroot.org>
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
import gtk
18
723 by Jelmer Vernooij
Merge support for showing gravatars.
19
from bzrlib.config import parse_username
20
729.1.1 by Jelmer Vernooij
Move i18n support to a separate file, so gettext files aren't loaded unless bzr-gtk is used.
21
from bzrlib.plugins.gtk.i18n import _i18n
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
22
from bzrlib.plugins.gtk.avatarproviders import (
23
    AvatarProviderGravatar,
24
    AvatarDownloaderWorker,
25
    )
26
27
28
class Avatar(gtk.HBox):
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
29
    """ Author or committer avatar """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
30
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
31
    def __init__(self, apparent_username):
32
        """ Constructor """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
33
        gtk.HBox.__init__(self)
34
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
35
        self.apparent_username = apparent_username
36
        self.username, self.email = parse_username(apparent_username)
37
        self.image = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
38
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
39
    def __eq__(self, other):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
40
        return (self.apparent_username == other.apparent_username and
41
                self.name == other.name and
42
                self.email == other.email)
43
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
44
    def show_spinner(self):
45
        """
46
        Replace the current content of the Avatar with a gtk.Spinner
47
        if an email address has been parsed. If not, show an gtk.Label with
48
        the translatable 'No email' text.
49
        """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
50
        if self.email:
729 by Jelmer Vernooij
Support use without gtk.Spinner, which is only available in pygtk >= 2.22.
51
            tooltip = _i18n("Retrieving avatar for %s...") % self.email
52
            if getattr(gtk, "Spinner", False):
53
                spinner = gtk.Spinner()
54
                spinner.start()
55
                self.pack_start(spinner, False)
56
                spinner.set_tooltip_text(tooltip)
57
                spinner.set_size_request(20, 20)
58
                spinner.show()
59
            else:
60
                spinner = gtk.Label(tooltip)
61
                self.pack_start(spinner)
62
                self.set_tooltip_text(self.apparent_username)
63
                spinner.show()
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
64
        else:
65
            no_email = gtk.Label(_i18n("No email"))
66
            self.pack_start(no_email)
67
            self.set_tooltip_text(self.apparent_username)
68
            no_email.show()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
69
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
70
    def show_image(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
71
        """Replace the current content of the Avatar with the gtk.Image """
72
        if self.email and self.image:
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
73
            self.remove(self.get_children()[0])
74
            self.pack_start(self.image)
75
            self.image.set_tooltip_text(self.apparent_username)
76
            self.image.show()
77
78
79
class AvatarBox(gtk.HBox):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
80
    """HBox showing an avatar."""
81
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
82
    def __init__(self, homogeneous=False, spacing=0):
83
        gtk.HBox.__init__(self, homogeneous, spacing)
84
        self.__avatars = {}
85
        self.avatar = None
86
        self.__displaying = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
87
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
88
    def reset_view(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
89
        """Remove current avatars from the gtk box."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
90
        for child in self.get_children():
91
            self.remove(child)
92
        self.__displaying = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
93
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
94
    def have_avatar(self, avatar):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
95
        """Return True if this box has the specified avatar.
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
96
        """
97
        return avatar.email in self.__avatars
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
98
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
99
    def showing(self, avatar):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
100
        """Return True if the displaying avatar matches the specified one.
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
101
        """
102
        return self.__displaying and self.__displaying == avatar
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
103
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
104
    def append_avatars_with(self, avatar):
105
        """
106
        Append avatars collection with the given one if not already registed
107
        otherwise render it back.
108
        When an avatar is added this method True, otherwise, if the avatar
109
        was in the collection, return False.
110
        """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
111
        if avatar.email and not avatar.email in self.__avatars:
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
112
            self.__avatars[avatar.email] = avatar
113
            self._new_cell_for_avatar(avatar)
114
            return True
115
        else:
116
            self.and_avatar_email(avatar.email).come_back_to_gui()
117
        return False
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
118
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
119
    def and_avatar_email(self, email):
120
        """
121
        Select the avatar from avatars collection
122
        in order to apply future actions
123
        """
124
        self.avatar = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
125
        if email and email in self.__avatars:
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
126
            self.avatar = self.__avatars[email]
127
        else:
128
            self.avatar = None
129
        return self
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
130
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
131
    def update_avatar_image_from_pixbuf_loader(self, loader):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
132
        """Replace the gtk.Spinner with the given loader."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
133
        if self.avatar:
134
            self.avatar.image = gtk.Image()
135
            self.avatar.image.set_from_pixbuf(loader.get_pixbuf())
136
            self.avatar.show_image()
137
            self.__displaying = self.avatar
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
138
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
139
    def come_back_to_gui(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
140
        """Render back avatar in the GUI."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
141
        if self.avatar:
142
            self.pack_start(self.avatar)
143
            self.__displaying = self.avatar
144
        else:
145
            self._show_no_email()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
146
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
147
    def _new_cell_for_avatar(self, avatar):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
148
        """Create a new cell in this box with a gtk.Spinner."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
149
        avatar.show_spinner()
150
        self.pack_start(avatar)
151
        avatar.show()
152
        self.__displaying = avatar
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
153
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
154
    def _show_no_email(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
155
        """Show a gtk.Label with test 'No email'."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
156
        no_email = gtk.Label(_i18n("No email"))
157
        self.pack_start(no_email)
158
        no_email.show()
159
160
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
161
class AvatarsBox(gtk.HBox):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
162
    """GTK container for author and committer avatars."""
163
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
164
    def __init__(self):
165
        gtk.HBox.__init__(self, False, 10)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
166
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
167
        self.__committer_box = None
168
        self.__authors_box = None
169
        self._init_gui()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
170
171
        # If more later you want to implement more avatar providers:
172
        # * Create a new class named AvatarProvider + provider_name that
173
        #   inherit from the AvatarProvider class.
174
        # * Implement a method that return url to use in the request.
175
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
176
        # For example, with Gravatar, the method return the complete url
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
177
        # with MD5 hash of the email address and put the value in a
178
        # gravatar_id field.
179
        # Then create a new worker (manage them in a python dictionary).
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
180
        provider = AvatarProviderGravatar()
181
        self.__worker = AvatarDownloaderWorker(
182
            provider.gravatar_id_for_email
183
        )
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
184
        # This callback method should be fired by all workers when a request
185
        # is done.
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
186
        self.__worker.set_callback_method(self._update_avatar_from_response)
187
        self.__worker.start()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
188
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
189
    def add(self, username, role):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
190
        """Add the given username in the role box and add in the worker queue.
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
191
        """
192
        avatar = Avatar(username)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
193
        if (role == "author" and not self._role_box_for("committer").showing(avatar)) or role == "committer":
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
194
            if self._role_box_for(role).append_avatars_with(avatar):
195
                self.__worker.queue(avatar.email)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
196
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
197
    def merge(self, usernames, role):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
198
        """Add avatars from a list"""
719.2.2 by zedtux
Patched code following Jelmer's recommandations
199
        for username in usernames:
200
            self.add(username, role)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
201
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
202
    def reset(self):
203
        """
204
        Request a reset view for all boxes in order to show only avatars
205
        of the selected line in the revision view screen.
206
        """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
207
        for role in ("committer", "author"):
208
            self._role_box_for(role).reset_view()
209
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
210
    def _init_gui(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
211
        """Create boxes where avatars will be displayed."""
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
212
        # 2 gtk.HBox: One for the committer and one for authors
213
        # Committer
214
        self.__committer_box = AvatarBox()
215
        self.__committer_box.set_size_request(80, 80)
216
        self.pack_end(self.__committer_box, False)
217
        self.__committer_box.show()
218
        # Authors
219
        self.__authors_box = AvatarBox()
220
        self.pack_end(self.__authors_box, False)
221
        self.__authors_box.set_spacing(10)
222
        self.__authors_box.show()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
223
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
224
    def _update_avatar_from_response(self, response, email):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
225
        """Callback method fired by avatar worker when finished.
226
227
        :param response: a urllib2.urlopen() return value.
228
        :param email: used to identify item from self.__avatars.
229
        """
230
        if email:
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
231
            # Convert downloaded image from provider to gtk.Image
232
            loader = gtk.gdk.PixbufLoader()
233
            loader.write(response.read())
234
            loader.close()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
235
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
236
            for role in ["committer", "author"]:
237
                self._role_box_for(role).and_avatar_email(email).update_avatar_image_from_pixbuf_loader(loader)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
238
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
239
    def _role_box_for(self, role):
240
        """ Return the gtk.HBox for the given role """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
241
        if role == "committer":
242
            return self.__committer_box
243
        else:
244
            return self.__authors_box