/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to ui.py

  • Committer: Jelmer Vernooij
  • Date: 2012-03-16 17:28:20 UTC
  • mto: This revision was merged to the branch mainline in revision 793.
  • Revision ID: jelmer@samba.org-20120316172820-ohpb9bvgo63k2n8u
use register-lazy

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2006 Szilveszter Farkas <szilveszter.farkas@gmail.com>
 
2
# Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org>
2
3
 
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
18
19
"""GTK UI
19
20
"""
20
21
 
21
 
import gtk
22
 
import sys
 
22
from gi.repository import Gtk
23
23
 
24
 
import bzrlib.progress
25
 
from bzrlib.symbol_versioning import (deprecated_method, 
26
 
        zero_eight)
27
24
from bzrlib.ui import UIFactory
28
25
 
29
26
 
30
 
class PromptDialog(gtk.Dialog):
31
 
    """ Prompt the user for a yes/no answer. """
32
 
    def __init__(self, prompt):
33
 
        gtk.Dialog.__init__(self)
34
 
        
35
 
        label = gtk.Label(prompt)
36
 
        self.vbox.pack_start(label, padding=10)
37
 
        
38
 
        self.vbox.show_all()
39
 
 
40
 
        self.add_buttons(gtk.STOCK_YES, gtk.RESPONSE_YES, gtk.STOCK_NO, gtk.RESPONSE_NO)
41
 
 
42
 
 
43
 
class PasswordDialog(gtk.Dialog):
 
27
def main_iteration(function):
 
28
    def with_main_iteration(self, *args, **kwargs):
 
29
        result = function(self, *args, **kwargs)
 
30
        while Gtk.events_pending():
 
31
            Gtk.main_iteration_do(False)
 
32
        return result
 
33
    return with_main_iteration
 
34
 
 
35
 
 
36
class PromptDialog(Gtk.MessageDialog):
 
37
    """Prompt the user for a yes/no answer."""
 
38
 
 
39
    def __init__(self, prompt, parent=None):
 
40
        super(PromptDialog, self).__init__(
 
41
            parent, Gtk.DialogFlags.DESTROY_WITH_PARENT,
 
42
            Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, prompt)
 
43
 
 
44
 
 
45
class InfoDialog(Gtk.MessageDialog):
 
46
    """Show the user an informational message."""
 
47
 
 
48
    MESSAGE_TYPE = Gtk.MessageType.INFO
 
49
 
 
50
    def __init__(self, prompt, parent=None):
 
51
        super(InfoDialog, self).__init__(
 
52
            parent, Gtk.DialogFlags.DESTROY_WITH_PARENT,
 
53
            self.MESSAGE_TYPE, Gtk.ButtonsType.CLOSE, prompt)
 
54
 
 
55
 
 
56
class WarningDialog(InfoDialog):
 
57
    """Show the user a warning message."""
 
58
 
 
59
    MESSAGE_TYPE = Gtk.MessageType.WARNING
 
60
 
 
61
 
 
62
class ErrorDialog(InfoDialog):
 
63
    """Show the user a warning message."""
 
64
 
 
65
    MESSAGE_TYPE = Gtk.MessageType.ERROR
 
66
 
 
67
 
 
68
class GtkProgressBar(Gtk.ProgressBar):
 
69
 
 
70
    def __init__(self):
 
71
        super(GtkProgressBar, self).__init__()
 
72
        self.set_fraction(0.0)
 
73
        self.current = None
 
74
        self.total = None
 
75
 
 
76
    @main_iteration
 
77
    def tick(self):
 
78
        self.show()
 
79
        self.pulse()
 
80
 
 
81
    @main_iteration
 
82
    def update(self, msg=None, current_cnt=None, total_cnt=None):
 
83
        self.show()
 
84
        if current_cnt is not None:
 
85
            self.current = current_cnt
 
86
        if total_cnt is not None:
 
87
            self.total = total_cnt
 
88
        if msg is not None:
 
89
            self.set_text(msg)
 
90
        if None not in (self.current, self.total):
 
91
            fraction = float(self.current) / self.total
 
92
            if fraction < 0.0 or fraction > 1.0:
 
93
                raise ValueError
 
94
            self.set_fraction(fraction)
 
95
 
 
96
    @main_iteration
 
97
    def finished(self):
 
98
        self.set_fraction(0.0)
 
99
        self.current = None
 
100
        self.total = None
 
