~ubuntu-branches/ubuntu/jaunty/system-config-printer/jaunty

1.1.42 by Till Kamppeter
Import upstream version 1.1.2+git20090125
1
#!/usr/bin/env python
2
3
## Copyright (C) 2008 Red Hat, Inc.
4
## Copyright (C) 2008 Tim Waugh <twaugh@redhat.com>
5
6
## This program 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 2 of the License, or
9
## (at your option) any later version.
10
11
## This program 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 this program; if not, write to the Free Software
18
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20
import gobject
21
import gtk
22
import subprocess
23
import threading
24
from gettext import gettext as _
25
from debug import *
26
27
class OperationCanceled(RuntimeError):
28
    pass
29
30
class Timed:
31
    def run (self):
32
        pass
33
34
    def cancel (self):
35
        pass
36
37
class TimedSubprocess(Timed):
38
    def __init__ (self, timeout=60000, parent=None, show_dialog=True,
39
                  **args):
40
        self.subp = subprocess.Popen (**args)
41
        self.output = dict()
42
        self.io_source = []
43
        self.watchers = 2
44
        self.timeout = timeout
45
        self.parent = parent
46
        self.show_dialog = show_dialog
47
        for f in [self.subp.stdout, self.subp.stderr]:
48
            source = gobject.io_add_watch (f,
49
                                           gobject.IO_IN |
50
                                           gobject.IO_HUP |
51
                                           gobject.IO_ERR,
52
                                           self.watcher)
53
            self.io_source.append (source)
54
55
        self.wait_window = None
56
57
    def run (self):
58
        if self.show_dialog:
59
            self.wait_source = gobject.timeout_add (1000,
60
                                                    self.show_wait_window)
61
62
        self.timeout_source = gobject.timeout_add (self.timeout,
63
                                                   self.do_timeout)
64
        gtk.main ()
65
        gobject.source_remove (self.timeout_source)
66
        if self.show_dialog:
67
            gobject.source_remove (self.wait_source)
68
        for source in self.io_source:
69
            gobject.source_remove (source)
70
        if self.wait_window != None:
71
            self.wait_window.destroy ()
72
        return (self.output.get (self.subp.stdout, '').split ('\n'),
73
                self.output.get (self.subp.stderr, '').split ('\n'),
74
                self.subp.poll ())
75
76
    def do_timeout (self):
77
        gtk.main_quit ()
78
        return False
79
80
    def watcher (self, source, condition):
81
        if condition & gobject.IO_IN:
82
            buffer = self.output.get (source, '')
83
            buffer += source.read ()
84
            self.output[source] = buffer
85
86
        if condition & gobject.IO_HUP:
87
            self.watchers -= 1
88
            if self.watchers == 0:
89
                gtk.main_quit ()
90
                return False
91
92
        return True
93
94
    def show_wait_window (self):
95
        wait = gtk.MessageDialog (self.parent,
96
                                  gtk.DIALOG_MODAL |
97
                                  gtk.DIALOG_DESTROY_WITH_PARENT,
98
                                  gtk.MESSAGE_INFO,
99
                                  gtk.BUTTONS_CANCEL,
100
                                  _("Please wait"))
101
        wait.connect ("delete_event", lambda *args: False)
102
        wait.connect ("response", self.wait_window_response)
103
        if self.parent:
104
            wait.set_transient_for (self.parent)
105
        wait.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
106
        wait.format_secondary_text (_("Gathering information"))
107
        wait.show_all ()
108
        self.wait_window = wait
109
        return False
110
111
    def wait_window_response (self, dialog, response):
112
        if response == gtk.RESPONSE_CANCEL:
113
            self.cancel ()
114
115
    def cancel (self):
116
        if self.watchers > 0:
117
            debugprint ("Command canceled")
118
            gtk.main_quit ()
119
            self.watchers = 0
120
121
class OperationThread(threading.Thread):
122
    def __init__ (self, target=None, args=(), kwargs={}):
123
        threading.Thread.__init__ (self)
124
        self.setDaemon (True)
125
        self.target = target
126
        self.args = args
127
        self.kwargs = kwargs
128
        self.exception = None
129
        self.result = None
130
131
    def run (self):
132
        try:
133
            debugprint ("Calling %s" % self.target)
134
            self.result = self.target (*self.args, **self.kwargs)
135
            debugprint ("Done")
136
        except Exception, e:
137
            debugprint ("Caught exception %s" % e)
138
            self.exception = e
139
140
    def collect_result (self):
141
        if self.isAlive ():
142
            # We've been canceled.
143
            raise OperationCanceled()
144
145
        if self.exception:
146
            raise self.exception
147
148
        return self.result
149
150
class TimedOperation(Timed):
151
    def __init__ (self, target, args=(), kwargs={}, parent=None,
152
                  show_dialog=False):
153
        self.wait_window = None
154
        self.parent = parent
155
        self.show_dialog = show_dialog
156
        self.thread = OperationThread (target=target,
157
                                       args=args,
158
                                       kwargs=kwargs)
159
        self.thread.start ()
160
161
    def run (self):
162
        if self.show_dialog:
163
            wait = gtk.MessageDialog (self.parent,
164
                                      gtk.DIALOG_MODAL |
165
                                      gtk.DIALOG_DESTROY_WITH_PARENT,
166
                                      gtk.MESSAGE_INFO,
167
                                      gtk.BUTTONS_CANCEL,
168
                                      _("Please wait"))
169
            wait.connect ("delete_event", lambda *args: False)
170
            wait.connect ("response", self.wait_window_response)
171
            if self.parent:
172
                wait.set_transient_for (self.parent)
173
174
            wait.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
175
            wait.format_secondary_text (_("Gathering information"))
176
            wait.show_all ()
177
178
        self.timeout_source = gobject.timeout_add (50, self.check_thread)
179
        gtk.main ()
180
        gobject.source_remove (self.timeout_source)
181
        if self.show_dialog:
182
            wait.destroy ()
183
184
        return self.thread.collect_result ()
185
186
    def check_thread (self):
187
        if self.thread.isAlive ():
188
            # Thread still running.
189
            return True
190
191
        # Thread has finished.  Stop the sub-loop.
192
        gtk.main_quit ()
193
        return False
194
195
    def wait_window_response (self, dialog, response):
196
        if response == gtk.RESPONSE_CANCEL:
197
            self.cancel ()
198
199
    def cancel (self):
200
        debugprint ("Command canceled")
201
        gtk.main_quit ()