/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
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
17
from gi.repository import Gtk
734.1.25 by Curtis Hovey
Updated the pixbuf calls to gtk3.
18
from gi.repository import GdkPixbuf
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
19
723 by Jelmer Vernooij
Merge support for showing gravatars.
20
from bzrlib.config import parse_username
21
729.1.1 by Jelmer Vernooij
Move i18n support to a separate file, so gettext files aren't loaded unless bzr-gtk is used.
22
from bzrlib.plugins.gtk.i18n import _i18n
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
23
from bzrlib.plugins.gtk.avatarproviders import (
24
    AvatarProviderGravatar,
25
    AvatarDownloaderWorker,
26
    )
27
28
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
29
class Avatar(Gtk.HBox):
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
30
    """ Author or committer avatar """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
31
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
32
    def __init__(self, apparent_username):
33
        """ Constructor """
734.1.51 by Curtis Hovey
Fix the initializer for many classes.
34
        super(Avatar, self).__init__()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
35
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
36
        self.apparent_username = apparent_username
37
        self.username, self.email = parse_username(apparent_username)
38
        self.image = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
39
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
40
    def __eq__(self, other):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
41
        return (self.apparent_username == other.apparent_username and
734.1.6 by Curtis Hovey
Added a very rough fix to see gannontation.
42
                self.username == other.username and
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
43
                self.email == other.email)
44
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
45
    def show_spinner(self):
46
        """
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
47
        Replace the current content of the Avatar with a Gtk.Spinner
48
        if an email address has been parsed. If not, show an Gtk.Label with
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
49
        the translatable 'No email' text.
50
        """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
51
        if self.email:
729 by Jelmer Vernooij
Support use without gtk.Spinner, which is only available in pygtk >= 2.22.
52
            tooltip = _i18n("Retrieving avatar for %s...") % self.email
734.1.6 by Curtis Hovey
Added a very rough fix to see gannontation.
53
            spinner = Gtk.Spinner()
54
            spinner.start()
55
            self.pack_start(spinner, False, True, 0)
56
            spinner.set_tooltip_text(tooltip)
57
            spinner.set_size_request(20, 20)
58
            spinner.show()
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
59
        else:
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
60
            no_email = Gtk.Label(label=_i18n("No email"))
61
            self.pack_start(no_email, True, True, 0)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
62
            self.set_tooltip_text(self.apparent_username)
63
            no_email.show()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
64
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
65
    def show_image(self):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
66
        """Replace the current content of the Avatar with the Gtk.Image """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
67
        if self.email and self.image:
734.1.31 by Curtis Hovey
Do not remove an item from an empty list.
68
            children = self.get_children()
69
            if children != []:
734.1.32 by Curtis Hovey
Lint fixes while looking at thread issues.
70
                self.remove(children[0])
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
71
            self.pack_start(self.image, True, True, 0)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
72
            self.image.set_tooltip_text(self.apparent_username)
73
            self.image.show()
74
75
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
76
class AvatarBox(Gtk.HBox):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
77
    """HBox showing an avatar."""
78
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
79
    def __init__(self, homogeneous=False, spacing=0):
734.1.51 by Curtis Hovey
Fix the initializer for many classes.
80
        super(AvatarBox, self).__init__(
81
            homogeneous=homogeneous, spacing=spacing)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
82
        self.__avatars = {}
83
        self.avatar = None
84
        self.__displaying = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