101
        self.hide()
 
102
 
 
103
    def clear(self):
 
104
        self.finished()
 
105
 
 
106
 
 
107
class ProgressContainerMixin:
 
108
    """Expose GtkProgressBar methods to a container class."""
 
109
 
 
110
    def tick(self, *args, **kwargs):
 
111
        self.show_all()
 
112
        self.pb.tick(*args, **kwargs)
 
113
 
 
114
    def update(self, *args, **kwargs):
 
115
        self.show_all()
 
116
        self.pb.update(*args, **kwargs)
 
117
 
 
118
    def finished(self):
 
119
        self.hide()
 
120
        self.pb.finished()
 
121
 
 
122
    def clear(self):
 
123
        self.hide()
 
124
        self.pb.clear()
 
125
 
 
126
 
 
127
class ProgressBarWindow(ProgressContainerMixin, Gtk.Window):
 
128
 
 
129
    def __init__(self):
 
130
        super(ProgressBarWindow, self).__init__(type=Gtk.WindowType.TOPLEVEL)
 
131
        self.set_border_width(0)
 
132
        self.set_title("Progress")
 
133
        self.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
 
134
        self.pb = GtkProgressBar()
 
135
        self.add(self.pb)
 
136
        self.resize(250, 15)
 
137
        self.set_resizable(False)
 
138
 
 
139
 
 
140
class ProgressPanel(ProgressContainerMixin, Gtk.Box):
 
141
 
 
142
    def __init__(self):
 
143
        super(ProgressPanel, self).__init__(Gtk.Orientation.HORIZONTAL, 5)
 
144
        image_loading = Gtk.Image.new_from_stock(Gtk.STOCK_REFRESH,
 
145
                                                 Gtk.IconSize.BUTTON)
 
146
        image_loading.show()
 
147
 
 
148
        self.pb = GtkProgressBar()
 
149
        self.set_border_width(5)
 
150
        self.pack_start(image_loading, False, False, 0)
 
151
        self.pack_start(self.pb, True, True, 0)
 
152
 
 
153
 
 
154
class PasswordDialog(Gtk.Dialog):
44
155
    """ Prompt the user for a password. """
 
156
 
45
157
    def __init__(self, prompt):
46
 
        gtk.Dialog.__init__(self)
47
 
        
48
 
        label = gtk.Label(prompt)
49
 
        self.vbox.pack_start(label, padding=10)
50
 
        
51
 
        self.entry = gtk.Entry()
 
158
        super(PasswordDialog, self).__init__()
 
159
 
 
160
        label = Gtk.Label(label=prompt)
 
161
        self.get_content_area().pack_start(label, True, True, 10)
 
162
 
 
163
        self.entry = Gtk.Entry()
52
164
        self.entry.set_visibility(False)
53
 
        self.vbox.pack_end(self.entry, padding=10)
54
 
        
55
 
        self.vbox.show_all()
