/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.6 by Curtis Hovey
Added a very rough fix to see gannontation.
34
        Gtk.HBox.__init__(self)
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.6 by Curtis Hovey
Added a very rough fix to see gannontation.
80
        Gtk.HBox.__init__(self, homogeneous=homogeneous, spacing=spacing)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
81
        self.__avatars = {}
82
        self.avatar = None
83
        self.__displaying = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
84
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
85
    def reset_view(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
86
        """Remove current avatars from the gtk box."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
87
        for child in self.get_children():
88
            self.remove(child)
89
        self.__displaying = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
90
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
91
    def have_avatar(self, avatar):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
92
        """Return True if this box has the specified avatar.
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
93
        """
94
        return avatar.email in self.__avatars
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
95
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
96
    def showing(self, avatar):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
97
        """Return True if the displaying avatar matches the specified one.
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
98
        """
99
        return self.__displaying and self.__displaying == avatar
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
100
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
101
    def append_avatars_with(self, avatar):
102
        """
103
        Append avatars collection with the given one if not already registed
104
        otherwise render it back.
105
        When an avatar is added this method True, otherwise, if the avatar
106
        was in the collection, return False.
107
        """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
108
        if avatar.email and not avatar.email in self.__avatars:
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
109
            self.__avatars[avatar.email] = avatar
110
            self._new_cell_for_avatar(avatar)
111
            return True
112
        else:
113
            self.and_avatar_email(avatar.email).come_back_to_gui()
114
        return False
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
115
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
116
    def and_avatar_email(self, email):
117
        """
118
        Select the avatar from avatars collection
119
        in order to apply future actions
120
        """
121
        self.avatar = None
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
122
        if email and email in self.__avatars:
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
123
            self.avatar = self.__avatars[email]
124
        else:
125
            self.avatar = None
126
        return self
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
127
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
128
    def update_avatar_image_from_pixbuf_loader(self, loader):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
129
        """Replace the Gtk.Spinner with the given loader."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
130
        if self.avatar:
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
131
            self.avatar.image = Gtk.Image()
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
132
            self.avatar.image.set_from_pixbuf(loader.get_pixbuf())
133
            self.avatar.show_image()
134
            self.__displaying = self.avatar
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
135
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
136
    def come_back_to_gui(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
137
        """Render back avatar in the GUI."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
138
        if self.avatar:
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
139
            self.pack_start(self.avatar, True, True, 0)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
140
            self.__displaying = self.avatar
141
        else:
142
            self._show_no_email()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
143
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
144
    def _new_cell_for_avatar(self, avatar):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
145
        """Create a new cell in this box with a Gtk.Spinner."""
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
146
        avatar.show_spinner()
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
147
        self.pack_start(avatar, True, True, 0)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
148
        avatar.show()
149
        self.__displaying = avatar
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
150
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
151
    def _show_no_email(self):
734.1.32 by Curtis Hovey
Lint fixes while looking at thread issues.
152
        """Show a Gtk.Label with text 'No email'."""
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
153
        no_email = Gtk.Label(label=_i18n("No email"))
154
        self.pack_start(no_email, True, True, 0)
719.2.4 by zedtux
Moved Avatar and AvatarBox classes into avatarsbox file
155
        no_email.show()
156
157
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
158
class AvatarsBox(Gtk.HBox):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
159
    """GTK container for author and committer avatars."""
160
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
161
    def __init__(self):
734.1.34 by Curtis Hovey
Ensure the avatar threads are stopped when the widget is destroyed.
162
        super(AvatarsBox, self).__init__(homogeneous=False, spacing=10)
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
163
        self.__committer_box = None
164
        self.__authors_box = None
165
        self._init_gui()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
166
167
        # If more later you want to implement more avatar providers:
168
        # * Create a new class named AvatarProvider + provider_name that
169
        #   inherit from the AvatarProvider class.
170
        # * Implement a method that return url to use in the request.
171
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
172
        # For example, with Gravatar, the method return the complete url
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
173
        # with MD5 hash of the email address and put the value in a
174
        # gravatar_id field.
175
        # 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)
176
        provider = AvatarProviderGravatar()
177
        self.__worker = AvatarDownloaderWorker(
178
            provider.gravatar_id_for_email
179
        )
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
180
        # This callback method should be fired by all workers when a request
181
        # is done.
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
182
        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.
183
        self.connect('destroy', self.on_destroy)
184
185
    def on_destroy(self, widget):
186
        self.__worker.stop()
187
        if self.__worker.is_alive():
188
            self.__worker.join()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
189
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
190
    def add(self, username, role):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
191
        """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)
192
        """
193
        avatar = Avatar(username)
734.1.32 by Curtis Hovey
Lint fixes while looking at thread issues.
194
        is_shown = self._role_box_for("committer").showing(avatar)
195
        if (role == "author" and not is_shown) or role == "committer":
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
196
            if self._role_box_for(role).append_avatars_with(avatar):
197
                self.__worker.queue(avatar.email)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
198
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
199
    def merge(self, usernames, role):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
200
        """Add avatars from a list"""
719.2.2 by zedtux
Patched code following Jelmer's recommandations
201
        for username in usernames:
202
            self.add(username, role)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
203
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
204
    def reset(self):
205
        """
206
        Request a reset view for all boxes in order to show only avatars
207
        of the selected line in the revision view screen.
208
        """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
209
        for role in ("committer", "author"):
210
            self._role_box_for(role).reset_view()
211
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
212
    def _init_gui(self):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
213
        """Create boxes where avatars will be displayed."""
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
214
        # 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)
215
        # Committer
216
        self.__committer_box = AvatarBox()
217
        self.__committer_box.set_size_request(80, 80)
734.1.6 by Curtis Hovey
Added a very rough fix to see gannontation.
218
        self.pack_end(self.__committer_box, False, True, 0)
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
219
        self.__committer_box.show()
220
        # Authors
221
        self.__authors_box = AvatarBox()
734.1.6 by Curtis Hovey
Added a very rough fix to see gannontation.
222
        self.pack_end(self.__authors_box, False, True, 0)
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
223
        self.__authors_box.set_spacing(10)
224
        self.__authors_box.show()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
225
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
226
    def _update_avatar_from_response(self, response, email):
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
227
        """Callback method fired by avatar worker when finished.
228
229
        :param response: a urllib2.urlopen() return value.
230
        :param email: used to identify item from self.__avatars.
231
        """
734.1.25 by Curtis Hovey
Updated the pixbuf calls to gtk3.
232
        if email:
233
            # Convert downloaded image from provider to Gtk.Image
234
            loader = GdkPixbuf.PixbufLoader()
235
            loader.write(response.read())
236
            loader.close()
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
237
734.1.25 by Curtis Hovey
Updated the pixbuf calls to gtk3.
238
            for role in ["committer", "author"]:
734.1.32 by Curtis Hovey
Lint fixes while looking at thread issues.
239
                self._role_box_for(role).and_avatar_email(
240
                    email).update_avatar_image_from_pixbuf_loader(loader)
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
241
719.2.1 by zedtux
Added committers and authors avatars from Gravatar (urllib2 version)
242
    def _role_box_for(self, role):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
243
        """ Return the Gtk.HBox for the given role """
728 by Jelmer Vernooij
Cleanups, fix compatibility with older versions of pygtk.
244
        if role == "committer":
245
            return self.__committer_box
246
        else:
247
            return self.__authors_box