85
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
86
    def reset_view(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
87
        """Remove current avatars from the gtk box."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
88
        for child in self.get_children():
89
            self.remove(child)
90
        self.__displaying = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
91
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
92
    def have_avatar(self, avatar):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
93
        """Return True if this box has the specified avatar.
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
94
        """
95
        return avatar.email in self.__avatars
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
96
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
97
    def showing(self, avatar):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
98
        """Return True if the displaying avatar matches the specified one.
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
99
        """
100
        return self.__displaying and self.__displaying == avatar
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
101
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
102
    def append_avatars_with(self, avatar):
103
        """
104
        Append avatars collection with the given one if not already registed
105
        otherwise render it back.
106
        When an avatar is added this method True, otherwise, if the avatar
107
        was in the collection, return False.
108
        """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
109
        if avatar.email and not avatar.email in self.__avatars:
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
110
            self.__avatars[avatar.email] = avatar
111
            self._new_cell_for_avatar(avatar)
112
            return True
113
        else:
114
            self.and_avatar_email(avatar.email).come_back_to_gui()
115
        return False
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
116
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
117
    def and_avatar_email(self, email):
118
        """
119
        Select the avatar from avatars collection
120
        in order to apply future actions
121
        """
122
        self.avatar = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
123
        if email and email in self.__avatars:
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
124
            self.avatar = self.__avatars[email]
125
        else:
126
            self.avatar = None
127
        return self
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
128
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
129
    def update_avatar_image_from_pixbuf_loader(self, loader):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
130
        """Replace the Gtk.Spinner with the given loader."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
131
        if self.avatar:
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
132
            self.avatar.image = Gtk.Image()
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
133
            self.avatar.image.set_from_pixbuf(loader.get_pixbuf())
134
            self.avatar.show_image()
135
            self.__displaying = self.avatar
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
136
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
137
    def come_back_to_gui(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
138
        """Render back avatar in the GUI."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
139
        if self.avatar:
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
140
            self.pack_start(self.avatar, True, True, 0)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
141
            self.__displaying = self.avatar
142
        else:
143
            self._show_no_email()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
144
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
145
    def _new_cell_for_avatar(self, avatar):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
146
        """Create a new cell in this box with a Gtk.Spinner."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
147
        avatar.show_spinner()
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
148
        self.pack_start(avatar, True, True, 0)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
149
        avatar.show()
150
        self.__displaying = avatar
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
151
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
152
    def _show_no_email(self):
734.1.32 by Curtis Hovey
Lint fixes while looking at thread issues.
153
        """Show a Gtk.Label with text 'No email'."""
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
154
        no_email = Gtk.Label(label=_i18n("No email"))
155
        self.pack_start(no_email, True, True, 0)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
156
        no_email.show()
157
158
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
159
class AvatarsBox(Gtk.HBox):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
160
    """GTK container for author and committer avatars."""
161
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
162
    def __init__(self):
734.1.34 by Curtis Hovey
Ensure the avatar threads are stopped when the widget is destroyed.
163
        super(AvatarsBox, self).__init__(homogeneous=False, spacing=10)
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
164
        self.__committer_box = None
165
        self.__authors_box = None
166
        self._init_gui()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
167
168
        # If more later you want to implement more avatar providers:
169
        # * Create a new class named AvatarProvider + provider_name that
170
        #   inherit from the AvatarProvider class.
171
        # * Implement a method that return url to use in the request.
172
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
173
        # For example, with Gravatar, the method return the complete url
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
174
        # with MD5 hash of the email address and put the value in a
175
        # gravatar_id field.
176
        # 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)
177
        provider = AvatarProviderGravatar()
178
        self.__worker = AvatarDownloaderWorker(
179
            provider.gravatar_id_for_email
180
        )
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
181
        # This callback method should be fired by all workers when a request
182
        # is done.
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
183
        self.__worker.set_callback_method(self._update_avatar_from_response)
734.1.34 by Curtis Hovey
Ensure the avatar threads are stopped when the widget is destroyed.
184
        self.connect('destroy', self.on_destroy)
185
186
    def on_destroy(self, widget):
187
        self.__worker.stop()
188
        if self.__worker.is_alive():
189
            self.__worker.join()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
190
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
191
    def add(self, username, role):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
192
        """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)
193
        """
194
        avatar = Avatar(username)
734.1.32 by Curtis Hovey
Lint fixes while looking at thread issues.
195
        is_shown = self._role_box_for("committer").showing(avatar)
196
        if (role == "author" and not is_shown) or role == "committer":
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
197
            if self._role_box_for(role).append_avatars_with(avatar):
198
                self.__worker.queue(avatar.email)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
199
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
200
    def merge(self, usernames, role):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
201
        """Add avatars from a list"""
719.2.2 by zedtux
Patched code following Jelmer's recommandations
202
        for username in usernames:
203
            self.add(username, role)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
204
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
205
    def reset(self):
206
        """
207
        Request a reset view for all boxes in order to show only avatars
208
        of the selected line in the revision view screen.
209
        """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
210
        for role in ("committer", "author"):
211
            self._role_box_for(role).reset_view()
212
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
213
    def _init_gui(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
214
        """Create boxes where avatars will be displayed."""
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
215
        # 2 Gtk.HBox: One for the committer and one for authors
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
216
        # Committer
217
        self.__committer_box = AvatarBox()
218
        self.__committer_box.set_size_request(80, 80)
734.1.6 by Curtis Hovey
Added a very rough fix to see gannontation.
219
        self.pack_end(self.__committer_box, False, True, 0)
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
220
        self.__committer_box.show()
221
        # Authors
222
        self.__authors_box = AvatarBox()
734.1.6 by Curtis Hovey
Added a very rough fix to see gannontation.
223
        self.pack_end(self.__authors_box, False, True, 0)
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
224
        self.__authors_box.set_spacing(10)
225
        self.__authors_box.show()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
226
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
227
    def _update_avatar_from_response(self, response, email):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
228
        """Callback method fired by avatar worker when finished.
229
230
        :param response: a urllib2.urlopen() return value.
231
        :param email: used to identify item from self.__avatars.
232
        """
734.1.25 by Curtis Hovey
Updated the pixbuf calls to gtk3.
233
        if email:
234
            # Convert downloaded image from provider to Gtk.Image
235
            loader = GdkPixbuf.PixbufLoader()
236
            loader.write(response.read())
237
            loader.close()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
238
734.1.25 by Curtis Hovey
Updated the pixbuf calls to gtk3.
239
            for role in ["committer", "author"]:
734.1.32 by Curtis Hovey
Lint fixes while looking at thread issues.
240
                self._role_box_for(role).and_avatar_email(
241
                    email).update_avatar_image_from_pixbuf_loader(loader)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
242
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
243
    def _role_box_for(self, role):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
244
        """ Return the Gtk.HBox for the given role """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
245
        if role == "committer":
246
            return self.__committer_box
247
        else:
248
            return self.__authors_box