56
 
        
57
 
        self.add_buttons(gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
58
 
    
 
165
        self.get_content_area().pack_end(self.entry, False, False, 10)
 
166
 
 
167
        self.get_content_area().show_all()
 
168
 
 
169
        self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK,
 
170
                         Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
 
171
 
59
172
    def _get_passwd(self):
60
173
        return self.entry.get_text()
61
174
 
63
176
 
64
177
 
65
178
class GtkUIFactory(UIFactory):
66
 
    """A UI factory for GTK user interefaces."""
67
 
 
68
 
    def __init__(self,
69
 
                 bar_type=None,
70
 
                 stdout=None,
71
 
                 stderr=None):
72
 
        """Create a GtkUIFactory.
73
 
 
74
 
        :param bar_type: The type of progress bar to create. It defaults to 
75
 
                         letting the bzrlib.progress.ProgressBar factory auto
76
 
                         select.
77
 
        """
 
179
    """A UI factory for GTK user interfaces."""
 
180
 
 
181
    def __init__(self):
 
182
        """Create a GtkUIFactory"""
78
183
        super(GtkUIFactory, self).__init__()
79
 
        self._bar_type = bar_type
80
 
        if stdout is None:
81
 
            self.stdout = sys.stdout
82
 
        else:
83
 
            self.stdout = stdout
84
 
        if stderr is None:
85
 
            self.stderr = sys.stderr
86
 
        else:
87
 
            self.stderr = stderr
 
184
        self.set_progress_bar_widget(None)
 
185
 
 
186
    def set_progress_bar_widget(self, widget):
 
187
        self._progress_bar_widget = widget
88
188
 
89
189
    def get_boolean(self, prompt):
90
190
        """GtkDialog with yes/no answers"""
91
191
        dialog = PromptDialog(prompt)
92
192
        response = dialog.run()
93
193
        dialog.destroy()
94
 
        if response == gtk.RESPONSE_YES:
95
 
            return True
96
 
        else:
97
 
            return False
98
 
        
99
 
    @deprecated_method(zero_eight)
100
 
    def progress_bar(self):
101
 
        """See UIFactory.nested_progress_bar()."""
102
 
        # this in turn is abstract, and creates either a tty or dots
103
 
        # bar depending on what we think of the terminal
104
 
        return bzrlib.progress.ProgressBar()
 
194
        return (response == Gtk.ResponseType.YES)
 
195
 
 
196
    def show_message(self, msg):
 
197
        """See UIFactory.show_message."""
 
198
        dialog = InfoDialog(msg)
 
199
        dialog.run()
 
200
        dialog.destroy()
 
201
 
 
202
    def show_warning(self, msg):
 
203
        """See UIFactory.show_warning."""
 
204
        dialog = WarningDialog(msg)
 
205
        dialog.run()
 
206
        dialog.destroy()
 
207
 
 
208
    def show_error(self, msg):
 
209
        """See UIFactory.show_error."""
 
210
        dialog = ErrorDialog(msg)
 
211
        dialog.run()
 
212
        dialog.destroy()
 
213
 
 
214
    def show_user_warning(self, warning_id, **message_args):
 
215
        """See UIFactory.show_user_warning."""
 
216
        if warning_id not in self.suppressed_warnings:
 
217
            message = self.format_user_warning(warning_id, message_args)
 
218
            self.show_warning(message)
105
219
 
106
220
    def get_password(self, prompt='', **kwargs):
107
221
        """Prompt the user for a password.
110
224
        :param kwargs: Arguments which will be expanded into the prompt.
111
225
                       This lets front ends display different things if
112
226
                       they so choose.
113
 
        :return: The password string, return None if the user 
 
227
        :return: The password string, return None if the user
114
228
                 canceled the request.
115
229
        """
116
230
        dialog = PasswordDialog(prompt % kwargs)
117
231
        response = dialog.run()
118
232
        passwd = dialog.passwd
119
233
        dialog.destroy()
120
 
        if response == gtk.RESPONSE_OK:
 
234
        if response == Gtk.ResponseType.OK:
121
235
            return passwd
122
236
        else:
123
237
            return None
124
238
 
125
 
    def nested_progress_bar(self):
126
 
        """Return a nested progress bar.
127
 
        
128
 
        The actual bar type returned depends on the progress module which
129
 
        may return a tty or dots bar depending on the terminal.
130
 
        
131
 
        FIXME: It should return a GtkProgressBar actually.
132
 
        """
133
 
        if self._progress_bar_stack is None:
134
 
            self._progress_bar_stack = bzrlib.progress.ProgressBarStack(
135
 
                klass=self._bar_type)
136
 
        return self._progress_bar_stack.get_nested()
137
 
 
138
 
    def clear_term(self):
139
 
        """Prepare the terminal for output.
140
 
 
141
 
        It has no sense when talking about GTK."""
142
 
        pass
 
239
    def _progress_all_finished(self):
 
240
        """See UIFactory._progress_all_finished."""
 
241
        pbw = self._progress_bar_widget
 
242
        if pbw:
 
243
            pbw.finished()
 
244
 
 
245
    def _ensure_progress_widget(self):
 
246
        if self._progress_bar_widget is None:
 
247
            # Default to a window since nobody gave us a better means to report
 
248
            # progress.
 
249
            self.set_progress_bar_widget(ProgressBarWindow())
 
250
 
 
251
    def _progress_updated(self, task):
 
252
        """See UIFactory._progress_updated."""
 
253
        self._ensure_progress_widget()
 
254
        self._progress_bar_widget.update(task.msg,
 
255
                                         task.current_cnt, task.total_cnt)
 
256
 
 
257
    def report_transport_activity(self, transport, byte_count, direction):
 
258
        """See UIFactory.report_transport_activity."""
 
259
        self._ensure_progress_widget()
 
260
        self._progress_bar_widget.tick()