1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1 |
## Copyright (C) 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
2 |
## Authors:
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
3 |
## Tim Waugh <twaugh@redhat.com>
|
4 |
## Jiri Popelka <jpopelka@redhat.com>
|
|
5 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
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 asyncconn |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
21 |
import authconn |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
22 |
import cups |
23 |
import dbus |
|
24 |
import dbus.glib |
|
25 |
import dbus.service |
|
26 |
import pynotify |
|
27 |
import gettext |
|
28 |
import glib |
|
1.1.52
by Till Kamppeter
Import upstream version 1.2.0+20100408 |
29 |
import gobject |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
30 |
import gtk |
31 |
import gtk.gdk |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
32 |
from gui import GtkGUI |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
33 |
import monitor |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
34 |
import os, shutil |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
35 |
import pango |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
36 |
import pwd |
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
37 |
import smburi |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
38 |
import subprocess |
39 |
import sys |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
40 |
import time |
41 |
import urllib |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
42 |
from xml.sax import saxutils |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
43 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
44 |
from debug import * |
45 |
import config |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
46 |
import statereason |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
47 |
import errordialogs |
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
48 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
49 |
try: |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
50 |
import gnomekeyring |
51 |
USE_KEYRING=True |
|
52 |
except ImportError: |
|
53 |
USE_KEYRING=False |
|
54 |
||
55 |
from gettext import gettext as _ |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
56 |
from statereason import StateReason |
57 |
||
58 |
pkgdata = config.pkgdatadir |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
59 |
ICON="printer" |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
60 |
ICON_SIZE=22 |
1.1.54
by Till Kamppeter
Import upstream version 1.2.3+20100723 |
61 |
SEARCHING_ICON="document-print-preview" |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
62 |
|
63 |
# We need to call pynotify.init before we can check the server for caps
|
|
1.1.45
by Till Kamppeter
Import upstream version 1.1.10+git20090725 |
64 |
pynotify.init('System Config Printer Notification') |
65 |
||
66 |
class PrinterURIIndex: |
|
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
67 |
def __init__ (self, names=[]): |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
68 |
self.printer = {} |
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
69 |
self.names = names |
70 |
self._collect_names () |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
71 |
|
72 |
def _collect_names (self, connection=None): |
|
73 |
if not self.names: |
|
74 |
return
|
|
75 |
||
76 |
if not connection: |
|
77 |
try: |
|
78 |
c = cups.Connection () |
|
79 |
except RuntimeError: |
|
80 |
return
|
|
81 |
||
82 |
for name in self.names: |
|
83 |
self.add_printer (name, connection=c) |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
84 |
|
85 |
self.names = [] |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
86 |
|
87 |
def add_printer (self, printer, connection=None): |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
88 |
try: |
1.1.52
by Till Kamppeter
Import upstream version 1.2.0+20100408 |
89 |
self._map_printer (name=printer, connection=connection) |
90 |
except KeyError: |
|
91 |
return
|
|
92 |
||
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
93 |
def update_from_attrs (self, printer, attrs): |
94 |
uris = [] |
|
95 |
if attrs.has_key ('printer-uri-supported'): |
|
96 |
uri_supported = attrs['printer-uri-supported'] |
|
97 |
if type (uri_supported) != list: |
|
98 |
uri_supported = [uri_supported] |
|
99 |
uris.extend (uri_supported) |
|
100 |
if attrs.has_key ('notify-printer-uri'): |
|
101 |
uris.append (attrs['notify-printer-uri']) |
|
102 |
if attrs.has_key ('printer-more-info'): |
|
103 |
uris.append (attrs['printer-more-info']) |
|
104 |
||
105 |
for uri in uris: |
|
106 |
self.printer[uri] = printer |
|
107 |
||
108 |
def remove_printer (self, printer): |
|
109 |
# Remove references to this printer in the URI map.
|
|
110 |
self._collect_names () |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
111 |
uris = self.printer.keys () |
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
112 |
for uri in uris: |
113 |
if self.printer[uri] == printer: |
|
114 |
del self.printer[uri] |
|
115 |
||
116 |
def lookup (self, uri, connection=None): |
|
117 |
self._collect_names () |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
118 |
try: |
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
119 |
return self.printer[uri] |
120 |
except KeyError: |
|
121 |
return self._map_printer (uri=uri, connection=connection) |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
122 |
|
123 |
def all_printer_names (self): |
|
124 |
self._collect_names () |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
125 |
return set (self.printer.values ()) |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
126 |
|
127 |
def lookup_cached_by_name (self, name): |
|
128 |
self._collect_names () |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
129 |
for uri, printer in self.printer.iteritems (): |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
130 |
if printer == name: |
131 |
return uri |
|
132 |
||
133 |
raise KeyError |
|
134 |
||
135 |
def _map_printer (self, uri=None, name=None, connection=None): |
|
136 |
try: |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
137 |
if connection == None: |
138 |
connection = cups.Connection () |
|
139 |
||
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
140 |
r = ['printer-name', 'printer-uri-supported', 'printer-more-info'] |
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
141 |
if uri != None: |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
142 |
attrs = connection.getPrinterAttributes (uri=uri, |
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
143 |
requested_attributes=r) |
144 |
else: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
145 |
attrs = connection.getPrinterAttributes (name, |
146 |
requested_attributes=r) |
|
147 |
except RuntimeError: |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
148 |
# cups.Connection() failed
|
149 |
raise KeyError |
|
150 |
except cups.IPPError: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
151 |
# URI not known.
|
152 |
raise KeyError |
|
153 |
||
154 |
name = attrs['printer-name'] |
|
155 |
self.update_from_attrs (name, attrs) |
|
156 |
if uri != None: |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
157 |
self.printer[uri] = name |
158 |
return name |
|
159 |
||
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
160 |
|
161 |
class CancelJobsOperation(gobject.GObject): |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
162 |
__gsignals__ = { |
163 |
'destroy': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []), |
|
164 |
'job-deleted': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
|
165 |
[gobject.TYPE_INT]), |
|
166 |
'ipp-error': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, |
|
167 |
[gobject.TYPE_INT, gobject.TYPE_PYOBJECT]), |
|
168 |
'finished': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []) |
|
169 |
}
|
|
170 |
||
171 |
def __init__ (self, parent, host, port, encryption, jobids, purge_job): |
|
172 |
gobject.GObject.__init__ (self) |
|
173 |
self.jobids = list (jobids) |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
174 |
self.purge_job = purge_job |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
175 |
self.host = host |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
176 |
self.port = port |
177 |
self.encryption = encryption |
|
178 |
if purge_job: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
179 |
if len(self.jobids) > 1: |
180 |
dialog_title = _("Delete Jobs") |
|
181 |
dialog_label = _("Do you really want to delete these jobs?") |
|
182 |
else: |
|
183 |
dialog_title = _("Delete Job") |
|
184 |
dialog_label = _("Do you really want to delete this job?") |
|
185 |
else: |
|
186 |
if len(self.jobids) > 1: |
|
187 |
dialog_title = _("Cancel Jobs") |
|
188 |
dialog_label = _("Do you really want to cancel these jobs?") |
|
189 |
else: |
|
190 |
dialog_title = _("Cancel Job") |
|
191 |
dialog_label = _("Do you really want to cancel this job?") |
|
192 |
||
193 |
dialog = gtk.Dialog (dialog_title, parent, |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
194 |
gtk.DIALOG_MODAL | |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
195 |
gtk.DIALOG_DESTROY_WITH_PARENT | |
196 |
gtk.DIALOG_NO_SEPARATOR, |
|
197 |
(_("Keep Printing"), gtk.RESPONSE_NO, |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
198 |
dialog_title, gtk.RESPONSE_YES)) |
199 |
dialog.set_default_response (gtk.RESPONSE_NO) |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
200 |
dialog.set_border_width (6) |
201 |
dialog.set_resizable (False) |
|
202 |
hbox = gtk.HBox (False, 12) |
|
203 |
image = gtk.Image () |
|
204 |
image.set_from_stock (gtk.STOCK_DIALOG_QUESTION, gtk.ICON_SIZE_DIALOG) |
|
205 |
image.set_alignment (0.0, 0.0) |
|
206 |
hbox.pack_start (image, False, False, 0) |
|
207 |
label = gtk.Label (dialog_label) |
|
208 |
label.set_line_wrap (True) |
|
209 |
label.set_alignment (0.0, 0.0) |
|
210 |
hbox.pack_start (label, False, False, 0) |
|
211 |
dialog.vbox.pack_start (hbox, False, False, 0) |
|
212 |
dialog.connect ("response", self.on_job_cancel_prompt_response) |
|
213 |
dialog.connect ("delete-event", self.on_job_cancel_prompt_delete) |
|
214 |
dialog.show_all () |
|
215 |
self.dialog = dialog |
|
216 |
self.connection = None |
|
217 |
debugprint ("+%s" % self) |
|
218 |
||
219 |
def __del__ (self): |
|
220 |
debugprint ("-%s" % self) |
|
221 |
||
222 |
def do_destroy (self): |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
223 |
if self.connection: |
224 |
self.connection.destroy () |
|
225 |
self.connection = None |
|
226 |
||
227 |
if self.dialog: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
228 |
self.dialog.destroy () |
229 |
self.dialog = None |
|
230 |
||
231 |
debugprint ("DESTROY: %s" % self) |
|
232 |
||
233 |
def destroy (self): |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
234 |
self.emit ('destroy') |
235 |
||
236 |
def on_job_cancel_prompt_delete (self, dialog, event): |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
237 |
self.on_job_cancel_prompt_response (dialog, gtk.RESPONSE_NO) |
238 |
||
239 |
def on_job_cancel_prompt_response (self, dialog, response): |
|
240 |
dialog.destroy () |
|
241 |
self.dialog = None |
|
242 |
||
243 |
if response != gtk.RESPONSE_YES: |
|
244 |
self.emit ('finished') |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
245 |
return
|
246 |
||
247 |
if len(self.jobids) == 0: |
|
248 |
self.emit ('finished') |
|
249 |
return
|
|
250 |
||
251 |
asyncconn.Connection (host=self.host, |
|
252 |
port=self.port, |
|
253 |
encryption=self.encryption, |
|
254 |
reply_handler=self._connected, |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
255 |
error_handler=self._connect_failed) |
256 |
||
257 |
def _connect_failed (self, connection, exc): |
|
258 |
debugprint ("CancelJobsOperation._connect_failed %s:%s" % (connection, repr (exc))) |
|
259 |
||
260 |
def _connected (self, connection, result): |
|
261 |
self.connection = connection |
|
262 |
||
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
263 |
if self.purge_job: |
264 |
operation = _("deleting job") |
|
265 |
else: |
|
266 |
operation = _("canceling job") |
|
267 |
||
268 |
self.connection._begin_operation (operation) |
|
269 |
self.connection.cancelJob (self.jobids[0], self.purge_job, |
|
270 |
reply_handler=self.cancelJob_finish, |
|
271 |
error_handler=self.cancelJob_error) |
|
272 |
||
273 |
def cancelJob_error (self, connection, exc): |
|
274 |
debugprint ("cancelJob_error %s:%s" % (connection, repr (exc))) |
|
275 |
if type (exc) == cups.IPPError: |
|
276 |
(e, m) = exc.args |
|
277 |
if (e != cups.IPP_NOT_POSSIBLE and |
|
278 |
e != cups.IPP_NOT_FOUND): |
|
279 |
self.emit ('ipp-error', self.jobids[0], exc) |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
280 |
self.cancelJob_finish(connection, None) |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
281 |
else: |
282 |
self.connection._end_operation () |
|
283 |
self.connection.destroy () |
|
284 |
self.connection = None |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
285 |
self.emit ('ipp-error', self.jobids[0], exc) |
286 |
# Give up.
|
|
287 |
self.emit ('finished') |
|
288 |
return
|
|
289 |
||
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
290 |
def cancelJob_finish (self, connection, result): |
291 |
debugprint ("cancelJob_finish %s:%s" % (connection, repr (result))) |
|
292 |
self.emit ('job-deleted', self.jobids[0]) |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
293 |
del self.jobids[0] |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
294 |
if not self.jobids: |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
295 |
# Last job canceled.
|
296 |
self.connection._end_operation () |
|
297 |
self.connection.destroy () |
|
298 |
self.connection = None |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
299 |
self.emit ('finished') |
300 |
return
|
|
301 |
else: |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
302 |
# there are other jobs to cancel/delete
|
303 |
connection.cancelJob (self.jobids[0], self.purge_job, |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
304 |
reply_handler=self.cancelJob_finish, |
305 |
error_handler=self.cancelJob_error) |
|
306 |
||
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
307 |
gobject.type_register (CancelJobsOperation) |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
308 |
|
309 |
class JobViewer (GtkGUI): |
|
310 |
required_job_attributes = set(['job-k-octets', |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
311 |
'job-name', |
312 |
'job-originating-user-name', |
|
313 |
'job-printer-uri', |
|
314 |
'job-state', |
|
315 |
'time-at-creation', |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
316 |
'job-preserved']) |
317 |
||
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
318 |
__gsignals__ = { |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
319 |
'finished': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []) |
320 |
}
|
|
321 |
||
322 |
def __init__(self, bus=None, loop=None, |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
323 |
applet=False, suppress_icon_hide=False, |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
324 |
my_jobs=True, specific_dests=None, |
325 |
parent=None): |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
326 |
gobject.GObject.__init__ (self) |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
327 |
self.loop = loop |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
328 |
self.applet = applet |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
329 |
self.suppress_icon_hide = suppress_icon_hide |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
330 |
self.my_jobs = my_jobs |
331 |
self.specific_dests = specific_dests |
|
332 |
notify_caps = pynotify.get_server_caps () |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
333 |
self.notify_has_actions = "actions" in notify_caps |
334 |
self.notify_has_persistence = "persistence" in notify_caps |
|
335 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
336 |
self.jobs = {} |
337 |
self.jobiters = {} |
|
338 |
self.jobids = [] |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
339 |
self.jobs_attrs = {} # dict of jobid->(GtkListStore, page_index) |
340 |
self.active_jobs = set() # of job IDs |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
341 |
self.stopped_job_prompts = set() # of job IDs |
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
342 |
self.printer_state_reasons = {} |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
343 |
self.num_jobs_when_hidden = 0 |
344 |
self.connecting_to_device = {} # dict of printer->time first seen |
|
345 |
self.state_reason_notifications = {} |
|
346 |
self.auth_info_dialogs = {} # by job ID |
|
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
347 |
self.job_creation_times_timer = None |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
348 |
self.new_printer_notifications = {} |
349 |
self.completed_job_notifications = {} |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
350 |
self.authenticated_jobs = set() # of job IDs |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
351 |
self.ops = [] |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
352 |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
353 |
self.getWidgets ({"JobsWindow": |
354 |
["JobsWindow", |
|
355 |
"treeview", |
|
356 |
"statusbar", |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
357 |
"toolbar"], |
358 |
"statusicon_popupmenu": |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
359 |
["statusicon_popupmenu"]}, |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
360 |
|
361 |
domain=config.PACKAGE) |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
362 |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
363 |
job_action_group = gtk.ActionGroup ("JobActionGroup") |
364 |
job_action_group.add_actions ([ |
|
365 |
("cancel-job", gtk.STOCK_CANCEL, _("_Cancel"), None, |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
366 |
_("Cancel selected jobs"), self.on_job_cancel_activate), |
367 |
("delete-job", gtk.STOCK_DELETE, _("_Delete"), None, |
|
368 |
_("Delete selected jobs"), self.on_job_delete_activate), |
|
369 |
("hold-job", gtk.STOCK_MEDIA_PAUSE, _("_Hold"), None, |
|
370 |
_("Hold selected jobs"), self.on_job_hold_activate), |
|
371 |
("release-job", gtk.STOCK_MEDIA_PLAY, _("_Release"), None, |
|
372 |
_("Release selected jobs"), self.on_job_release_activate), |
|
373 |
("reprint-job", gtk.STOCK_REDO, _("Re_print"), None, |
|
374 |
_("Reprint selected jobs"), self.on_job_reprint_activate), |
|
375 |
("retrieve-job", gtk.STOCK_SAVE_AS, _("Re_trieve"), None, |
|
376 |
_("Retrieve selected jobs"), self.on_job_retrieve_activate), |
|
377 |
("move-job", None, _("_Move To"), None, None, None), |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
378 |
("authenticate-job", None, _("_Authenticate"), None, None, |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
379 |
self.on_job_authenticate_activate), |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
380 |
("job-attributes", None, _("_View Attributes"), None, None, |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
381 |
self.on_job_attributes_activate), |
382 |
("close", gtk.STOCK_CLOSE, None, "<ctrl>w", |
|
383 |
_("Close this window"), self.on_delete_event) |
|
384 |
])
|
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
385 |
self.job_ui_manager = gtk.UIManager () |
386 |
self.job_ui_manager.insert_action_group (job_action_group, -1) |
|
387 |
self.job_ui_manager.add_ui_from_string ( |
|
388 |
"""
|
|
389 |
<ui>
|
|
390 |
<accelerator action="cancel-job"/>
|
|
391 |
<accelerator action="delete-job"/>
|
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
392 |
<accelerator action="hold-job"/>
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
393 |
<accelerator action="release-job"/>
|
394 |
<accelerator action="reprint-job"/>
|
|
395 |
<accelerator action="retrieve-job"/>
|
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
396 |
<accelerator action="move-job"/>
|
397 |
<accelerator action="authenticate-job"/>
|
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
398 |
<accelerator action="job-attributes"/>
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
399 |
<accelerator action="close"/>
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
400 |
</ui>
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
401 |
"""
|
402 |
)
|
|
403 |
self.job_ui_manager.ensure_update () |
|
404 |
self.JobsWindow.add_accel_group (self.job_ui_manager.get_accel_group ()) |
|
405 |
self.job_context_menu = gtk.Menu () |
|
406 |
for action_name in ["cancel-job", |
|
407 |
"delete-job", |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
408 |
"hold-job", |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
409 |
"release-job", |
410 |
"reprint-job", |
|
411 |
"retrieve-job", |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
412 |
"move-job", |
413 |
None, |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
414 |
"authenticate-job", |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
415 |
"job-attributes"]: |
416 |
if not action_name: |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
417 |
item = gtk.SeparatorMenuItem () |
418 |
else: |
|
419 |
action = job_action_group.get_action (action_name) |
|
420 |
action.set_sensitive (False) |
|
421 |
item = action.create_menu_item () |
|
422 |
||
423 |
if action_name == 'move-job': |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
424 |
self.move_job_menuitem = item |
425 |
printers = gtk.Menu () |
|
426 |
item.set_submenu (printers) |
|
427 |
||
428 |
item.show () |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
429 |
self.job_context_menu.append (item) |
430 |
||
431 |
for action_name in ["cancel-job", |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
432 |
"delete-job", |
433 |
"hold-job", |
|
434 |
"release-job", |
|
435 |
"reprint-job", |
|
436 |
"retrieve-job", |
|
437 |
"close"]: |
|
438 |
action = job_action_group.get_action (action_name) |
|
439 |
action.set_sensitive (action_name == "close") |
|
440 |
action.set_is_important (action_name == "close") |
|
441 |
item = action.create_tool_item () |
|
442 |
item.show () |
|
443 |
self.toolbar.insert (item, -1) |
|
444 |
||
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
445 |
for skip, ellipsize, name, setter in \ |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
446 |
[(False, False, _("Job"), self._set_job_job_number_text), |
447 |
(True, False, _("User"), self._set_job_user_text), |
|
448 |
(False, True, _("Document"), self._set_job_document_text), |
|
449 |
(False, True, _("Printer"), self._set_job_printer_text), |
|
450 |
(False, False, _("Size"), self._set_job_size_text)]: |
|
451 |
if applet and skip: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
452 |
# Skip the user column when running as applet.
|
453 |
continue
|
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
454 |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
455 |
cell = gtk.CellRendererText() |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
456 |
if ellipsize: |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
457 |
# Ellipsize the 'Document' and 'Printer' columns.
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
458 |
cell.set_property ("ellipsize", pango.ELLIPSIZE_END) |
459 |
cell.set_property ("width-chars", 20) |
|
460 |
column = gtk.TreeViewColumn(name, cell) |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
461 |
column.set_cell_data_func (cell, setter) |
462 |
column.set_resizable(True) |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
463 |
self.treeview.append_column(column) |
464 |
||
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
465 |
cell = gtk.CellRendererText () |
466 |
column = gtk.TreeViewColumn (_("Time submitted"), cell, text=1) |
|
467 |
column.set_resizable (True) |
|
468 |
self.treeview.append_column (column) |
|
469 |
||
470 |
column = gtk.TreeViewColumn (_("Status")) |
|
471 |
icon = gtk.CellRendererPixbuf () |
|
472 |
column.pack_start (icon, False) |
|
473 |
text = gtk.CellRendererText () |
|
474 |
text.set_property ("ellipsize", pango.ELLIPSIZE_END) |
|
475 |
text.set_property ("width-chars", 20) |
|
476 |
column.pack_start (text, True) |
|
477 |
column.set_cell_data_func (icon, self._set_job_status_icon) |
|
478 |
column.set_cell_data_func (text, self._set_job_status_text) |
|
479 |
self.treeview.append_column (column) |
|
480 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
481 |
self.store = gtk.TreeStore(int, str) |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
482 |
self.store.set_sort_column_id (0, gtk.SORT_DESCENDING) |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
483 |
self.treeview.set_model(self.store) |
484 |
self.treeview.set_rules_hint (True) |
|
485 |
self.selection = self.treeview.get_selection() |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
486 |
self.selection.set_mode(gtk.SELECTION_MULTIPLE) |
487 |
self.selection.connect('changed', self.on_selection_changed) |
|
488 |
self.treeview.connect ('button_release_event', |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
489 |
self.on_treeview_button_release_event) |
490 |
self.treeview.connect ('popup-menu', self.on_treeview_popup_menu) |
|
491 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
492 |
self.JobsWindow.set_icon_name (ICON) |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
493 |
self.JobsWindow.hide () |
494 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
495 |
if specific_dests: |
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
496 |
the_dests = reduce (lambda x, y: x + ", " + y, specific_dests) |
497 |
||
498 |
if my_jobs: |
|
499 |
if specific_dests: |
|
500 |
title = _("my jobs on %s") % the_dests |
|
501 |
else: |
|
502 |
title = _("my jobs") |
|
503 |
else: |
|
504 |
if specific_dests: |
|
505 |
title = "%s" % the_dests |
|
506 |
else: |
|
507 |
title = _("all jobs") |
|
508 |
self.JobsWindow.set_title (_("Document Print Status (%s)") % title) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
509 |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
510 |
if parent: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
511 |
self.JobsWindow.set_transient_for (parent) |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
512 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
513 |
def load_icon(theme, icon): |
1.1.54
by Till Kamppeter
Import upstream version 1.2.3+20100723 |
514 |
try: |
515 |
pixbuf = theme.load_icon (icon, ICON_SIZE, 0) |
|
516 |
except gobject.GError: |
|
517 |
debugprint ("No %s icon available" % icon) |
|
518 |
# Just create an empty pixbuf.
|
|
519 |
pixbuf = gtk.gdk.Pixbuf (gtk.gdk.COLORSPACE_RGB, |
|
520 |
True, 8, ICON_SIZE, ICON_SIZE) |
|
521 |
pixbuf.fill (0) |
|
522 |
return pixbuf |
|
523 |
||
524 |
theme = gtk.icon_theme_get_default () |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
525 |
self.icon_jobs = load_icon (theme, ICON) |
1.1.54
by Till Kamppeter
Import upstream version 1.2.3+20100723 |
526 |
self.icon_jobs_processing = load_icon (theme, "printer-printing") |
527 |
self.icon_no_jobs = self.icon_jobs.copy () |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
528 |
self.icon_no_jobs.fill (0) |
529 |
self.icon_jobs.composite (self.icon_no_jobs, |
|
530 |
0, 0, |
|
531 |
self.icon_no_jobs.get_width(), |
|
532 |
self.icon_no_jobs.get_height(), |
|
533 |
0, 0, |
|
534 |
1.0, 1.0, |
|
535 |
gtk.gdk.INTERP_BILINEAR, |
|
536 |
127) |
|
537 |
if self.applet and not self.notify_has_persistence: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
538 |
self.statusicon = gtk.StatusIcon () |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
539 |
self.statusicon.set_from_pixbuf (self.icon_no_jobs) |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
540 |
self.statusicon.connect ('activate', self.toggle_window_display) |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
541 |
self.statusicon.connect ('popup-menu', self.on_icon_popupmenu) |
542 |
self.statusicon.set_visible (False) |
|
543 |
||
544 |
# D-Bus
|
|
545 |
if bus == None: |
|
546 |
bus = dbus.SystemBus () |
|
547 |
||
548 |
self.set_process_pending (True) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
549 |
self.host = cups.getServer () |
550 |
self.port = cups.getPort () |
|
551 |
self.encryption = cups.getEncryption () |
|
552 |
self.monitor = monitor.Monitor (bus=bus, my_jobs=my_jobs, |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
553 |
host=self.host, port=self.port, |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
554 |
encryption=self.encryption) |
555 |
self.monitor.connect ('refresh', self.on_refresh) |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
556 |
self.monitor.connect ('job-added', self.job_added) |
557 |
self.monitor.connect ('job-event', self.job_event) |
|
558 |
self.monitor.connect ('job-removed', self.job_removed) |
|
559 |
self.monitor.connect ('state-reason-added', self.state_reason_added) |
|
560 |
self.monitor.connect ('state-reason-removed', self.state_reason_removed) |
|
561 |
self.monitor.connect ('still-connecting', self.still_connecting) |
|
562 |
self.monitor.connect ('now-connected', self.now_connected) |
|
563 |
self.monitor.connect ('printer-added', self.printer_added) |
|
564 |
self.monitor.connect ('printer-event', self.printer_event) |
|
565 |
self.monitor.connect ('printer-removed', self.printer_removed) |
|
566 |
self.monitor.refresh () |
|
567 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
568 |
if not self.applet: |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
569 |
self.JobsWindow.show () |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
570 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
571 |
self.JobsAttributesWindow = gtk.Window() |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
572 |
self.JobsAttributesWindow.set_title (_("Job attributes")) |
573 |
self.JobsAttributesWindow.set_position(gtk.WIN_POS_MOUSE) |
|
574 |
self.JobsAttributesWindow.set_default_size(600, 600) |
|
575 |
self.JobsAttributesWindow.set_transient_for (self.JobsWindow) |
|
576 |
self.JobsAttributesWindow.connect("delete_event", |
|
577 |
self.job_attributes_on_delete_event) |
|
578 |
self.JobsAttributesWindow.add_accel_group (self.job_ui_manager.get_accel_group ()) |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
579 |
attrs_action_group = gtk.ActionGroup ("AttrsActionGroup") |
580 |
attrs_action_group.add_actions ([ |
|
581 |
("close", gtk.STOCK_CLOSE, None, "<ctrl>w", |
|
582 |
_("Close this window"), self.job_attributes_on_delete_event) |
|
583 |
])
|
|
584 |
self.attrs_ui_manager = gtk.UIManager () |
|
585 |
self.attrs_ui_manager.insert_action_group (attrs_action_group, -1) |
|
586 |
self.attrs_ui_manager.add_ui_from_string ( |
|
587 |
"""
|
|
588 |
<ui>
|
|
589 |
<accelerator action="close"/>
|
|
590 |
</ui>
|
|
591 |
"""
|
|
592 |
)
|
|
593 |
self.attrs_ui_manager.ensure_update () |
|
594 |
self.JobsAttributesWindow.add_accel_group (self.attrs_ui_manager.get_accel_group ()) |
|
595 |
vbox = gtk.VBox () |
|
596 |
self.JobsAttributesWindow.add (vbox) |
|
597 |
toolbar = gtk.Toolbar () |
|
598 |
action = self.attrs_ui_manager.get_action ("/close") |
|
599 |
item = action.create_tool_item () |
|
600 |
item.set_is_important (True) |
|
601 |
toolbar.insert (item, 0) |
|
602 |
vbox.pack_start (toolbar, False, False, 0) |
|
603 |
self.notebook = gtk.Notebook() |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
604 |
vbox.pack_start (self.notebook) |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
605 |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
606 |
def cleanup (self): |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
607 |
self.monitor.cleanup () |
608 |
||
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
609 |
self.JobsWindow.hide () |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
610 |
|
611 |
# Close any open notifications.
|
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
612 |
for l in [self.new_printer_notifications.values (), |
613 |
self.state_reason_notifications.values ()]: |
|
614 |
for notification in l: |
|
615 |
if notification.get_data ('closed') != True: |
|
616 |
try: |
|
1.1.52
by Till Kamppeter
Import upstream version 1.2.0+20100408 |
617 |
notification.close () |
618 |
except glib.GError: |
|
619 |
# Can fail if the notification wasn't even shown
|
|
620 |
# yet (as in bug #571603).
|
|
621 |
pass
|
|
622 |
notification.set_data ('closed', True) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
623 |
|
624 |
if self.job_creation_times_timer != None: |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
625 |
gobject.source_remove (self.job_creation_times_timer) |
626 |
self.job_creation_times_timer = None |
|
627 |
||
628 |
for op in self.ops: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
629 |
op.destroy () |
630 |
||
631 |
if self.applet and not self.notify_has_persistence: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
632 |
self.statusicon.set_visible (False) |
633 |
||
634 |
self.emit ('finished') |
|
635 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
636 |
def set_process_pending (self, whether): |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
637 |
self.process_pending_events = whether |
638 |
||
639 |
def on_delete_event(self, *args): |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
640 |
if self.applet or not self.loop: |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
641 |
self.JobsWindow.hide () |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
642 |
self.JobsWindow.set_data ('visible', False) |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
643 |
if not self.applet: |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
644 |
# Being run from main app, not applet
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
645 |
self.cleanup () |
646 |
else: |
|
647 |
self.loop.quit () |
|
648 |
return True |
|
649 |
||
650 |
def job_attributes_on_delete_event(self, widget, event=None): |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
651 |
for page in range(self.notebook.get_n_pages()): |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
652 |
self.notebook.remove_page(-1) |
653 |
self.jobs_attrs = {} |
|
654 |
self.JobsAttributesWindow.hide_all() |
|
655 |
return True |
|
656 |
||
657 |
def show_IPP_Error(self, exception, message): |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
658 |
return errordialogs.show_IPP_Error (exception, message, self.JobsWindow) |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
659 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
660 |
def toggle_window_display(self, icon, force_show=False): |
661 |
visible = self.JobsWindow.get_data('visible') |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
662 |
if force_show: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
663 |
visible = False |
664 |
||
665 |
if self.notify_has_persistence: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
666 |
if visible: |
667 |
self.JobsWindow.hide () |
|
668 |
else: |
|
669 |
self.JobsWindow.show () |
|
670 |
else: |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
671 |
if visible: |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
672 |
w = self.JobsWindow.window |
673 |
aw = self.JobsAttributesWindow.window |
|
674 |
(s, area, o) = self.statusicon.get_geometry () |
|
675 |
w.set_skip_taskbar_hint (True) |
|
676 |
if aw != None: |
|
677 |
aw.set_skip_taskbar_hint (True) |
|
678 |
||
679 |
w.property_change ("_NET_WM_ICON_GEOMETRY", |
|
680 |
"CARDINAL", 32, |
|
681 |
gtk.gdk.PROP_MODE_REPLACE, |
|
682 |
list (area)) |
|
683 |
self.JobsWindow.iconify () |
|
684 |
else: |
|
685 |
self.JobsWindow.present () |
|
686 |
self.JobsWindow.window.set_skip_taskbar_hint (False) |
|
687 |
aw = self.JobsAttributesWindow.window |
|
688 |
if aw != None: |
|
689 |
aw.set_skip_taskbar_hint (False) |
|
690 |
||
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
691 |
self.JobsWindow.set_data ('visible', not visible) |
692 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
693 |
def on_show_completed_jobs_clicked(self, toggletoolbutton): |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
694 |
if toggletoolbutton.get_active(): |
695 |
which_jobs = "all" |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
696 |
else: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
697 |
which_jobs = "not-completed" |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
698 |
self.monitor.refresh(which_jobs=which_jobs, refresh_all=False) |
699 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
700 |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
701 |
def update_job_creation_times(self): |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
702 |
now = time.time () |
703 |
need_update = False |
|
704 |
for job, data in self.jobs.iteritems(): |
|
705 |
t = _("Unknown") |
|
706 |
if data.has_key ('time-at-creation'): |
|
707 |
created = data['time-at-creation'] |
|
708 |
ago = now - created |
|
709 |
need_update = True |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
710 |
if ago < 2 * 60: |
711 |
t = _("a minute ago") |
|
712 |
elif ago < 60 * 60: |
|
713 |
mins = int (ago / 60) |
|
714 |
t = _("%d minutes ago") % mins |
|
715 |
elif ago < 24 * 60 * 60: |
|
716 |
hours = int (ago / (60 * 60)) |
|
717 |
if hours == 1: |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
718 |
t = _("an hour ago") |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
719 |
else: |
720 |
t = _("%d hours ago") % hours |
|
721 |
elif ago < 7 * 24 * 60 * 60: |
|
722 |
days = int (ago / (24 * 60 * 60)) |
|
723 |
if days == 1: |
|
724 |
t = _("yesterday") |
|
725 |
else: |
|
726 |
t = _("%d days ago") % days |
|
727 |
elif ago < 6 * 7 * 24 * 60 * 60: |
|
728 |
weeks = int (ago / (7 * 24 * 60 * 60)) |
|
729 |
if weeks == 1: |
|
730 |
t = _("last week") |
|
731 |
else: |
|
732 |
t = _("%d weeks ago") % weeks |
|
733 |
else: |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
734 |
need_update = False |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
735 |
t = time.strftime ("%B %Y", time.localtime (created)) |
1.1.45
by Till Kamppeter
Import upstream version 1.1.10+git20090725 |
736 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
737 |
if self.jobiters.has_key (job): |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
738 |
iter = self.jobiters[job] |
739 |
self.store.set_value (iter, 1, t) |
|
740 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
741 |
if need_update and not self.job_creation_times_timer: |
742 |
def update_times_with_locking (): |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
743 |
gtk.gdk.threads_enter () |
744 |
ret = self.update_job_creation_times () |
|
745 |
gtk.gdk.threads_leave () |
|
746 |
return ret |
|
747 |
||
748 |
t = gobject.timeout_add_seconds (60, update_times_with_locking) |
|
749 |
self.job_creation_times_timer = t |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
750 |
|
751 |
if not need_update: |
|
752 |
if self.job_creation_times_timer: |
|
753 |
gobject.source_remove (self.job_creation_times_timer) |
|
754 |
self.job_creation_times_timer = None |
|
755 |
||
756 |
# Return code controls whether the timeout will recur.
|
|
757 |
return need_update |
|
758 |
||
759 |
def print_error_dialog_response(self, dialog, response, jobid): |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
760 |
dialog.hide () |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
761 |
dialog.destroy () |
762 |
self.stopped_job_prompts.remove (jobid) |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
763 |
if response == gtk.RESPONSE_NO: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
764 |
# Diagnose
|
765 |
if not self.__dict__.has_key ('troubleshooter'): |
|
766 |
import troubleshoot |
|
767 |
troubleshooter = troubleshoot.run (self.on_troubleshoot_quit) |
|
768 |
self.troubleshooter = troubleshooter |
|
769 |
||
770 |
def on_troubleshoot_quit(self, troubleshooter): |
|
771 |
del self.troubleshooter |
|
772 |
||
773 |
def add_job (self, job, data, connection=None): |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
774 |
self.update_job (job, data, connection=connection) |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
775 |
|
776 |
store = self.store |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
777 |
iter = self.store.append (None) |
778 |
store.set_value (iter, 0, job) |
|
779 |
debugprint ("Job %d added" % job) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
780 |
self.jobiters[job] = iter |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
781 |
|
1.1.45
by Till Kamppeter
Import upstream version 1.1.10+git20090725 |
782 |
range = self.treeview.get_visible_range () |
783 |
if range != None: |
|
784 |
(start, end) = range |
|
785 |
if (self.store.get_sort_column_id () == (0, |
|
786 |
gtk.SORT_DESCENDING) and |
|
787 |
start == (1,)): |
|
788 |
# This job was added job above the visible range, and
|
|
789 |
# we are sorting by descending job ID. Scroll to it.
|
|
790 |
self.treeview.scroll_to_cell ((0,), None, False, 0.0, 0.0) |
|
791 |
||
792 |
if not self.job_creation_times_timer: |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
793 |
def start_updating_job_creation_times(): |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
794 |
gtk.gdk.threads_enter () |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
795 |
self.update_job_creation_times () |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
796 |
gtk.gdk.threads_leave () |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
797 |
return False |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
798 |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
799 |
gobject.timeout_add (500, start_updating_job_creation_times) |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
800 |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
801 |
def update_monitor (self): |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
802 |
self.monitor.update () |
803 |
||
804 |
def update_job (self, job, data, connection=None): |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
805 |
# Fetch required attributes for this job if they are missing.
|
806 |
r = self.required_job_attributes - set (data.keys ()) |
|
807 |
||
808 |
# If we are showing attributes of this job at this moment, update them.
|
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
809 |
if job in self.jobs_attrs: |
810 |
self.update_job_attributes_viewer(job) |
|
811 |
||
812 |
if r: |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
813 |
attrs = None |
814 |
try: |
|
815 |
if connection == None: |
|
816 |
connection = cups.Connection (host=self.host, |
|
817 |
port=self.port, |
|
818 |
encryption=self.encryption) |
|
819 |
||
820 |
debugprint ("requesting %s" % r) |
|
821 |
r = list (r) |
|
822 |
attrs = connection.getJobAttributes (job, |
|
823 |
requested_attributes=r) |
|
824 |
except RuntimeError: |
|
825 |
pass
|
|
826 |
except AttributeError: |
|
827 |
pass
|
|
828 |
except cups.IPPError: |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
829 |
# someone else may have purged the job
|
830 |
return
|
|
831 |
||
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
832 |
if attrs: |
833 |
data.update (attrs) |
|
834 |
||
835 |
self.jobs[job] = data |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
836 |
|
837 |
job_requires_auth = False |
|
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
838 |
try: |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
839 |
jstate = data.get ('job-state', cups.IPP_JOB_PROCESSING) |
840 |
s = int (jstate) |
|
841 |
||
842 |
if s in [cups.IPP_JOB_HELD, cups.IPP_JOB_STOPPED]: |
|
843 |
jattrs = ['job-state', 'job-hold-until'] |
|
844 |
pattrs = ['auth-info-required', 'device-uri'] |
|
845 |
uri = data.get ('job-printer-uri') |
|
846 |
c = authconn.Connection (self.JobsWindow, |
|
847 |
host=self.host, |
|
848 |
port=self.port, |
|
849 |
encryption=self.encryption) |
|
850 |
attrs = c.getPrinterAttributes (uri = uri, |
|
851 |
requested_attributes=pattrs) |
|
852 |
||
853 |
try: |
|
854 |
auth_info_required = attrs['auth-info-required'] |
|
855 |
except KeyError: |
|
856 |
debugprint ("No auth-info-required attribute; " |
|
857 |
"guessing instead") |
|
858 |
auth_info_required = ['username', 'password'] |
|
859 |
||
860 |
if not isinstance (auth_info_required, list): |
|
861 |
auth_info_required = [auth_info_required] |
|
862 |
attrs['auth-info-required'] = auth_info_required |
|
863 |
||
864 |
data.update (attrs) |
|
865 |
||
866 |
attrs = c.getJobAttributes (job, |
|
867 |
requested_attributes=jattrs) |
|
868 |
data.update (attrs) |
|
869 |
jstate = data.get ('job-state', cups.IPP_JOB_PROCESSING) |
|
870 |
s = int (jstate) |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
871 |
except ValueError: |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
872 |
pass
|
873 |
except RuntimeError: |
|
874 |
pass
|
|
875 |
except cups.IPPError, (e, m): |
|
876 |
pass
|
|
877 |
||
878 |
# Invalidate the cached status description and redraw the treeview.
|
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
879 |
try: |
880 |
del data['_status_text'] |
|
881 |
except KeyError: |
|
882 |
pass
|
|
883 |
self.treeview.queue_draw () |
|
884 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
885 |
# Check whether authentication is required.
|
886 |
if self.applet: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
887 |
job_requires_auth = (s == cups.IPP_JOB_HELD and |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
888 |
data.get ('job-hold-until', 'none') == |
889 |
'auth-info-required') |
|
890 |
||
891 |
if (job_requires_auth and |
|
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
892 |
not self.auth_info_dialogs.has_key (job)): |
893 |
try: |
|
894 |
cups.require ("1.9.37") |
|
895 |
except: |
|
896 |
debugprint ("Authentication required but " |
|
897 |
"authenticateJob() not available") |
|
898 |
return
|
|
899 |
||
900 |
# Find out which auth-info is required.
|
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
901 |
try_keyring = USE_KEYRING |
902 |
keyring_attrs = dict() |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
903 |
auth_info = None |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
904 |
if try_keyring and 'password' in auth_info_required: |
905 |
auth_info_required = data.get ('auth-info-required', []) |
|
906 |
device_uri = data.get ("device-uri") |
|
907 |
(scheme, rest) = urllib.splittype (device_uri) |
|
908 |
if scheme == 'smb': |
|
909 |
uri = smburi.SMBURI (uri=device_uri) |
|
910 |
(group, server, share, |
|
911 |
user, password) = uri.separate () |
|
912 |
keyring_attrs["domain"] = str (group) |
|
913 |
else: |
|
914 |
(serverport, rest) = urllib.splithost (rest) |
|
915 |
(server, port) = urllib.splitnport (serverport) |
|
1.1.45
by Till Kamppeter
Import upstream version 1.1.10+git20090725 |
916 |
keyring_attrs.update ({ "server": str (server.lower ()), |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
917 |
"protocol": str (scheme)}) |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
918 |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
919 |
if job in self.authenticated_jobs: |
920 |
# We've already tried to authenticate this job before.
|
|
921 |
try_keyring = False |
|
922 |
||
923 |
if try_keyring and 'password' in auth_info_required: |
|
924 |
type = gnomekeyring.ITEM_NETWORK_PASSWORD |
|
925 |
try: |
|
926 |
items = gnomekeyring.find_items_sync (type, |
|
927 |
keyring_attrs) |
|
928 |
auth_info = map (lambda x: '', auth_info_required) |
|
929 |
ind = auth_info_required.index ('username') |
|
930 |
auth_info[ind] = items[0].attributes.get ('user', '') |
|
931 |
ind = auth_info_required.index ('password') |
|
932 |
auth_info[ind] = items[0].secret |
|
933 |
except gnomekeyring.NoMatchError: |
|
934 |
debugprint ("gnomekeyring: no match for %s" % |
|
935 |
keyring_attrs) |
|
936 |
except gnomekeyring.DeniedError: |
|
937 |
debugprint ("gnomekeyring: denied for %s" % |
|
938 |
keyring_attrs) |
|
939 |
||
940 |
if try_keyring and c == None: |
|
941 |
try: |
|
942 |
c = authconn.Connection (self.JobsWindow, |
|
943 |
host=self.host, |
|
944 |
port=self.port, |
|
945 |
encryption=self.encryption) |
|
946 |
except RuntimeError: |
|
947 |
try_keyring = False |
|
948 |
||
949 |
if try_keyring and auth_info != None: |
|
950 |
try: |
|
951 |
c._begin_operation (_("authenticating job")) |
|
952 |
c.authenticateJob (job, auth_info) |
|
953 |
c._end_operation () |
|
954 |
self.monitor.update () |
|
955 |
debugprint ("Automatically authenticated job %d" % job) |
|
956 |
self.authenticated_jobs.add (job) |
|
957 |
return
|
|
958 |
except cups.IPPError, (e, m): |
|
959 |
c._end_operation () |
|
960 |
nonfatalException () |
|
961 |
return
|
|
962 |
except: |
|
963 |
c._end_operation () |
|
964 |
nonfatalException () |
|
965 |
||
966 |
username = pwd.getpwuid (os.getuid ())[0] |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
967 |
keyring_attrs["user"] = str (username) |
968 |
self.display_auth_info_dialog (job, keyring_attrs) |
|
969 |
self.update_sensitivity () |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
970 |
|
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
971 |
def display_auth_info_dialog (self, job, keyring_attrs=None): |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
972 |
data = self.jobs[job] |
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
973 |
auth_info_required = data['auth-info-required'] |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
974 |
dialog = authconn.AuthDialog (auth_info_required=auth_info_required, |
975 |
allow_remember=USE_KEYRING) |
|
976 |
dialog.set_data ('keyring-attrs', keyring_attrs) |
|
977 |
dialog.set_data ('auth-info-required', auth_info_required) |
|
978 |
dialog.set_position (gtk.WIN_POS_CENTER) |
|
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
979 |
|
980 |
# Pre-fill 'username' field.
|
|
981 |
auth_info = map (lambda x: '', auth_info_required) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
982 |
username = pwd.getpwuid (os.getuid ())[0] |
983 |
if 'username' in auth_info_required: |
|
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
984 |
try: |
985 |
ind = auth_info_required.index ('username') |
|
986 |
auth_info[ind] = username |
|
987 |
dialog.set_auth_info (auth_info) |
|
988 |
except: |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
989 |
nonfatalException () |
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
990 |
|
991 |
# Focus on the first empty field.
|
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
992 |
index = 0 |
993 |
for field in auth_info_required: |
|
994 |
if auth_info[index] == '': |
|
995 |
dialog.field_grab_focus (field) |
|
996 |
break
|
|
997 |
index += 1 |
|
998 |
||
999 |
dialog.set_prompt (_("Authentication required for " |
|
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
1000 |
"printing document `%s' (job %d)") % |
1001 |
(data.get('job-name', _("Unknown")), job)) |
|
1002 |
self.auth_info_dialogs[job] = dialog |
|
1003 |
dialog.connect ('response', self.auth_info_dialog_response) |
|
1004 |
dialog.connect ('delete-event', self.auth_info_dialog_delete) |
|
1005 |
dialog.set_data ('job-id', job) |
|
1006 |
dialog.show_all () |
|
1007 |
dialog.set_keep_above (True) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1008 |
dialog.show_now () |
1009 |
||
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
1010 |
def auth_info_dialog_delete (self, dialog, event): |
1011 |
self.auth_info_dialog_response (dialog, gtk.RESPONSE_CANCEL) |
|
1012 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1013 |
def auth_info_dialog_response (self, dialog, response): |
1014 |
jobid = dialog.get_data ('job-id') |
|
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
1015 |
del self.auth_info_dialogs[jobid] |
1016 |
||
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1017 |
if response != gtk.RESPONSE_OK: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1018 |
dialog.destroy () |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1019 |
return
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1020 |
|
1021 |
auth_info = dialog.get_auth_info () |
|
1022 |
try: |
|
1023 |
c = authconn.Connection (self.JobsWindow, |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1024 |
host=self.host, |
1025 |
port=self.port, |
|
1026 |
encryption=self.encryption) |
|
1027 |
except RuntimeError: |
|
1028 |
debugprint ("Error connecting to CUPS for authentication") |
|
1029 |
return
|
|
1030 |
||
1031 |
remember = False |
|
1032 |
c._begin_operation (_("authenticating job")) |
|
1033 |
try: |
|
1034 |
c.authenticateJob (jobid, auth_info) |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1035 |
remember = dialog.get_remember_password () |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1036 |
self.authenticated_jobs.add (jobid) |
1037 |
self.monitor.update () |
|
1038 |
except cups.IPPError, (e, m): |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1039 |
self.show_IPP_Error (e, m) |
1040 |
||
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1041 |
c._end_operation () |
1042 |
||
1043 |
if remember: |
|
1044 |
try: |
|
1045 |
keyring = gnomekeyring.get_default_keyring_sync () |
|
1046 |
type = gnomekeyring.ITEM_NETWORK_PASSWORD |
|
1047 |
attrs = dialog.get_data ("keyring-attrs") |
|
1048 |
auth_info_required = dialog.get_data ('auth-info-required') |
|
1049 |
if attrs != None and auth_info_required != None: |
|
1.1.45
by Till Kamppeter
Import upstream version 1.1.10+git20090725 |
1050 |
try: |
1051 |
ind = auth_info_required.index ('username') |
|
1052 |
attrs['user'] = auth_info[ind] |
|
1053 |
except IndexError: |
|
1054 |
pass
|
|
1055 |
||
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1056 |
name = "%s@%s (%s)" % (attrs.get ("user"), |
1057 |
attrs.get ("server"), |
|
1058 |
attrs.get ("protocol")) |
|
1059 |
ind = auth_info_required.index ('password') |
|
1060 |
secret = auth_info[ind] |
|
1061 |
id = gnomekeyring.item_create_sync (keyring, type, name, |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1062 |
attrs, secret, True) |
1063 |
debugprint ("keyring: created id %d for %s" % (id, name)) |
|
1064 |
except: |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1065 |
nonfatalException () |
1066 |
||
1067 |
dialog.destroy () |
|
1068 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1069 |
def set_statusicon_visibility (self): |
1070 |
if not self.applet: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1071 |
return
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1072 |
|
1073 |
if self.suppress_icon_hide: |
|
1074 |
# Avoid hiding the icon if we've been woken up to notify
|
|
1075 |
# about a new printer.
|
|
1076 |
self.suppress_icon_hide = False |
|
1077 |
return
|
|
1078 |
||
1079 |
open_notifications = len (self.new_printer_notifications.keys ()) |
|
1080 |
open_notifications += len (self.completed_job_notifications.keys ()) |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1081 |
for reason, notification in self.state_reason_notifications.iteritems(): |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1082 |
if notification.get_data ('closed') != True: |
1083 |
open_notifications += 1 |
|
1084 |
num_jobs = len (self.active_jobs) |
|
1.1.43
by Till Kamppeter
Import upstream version 1.1.3+git20090217 |
1085 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1086 |
debugprint ("open notifications: %d" % open_notifications) |
1087 |
debugprint ("num_jobs: %d" % num_jobs) |
|
1088 |
debugprint ("num_jobs_when_hidden: %d" % self.num_jobs_when_hidden) |
|
1089 |
||
1090 |
if self.notify_has_persistence: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1091 |
return
|
1092 |
||
1093 |
self.statusicon.set_visible (open_notifications > 0 or |
|
1094 |
num_jobs > self.num_jobs_when_hidden) |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1095 |
|
1096 |
# Let the icon show/hide itself before continuing.
|
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1097 |
while self.process_pending_events and gtk.events_pending (): |
1098 |
gtk.main_iteration () |
|
1099 |
||
1100 |
def on_treeview_popup_menu (self, treeview): |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
1101 |
event = gtk.gdk.Event (gtk.gdk.NOTHING) |
1102 |
self.show_treeview_popup_menu (treeview, event, 0) |
|
1103 |
||
1104 |
def on_treeview_button_release_event(self, treeview, event): |
|
1105 |
if event.button == 3: |
|
1106 |
self.show_treeview_popup_menu (treeview, event, event.button) |
|
1107 |
||
1108 |
def update_sensitivity (self, selection = None): |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
1109 |
if (selection is None): |
1110 |
selection = self.treeview.get_selection () |
|
1111 |
(model, pathlist) = selection.get_selected_rows() |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1112 |
cancel = self.job_ui_manager.get_action ("/cancel-job") |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1113 |
delete = self.job_ui_manager.get_action ("/delete-job") |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1114 |
hold = self.job_ui_manager.get_action ("/hold-job") |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1115 |
release = self.job_ui_manager.get_action ("/release-job") |
1116 |
reprint = self.job_ui_manager.get_action ("/reprint-job") |
|
1117 |
retrieve = self.job_ui_manager.get_action ("/retrieve-job") |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1118 |
authenticate = self.job_ui_manager.get_action ("/authenticate-job") |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1119 |
attributes = self.job_ui_manager.get_action ("/job-attributes") |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1120 |
move = self.job_ui_manager.get_action ("/move-job") |
1121 |
if len (pathlist) == 0: |
|
1122 |
for widget in [cancel, delete, hold, release, reprint, retrieve, |
|
1123 |
move, authenticate, attributes]: |
|
1124 |
widget.set_sensitive (False) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1125 |
return
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1126 |
|
1127 |
cancel_sensitive = True |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1128 |
hold_sensitive = True |
1129 |
release_sensitive = True |
|
1130 |
reprint_sensitive = True |
|
1131 |
authenticate_sensitive = True |
|
1132 |
move_sensitive = False |
|
1133 |
other_printers = self.printer_uri_index.all_printer_names () |
|
1134 |
job_printers = dict() |
|
1135 |
||
1136 |
self.jobids = [] |
|
1137 |
for path in pathlist: |
|
1138 |
iter = self.store.get_iter (path) |
|
1139 |
jobid = self.store.get_value (iter, 0) |
|
1140 |
self.jobids.append(jobid) |
|
1141 |
job = self.jobs[jobid] |
|
1142 |
||
1143 |
if job.has_key ('job-state'): |
|
1144 |
s = job['job-state'] |
|
1145 |
if s >= cups.IPP_JOB_CANCELED: |
|
1146 |
cancel_sensitive = False |
|
1147 |
if s != cups.IPP_JOB_PENDING: |
|
1148 |
hold_sensitive = False |
|
1149 |
if s != cups.IPP_JOB_HELD: |
|
1150 |
release_sensitive = False |
|
1151 |
if (not job.get('job-preserved', False)): |
|
1152 |
reprint_sensitive = False |
|
1153 |
||
1154 |
if (job.get ('job-state', |
|
1155 |
cups.IPP_JOB_CANCELED) != cups.IPP_JOB_HELD or |
|
1156 |
job.get ('job-hold-until', 'none') != 'auth-info-required'): |
|
1157 |
authenticate_sensitive = False |
|
1158 |
||
1159 |
uri = job.get ('job-printer-uri', None) |
|
1160 |
if uri: |
|
1161 |
try: |
|
1.1.54
by Till Kamppeter
Import upstream version 1.2.3+20100723 |
1162 |
printer = self.printer_uri_index.lookup (uri) |
1163 |
except KeyError: |
|
1164 |
printer = uri |
|
1165 |
job_printers[printer] = uri |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1166 |
|
1167 |
if len (job_printers.keys ()) == 1: |
|
1168 |
try: |
|
1169 |
other_printers.remove (job_printers.keys ()[0]) |
|
1170 |
except KeyError: |
|
1171 |
pass
|
|
1172 |
||
1173 |
if len (other_printers) > 0: |
|
1174 |
printers_menu = gtk.Menu () |
|
1175 |
other_printers = list (other_printers) |
|
1176 |
other_printers.sort () |
|
1177 |
for printer in other_printers: |
|
1178 |
try: |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
1179 |
uri = self.printer_uri_index.lookup_cached_by_name (printer) |
1180 |
except KeyError: |
|
1181 |
uri = None |
|
1182 |
menuitem = gtk.MenuItem (printer, False) |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1183 |
menuitem.set_sensitive (uri != None) |
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
1184 |
menuitem.show () |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1185 |
menuitem.connect ('activate', self.on_job_move_activate, uri) |
1186 |
printers_menu.append (menuitem) |
|
1187 |
||
1188 |
self.move_job_menuitem.set_submenu (printers_menu) |
|
1189 |
move_sensitive = True |
|
1190 |
||
1191 |
cancel.set_sensitive(cancel_sensitive) |
|
1192 |
delete.set_sensitive(not cancel_sensitive) |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
1193 |
hold.set_sensitive(hold_sensitive) |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1194 |
release.set_sensitive(release_sensitive) |
1195 |
reprint.set_sensitive(reprint_sensitive) |
|
1196 |
retrieve.set_sensitive(reprint_sensitive) |
|
1197 |
move.set_sensitive (move_sensitive) |
|
1198 |
authenticate.set_sensitive(authenticate_sensitive) |
|
1199 |
attributes.set_sensitive(True) |
|
1200 |
||
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1201 |
def on_selection_changed (self, selection): |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
1202 |
self.update_sensitivity (selection) |
1203 |
||
1204 |
def show_treeview_popup_menu (self, treeview, event, event_button): |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1205 |
# Right-clicked.
|
1206 |
self.job_context_menu.popup (None, None, None, event_button, |
|
1207 |
event.get_time ()) |
|
1208 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1209 |
def on_icon_popupmenu(self, icon, button, time): |
1210 |
self.statusicon_popupmenu.popup (None, None, None, button, time) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1211 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1212 |
def on_icon_hide_activate(self, menuitem): |
1213 |
self.num_jobs_when_hidden = len (self.jobs.keys ()) |
|
1214 |
self.set_statusicon_visibility () |
|
1215 |
||
1216 |
def on_icon_configure_printers_activate(self, menuitem): |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1217 |
if self.loop: |
1218 |
env = {} |
|
1219 |
for name, value in os.environ.iteritems (): |
|
1220 |
if name == "SYSTEM_CONFIG_PRINTER_UI": |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1221 |
continue
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1222 |
env[name] = value |
1223 |
p = subprocess.Popen ([ "system-config-printer" ], |
|
1224 |
close_fds=True, env=env) |
|
1225 |
gobject.timeout_add_seconds (10, self.poll_subprocess, p) |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1226 |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1227 |
def poll_subprocess(self, process): |
1228 |
returncode = process.poll () |
|
1229 |
return returncode == None |
|
1230 |
||
1231 |
def on_icon_quit_activate (self, menuitem): |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1232 |
self.cleanup () |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1233 |
if self.loop: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1234 |
self.loop.quit () |
1235 |
||
1236 |
def on_job_cancel_activate(self, menuitem): |
|
1237 |
self.on_job_cancel_activate2(False) |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1238 |
|
1239 |
def on_job_delete_activate(self, menuitem): |
|
1240 |
self.on_job_cancel_activate2(True) |
|
1241 |
||
1242 |
def on_job_cancel_activate2(self, purge_job): |
|
1243 |
if self.jobids: |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
1244 |
op = CancelJobsOperation (self.JobsWindow, self.host, self.port, |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1245 |
self.encryption, self.jobids, purge_job) |
1246 |
self.ops.append (op) |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
1247 |
op.connect ('finished', self.on_canceljobs_finished) |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1248 |
op.connect ('ipp-error', self.on_canceljobs_error) |
1249 |
||
1250 |
def on_canceljobs_finished (self, canceljobsoperation): |
|
1251 |
canceljobsoperation.destroy () |
|
1252 |
i = self.ops.index (canceljobsoperation) |
|
1253 |
del self.ops[i] |
|
1254 |
self.update_monitor () |
|
1255 |
||
1256 |
def on_canceljobs_error (self, canceljobsoperation, jobid, exc): |
|
1257 |
self.update_monitor () |
|
1258 |
if type (exc) == cups.IPPError: |
|
1259 |
(e, m) = exc.args |
|
1260 |
if (e != cups.IPP_NOT_POSSIBLE and |
|
1261 |
e != cups.IPP_NOT_FOUND): |
|
1262 |
self.show_IPP_Error (e, m) |
|
1263 |
||
1264 |
return
|
|
1265 |
||
1266 |
raise exc |
|
1267 |
||
1.1.39
by Till Kamppeter
Import upstream version 1.0.4+git20080730 |
1268 |
def on_job_hold_activate(self, menuitem): |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1269 |
try: |
1270 |
c = authconn.Connection (self.JobsWindow, |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1271 |
host=self.host, |
1272 |
port=self.port, |
|
1273 |
encryption=self.encryption) |
|
1274 |
except RuntimeError: |
|
1275 |
return
|
|
1276 |
||
1277 |
for jobid in self.jobids: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1278 |
c._begin_operation (_("holding job")) |
1279 |
try: |
|
1280 |
c.setJobHoldUntil (jobid, "indefinite") |
|
1281 |
except cups.IPPError, (e, m): |
|
1282 |
if (e != cups.IPP_NOT_POSSIBLE and |
|
1283 |
e != cups.IPP_NOT_FOUND): |
|
1284 |
self.show_IPP_Error (e, m) |
|
1285 |
self.monitor.update () |
|
1286 |
c._end_operation () |
|
1287 |
return
|
|
1288 |
c._end_operation () |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1289 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1290 |
del c |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1291 |
self.monitor.update () |
1292 |
||
1.1.39
by Till Kamppeter
Import upstream version 1.0.4+git20080730 |
1293 |
def on_job_release_activate(self, menuitem): |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1294 |
try: |
1295 |
c = authconn.Connection (self.JobsWindow, |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1296 |
host=self.host, |
1297 |
port=self.port, |
|
1298 |
encryption=self.encryption) |
|
1299 |
except RuntimeError: |
|
1300 |
return
|
|
1301 |
||
1302 |
for jobid in self.jobids: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1303 |
c._begin_operation (_("releasing job")) |
1304 |
try: |
|
1305 |
c.setJobHoldUntil (jobid, "no-hold") |
|
1306 |
except cups.IPPError, (e, m): |
|
1307 |
if (e != cups.IPP_NOT_POSSIBLE and |
|
1308 |
e != cups.IPP_NOT_FOUND): |
|
1309 |
self.show_IPP_Error (e, m) |
|
1310 |
self.monitor.update () |
|
1311 |
c._end_operation () |
|
1312 |
return
|
|
1313 |
c._end_operation () |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1314 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1315 |
del c |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1316 |
self.monitor.update () |
1317 |
||
1.1.39
by Till Kamppeter
Import upstream version 1.0.4+git20080730 |
1318 |
def on_job_reprint_activate(self, menuitem): |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1319 |
try: |
1320 |
c = authconn.Connection (self.JobsWindow, |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1321 |
host=self.host, |
1322 |
port=self.port, |
|
1323 |
encryption=self.encryption) |
|
1324 |
for jobid in self.jobids: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1325 |
c.restartJob (jobid) |
1326 |
del c |
|
1327 |
except cups.IPPError, (e, m): |
|
1328 |
self.show_IPP_Error (e, m) |
|
1329 |
self.monitor.update () |
|
1330 |
return
|
|
1331 |
except RuntimeError: |
|
1332 |
return
|
|
1333 |
||
1334 |
self.monitor.update () |
|
1335 |
||
1336 |
def on_job_retrieve_activate(self, menuitem): |
|
1337 |
try: |
|
1338 |
c = authconn.Connection (self.JobsWindow, |
|
1339 |
host=self.host, |
|
1340 |
port=self.port, |
|
1341 |
encryption=self.encryption) |
|
1342 |
except RuntimeError: |
|
1343 |
return
|
|
1344 |
||
1345 |
for jobid in self.jobids: |
|
1346 |
try: |
|
1347 |
attrs=c.getJobAttributes(jobid) |
|
1348 |
printer_uri=attrs['job-printer-uri'] |
|
1349 |
document_count=attrs['document-count'] |
|
1350 |
for document_number in range(1, document_count+1): |
|
1351 |
document=c.getDocument(printer_uri, jobid, document_number) |
|
1352 |
tempfile = document.get('file') |
|
1353 |
name = document.get('document-name') |
|
1354 |
format = document.get('document-format', '') |
|
1355 |
||
1356 |
# if there's no document-name retrieved
|
|
1357 |
if name == None: |
|
1358 |
# give the default filename some meaningful name
|
|
1359 |
name = _("retrieved")+str(document_number) |
|
1360 |
# add extension according to format
|
|
1361 |
if format == 'application/postscript': |
|
1362 |
name = name + ".ps" |
|
1363 |
elif format.find('application/vnd.') != -1: |
|
1364 |
name = name + format.replace('application/vnd', '') |
|
1365 |
elif format.find('application/') != -1: |
|
1366 |
name = name + format.replace('application/', '.') |
|
1367 |
||
1368 |
if tempfile != None: |
|
1369 |
dialog = gtk.FileChooserDialog (_("Save File"), |
|
1370 |
self.JobsWindow, |
|
1371 |
gtk.FILE_CHOOSER_ACTION_SAVE, |
|
1372 |
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, |
|
1373 |
gtk.STOCK_SAVE, gtk.RESPONSE_OK)) |
|
1374 |
dialog.set_current_name(name) |
|
1375 |
dialog.set_do_overwrite_confirmation(True) |
|
1376 |
||
1377 |
response = dialog.run() |
|
1378 |
if response == gtk.RESPONSE_OK: |
|
1379 |
file_to_save = dialog.get_filename() |
|
1380 |
try: |
|
1381 |
shutil.copyfile(tempfile, file_to_save) |
|
1382 |
except (IOError, shutil.Error): |
|
1383 |
debugprint("Unable to save file "+file_to_save) |
|
1384 |
elif response == gtk.RESPONSE_CANCEL: |
|
1385 |
pass
|
|
1386 |
dialog.destroy() |
|
1387 |
os.unlink(tempfile) |
|
1388 |
else: |
|
1389 |
debugprint("Unable to retrieve file from job file") |
|
1390 |
return
|
|
1391 |
||
1392 |
except cups.IPPError, (e, m): |
|
1393 |
self.show_IPP_Error (e, m) |
|
1394 |
self.monitor.update () |
|
1395 |
return
|
|
1396 |
||
1397 |
del c |
|
1398 |
self.monitor.update () |
|
1399 |
||
1400 |
def on_job_move_activate(self, menuitem, job_printer_uri): |
|
1401 |
try: |
|
1402 |
c = authconn.Connection (self.JobsWindow, |
|
1403 |
host=self.host, |
|
1404 |
port=self.port, |
|
1405 |
encryption=self.encryption) |
|
1406 |
for jobid in self.jobids: |
|
1407 |
c.moveJob (job_id=jobid, job_printer_uri=job_printer_uri) |
|
1408 |
del c |
|
1409 |
except cups.IPPError, (e, m): |
|
1410 |
self.show_IPP_Error (e, m) |
|
1411 |
self.monitor.update () |
|
1412 |
return
|
|
1413 |
except RuntimeError: |
|
1414 |
return
|
|
1415 |
except AttributeError: |
|
1416 |
# Requires pycups >= 1.9.47
|
|
1417 |
debugprint ("Move requires pycups >= 1.9.47") |
|
1418 |
return
|
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1419 |
|
1420 |
self.monitor.update () |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1421 |
|
1422 |
def on_job_authenticate_activate(self, menuitem): |
|
1423 |
for jobid in self.jobids: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1424 |
self.display_auth_info_dialog (jobid) |
1425 |
||
1.1.39
by Till Kamppeter
Import upstream version 1.0.4+git20080730 |
1426 |
def on_refresh_clicked(self, toolbutton): |
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
1427 |
self.monitor.refresh () |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1428 |
self.update_job_creation_times () |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1429 |
|
1430 |
def on_job_attributes_activate(self, menuitem): |
|
1431 |
""" For every selected job create notebook page with attributes. """
|
|
1432 |
try: |
|
1433 |
c = cups.Connection (host=self.host, |
|
1434 |
port=self.port, |
|
1435 |
encryption=self.encryption) |
|
1436 |
except RuntimeError: |
|
1437 |
return False |
|
1438 |
||
1439 |
for jobid in self.jobids: |
|
1440 |
if jobid not in self.jobs_attrs: |
|
1441 |
# add new notebook page with scrollable treeview
|
|
1442 |
scrolledwindow = gtk.ScrolledWindow() |
|
1443 |
label = gtk.Label(jobid) # notebook page has label with jobid |
|
1444 |
page_index = self.notebook.append_page(scrolledwindow, label) |
|
1445 |
attr_treeview = gtk.TreeView() |
|
1446 |
scrolledwindow.add(attr_treeview) |
|
1447 |
cell = gtk.CellRendererText () |
|
1448 |
attr_treeview.insert_column_with_attributes(0, _("Name"), |
|
1449 |
cell, text=0) |
|
1450 |
cell = gtk.CellRendererText () |
|
1451 |
attr_treeview.insert_column_with_attributes(1, _("Value"), |
|
1452 |
cell, text=1) |
|
1453 |
attr_store = gtk.ListStore(gobject.TYPE_STRING, |
|
1454 |
gobject.TYPE_STRING) |
|
1455 |
attr_treeview.set_model(attr_store) |
|
1456 |
attr_treeview.get_selection().set_mode(gtk.SELECTION_NONE) |
|
1457 |
attr_store.set_sort_column_id (0, gtk.SORT_ASCENDING) |
|
1458 |
self.jobs_attrs[jobid] = (attr_store, page_index) |
|
1459 |
self.update_job_attributes_viewer (jobid, conn=c) |
|
1460 |
||
1461 |
self.JobsAttributesWindow.show_all () |
|
1462 |
||
1463 |
def update_job_attributes_viewer(self, jobid, conn=None): |
|
1464 |
""" Update attributes store with new values. """
|
|
1465 |
if conn != None: |
|
1466 |
c = conn |
|
1467 |
else: |
|
1468 |
try: |
|
1469 |
c = cups.Connection (host=self.host, |
|
1470 |
port=self.port, |
|
1471 |
encryption=self.encryption) |
|
1472 |
except RuntimeError: |
|
1473 |
return False |
|
1474 |
||
1475 |
if jobid in self.jobs_attrs: |
|
1476 |
(attr_store, page) = self.jobs_attrs[jobid] |
|
1477 |
try: |
|
1478 |
attrs = c.getJobAttributes(jobid) # new attributes |
|
1479 |
except AttributeError: |
|
1480 |
return
|
|
1481 |
except cups.IPPError: |
|
1482 |
# someone else may have purged the job,
|
|
1483 |
# remove jobs notebook page
|
|
1484 |
self.notebook.remove_page(page) |
|
1485 |
del self.jobs_attrs[jobid] |
|
1486 |
return
|
|
1487 |
||
1488 |
attr_store.clear() # remove old attributes |
|
1489 |
for name, value in attrs.iteritems(): |
|
1490 |
if name in ['job-id', 'job-printer-up-time']: |
|
1491 |
continue
|
|
1492 |
attr_store.append([name, value]) |
|
1493 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1494 |
def job_is_active (self, jobdata): |
1495 |
state = jobdata.get ('job-state', cups.IPP_JOB_CANCELED) |
|
1496 |
if state >= cups.IPP_JOB_CANCELED: |
|
1497 |
return False |
|
1498 |
||
1499 |
return True |
|
1500 |
||
1501 |
## Icon manipulation
|
|
1502 |
def add_state_reason_emblem (self, pixbuf, printer=None): |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
1503 |
worst_reason = None |
1504 |
if printer == None and self.worst_reason != None: |
|
1505 |
# Check that it's valid.
|
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1506 |
printer = self.worst_reason.get_printer () |
1507 |
found = False |
|
1508 |
for reason in self.printer_state_reasons.get (printer, []): |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
1509 |
if reason == self.worst_reason: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1510 |
worst_reason = self.worst_reason |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
1511 |
break
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1512 |
if worst_reason == None: |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
1513 |
self.worst_reason = None |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1514 |
|
1515 |
if printer != None: |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
1516 |
for reason in self.printer_state_reasons.get (printer, []): |
1517 |
if worst_reason == None: |
|
1518 |
worst_reason = reason |
|
1519 |
elif reason > worst_reason: |
|
1520 |
worst_reason = reason |
|
1521 |
||
1522 |
if worst_reason != None: |
|
1523 |
level = worst_reason.get_level () |
|
1524 |
if level > StateReason.REPORT: |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1525 |
# Add an emblem to the icon.
|
1526 |
icon = StateReason.LEVEL_ICON[level] |
|
1527 |
pixbuf = pixbuf.copy () |
|
1528 |
try: |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1529 |
theme = gtk.icon_theme_get_default () |
1530 |
emblem = theme.load_icon (icon, 22, 0) |
|
1531 |
emblem.composite (pixbuf, |
|
1532 |
pixbuf.get_width () / 2, |
|
1533 |
pixbuf.get_height () / 2, |
|
1534 |
emblem.get_width () / 2, |
|
1535 |
emblem.get_height () / 2, |
|
1536 |
pixbuf.get_width () / 2, |
|
1537 |
pixbuf.get_height () / 2, |
|
1538 |
0.5, 0.5, |
|
1539 |
gtk.gdk.INTERP_BILINEAR, 255) |
|
1540 |
except gobject.GError: |
|
1541 |
debugprint ("No %s icon available" % icon) |
|
1542 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1543 |
return pixbuf |
1544 |
||
1545 |
def get_icon_pixbuf (self, have_jobs=None): |
|
1546 |
if not self.applet: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1547 |
return
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1548 |
|
1549 |
if have_jobs == None: |
|
1550 |
have_jobs = len (self.jobs.keys ()) > 0 |
|
1551 |
||
1552 |
if have_jobs: |
|
1553 |
pixbuf = self.icon_jobs |
|
1554 |
for jobid, jobdata in self.jobs.iteritems (): |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1555 |
jstate = jobdata.get ('job-state', cups.IPP_JOB_PENDING) |
1556 |
if jstate == cups.IPP_JOB_PROCESSING: |
|
1557 |
pixbuf = self.icon_jobs_processing |
|
1558 |
break
|
|
1559 |
else: |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1560 |
pixbuf = self.icon_no_jobs |
1561 |
||
1562 |
try: |
|
1563 |
pixbuf = self.add_state_reason_emblem (pixbuf) |
|
1564 |
except: |
|
1565 |
nonfatalException () |
|
1566 |
||
1567 |
return pixbuf |
|
1568 |
||
1569 |
def set_statusicon_tooltip (self, tooltip=None): |
|
1570 |
if not self.applet: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1571 |
return
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1572 |
|
1573 |
if tooltip == None: |
|
1574 |
num_jobs = len (self.jobs) |
|
1575 |
if num_jobs == 0: |
|
1576 |
tooltip = _("No documents queued") |
|
1577 |
elif num_jobs == 1: |
|
1578 |
tooltip = _("1 document queued") |
|
1579 |
else: |
|
1580 |
tooltip = _("%d documents queued") % num_jobs |
|
1581 |
||
1582 |
self.statusicon.set_tooltip (tooltip) |
|
1583 |
||
1584 |
def update_status (self, have_jobs=None): |
|
1585 |
# Found out which printer state reasons apply to our active jobs.
|
|
1586 |
upset_printers = set() |
|
1587 |
for printer, reasons in self.printer_state_reasons.iteritems (): |
|
1588 |
if len (reasons) > 0: |
|
1589 |
upset_printers.add (printer) |
|
1590 |
debugprint ("Upset printers: %s" % upset_printers) |
|
1591 |
||
1592 |
my_upset_printers = set() |
|
1593 |
if len (upset_printers): |
|
1594 |
my_upset_printers = set() |
|
1595 |
for jobid in self.active_jobs: |
|
1596 |
# 'job-printer-name' is set by job_added/job_event
|
|
1597 |
printer = self.jobs[jobid]['job-printer-name'] |
|
1598 |
if printer in upset_printers: |
|
1599 |
my_upset_printers.add (printer) |
|
1600 |
debugprint ("My upset printers: %s" % my_upset_printers) |
|
1601 |
||
1602 |
my_reasons = [] |
|
1603 |
for printer in my_upset_printers: |
|
1604 |
my_reasons.extend (self.printer_state_reasons[printer]) |
|
1605 |
||
1606 |
# Find out which is the most problematic.
|
|
1607 |
self.worst_reason = None |
|
1608 |
if len (my_reasons) > 0: |
|
1609 |
worst_reason = my_reasons[0] |
|
1610 |
for reason in my_reasons: |
|
1611 |
if reason > worst_reason: |
|
1612 |
worst_reason = reason |
|
1613 |
self.worst_reason = worst_reason |
|
1614 |
debugprint ("Worst reason: %s" % worst_reason) |
|
1615 |
||
1616 |
self.statusbar.pop (0) |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1617 |
if self.worst_reason != None: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1618 |
(title, tooltip) = self.worst_reason.get_description () |
1619 |
self.statusbar.push (0, tooltip) |
|
1620 |
else: |
|
1621 |
tooltip = None |
|
1622 |
status_message = "" |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1623 |
processing = 0 |
1624 |
pending = 0 |
|
1625 |
for jobid in self.active_jobs: |
|
1626 |
try: |
|
1627 |
job_state = self.jobs[jobid]['job-state'] |
|
1628 |
except KeyError: |
|
1629 |
continue
|
|
1630 |
if job_state == cups.IPP_JOB_PROCESSING: |
|
1631 |
processing = processing + 1 |
|
1632 |
elif job_state == cups.IPP_JOB_PENDING: |
|
1633 |
pending = pending + 1 |
|
1634 |
if ((processing > 0) or (pending > 0)): |
|
1635 |
status_message = _("processing / pending: %d / %d") % (processing, pending) |
|
1636 |
self.statusbar.push(0, status_message) |
|
1637 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1638 |
if self.applet and not self.notify_has_persistence: |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1639 |
pixbuf = self.get_icon_pixbuf (have_jobs=have_jobs) |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1640 |
self.statusicon.set_from_pixbuf (pixbuf) |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1641 |
self.set_statusicon_visibility () |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1642 |
self.set_statusicon_tooltip (tooltip=tooltip) |
1643 |
||
1644 |
## Notifications
|
|
1645 |
def notify_printer_state_reason_if_important (self, reason): |
|
1646 |
level = reason.get_level () |
|
1647 |
if level < StateReason.WARNING: |
|
1648 |
# Not important enough to justify a notification.
|
|
1649 |
return
|
|
1650 |
||
1651 |
blacklist = [ |
|
1.1.54
by Till Kamppeter
Import upstream version 1.2.3+20100723 |
1652 |
# Some printers report 'other-warning' for no apparent
|
1653 |
# reason, e.g. Canon iR 3170C, Epson AL-CX11NF.
|
|
1654 |
# See bug #520815.
|
|
1655 |
"other", |
|
1656 |
||
1657 |
# This seems to be some sort of 'magic' state reason that
|
|
1658 |
# is for internal use only.
|
|
1659 |
"com.apple.print.recoverable", |
|
1660 |
]
|
|
1661 |
||
1662 |
if reason.get_reason () in blacklist: |
|
1663 |
return
|
|
1664 |
||
1665 |
self.notify_printer_state_reason (reason) |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1666 |
|
1667 |
def notify_printer_state_reason (self, reason): |
|
1668 |
tuple = reason.get_tuple () |
|
1669 |
if self.state_reason_notifications.has_key (tuple): |
|
1670 |
debugprint ("Already sent notification for %s" % repr (reason)) |
|
1671 |
return
|
|
1672 |
||
1673 |
level = reason.get_level () |
|
1674 |
if (level == StateReason.ERROR or |
|
1675 |
reason.get_reason () == "connecting-to-device"): |
|
1676 |
urgency = pynotify.URGENCY_NORMAL |
|
1677 |
else: |
|
1678 |
urgency = pynotify.URGENCY_LOW |
|
1679 |
||
1680 |
(title, text) = reason.get_description () |
|
1681 |
notification = pynotify.Notification (title, text, 'printer') |
|
1682 |
reason.user_notified = True |
|
1683 |
notification.set_urgency (urgency) |
|
1684 |
if self.notify_has_actions: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1685 |
notification.set_timeout (pynotify.EXPIRES_NEVER) |
1.1.45
by Till Kamppeter
Import upstream version 1.1.10+git20090725 |
1686 |
notification.connect ('closed', |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1687 |
self.on_state_reason_notification_closed) |
1688 |
self.state_reason_notifications[reason.get_tuple ()] = notification |
|
1689 |
self.set_statusicon_visibility () |
|
1690 |
try: |
|
1.1.45
by Till Kamppeter
Import upstream version 1.1.10+git20090725 |
1691 |
notification.show () |
1692 |
except gobject.GError: |
|
1693 |
nonfatalException () |
|
1694 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1695 |
def on_state_reason_notification_closed (self, notification, reason=None): |
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
1696 |
debugprint ("Notification %s closed" % repr (notification)) |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1697 |
notification.set_data ('closed', True) |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1698 |
self.set_statusicon_visibility () |
1699 |
return
|
|
1700 |
||
1701 |
def notify_completed_job (self, jobid): |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1702 |
job = self.jobs.get (jobid, {}) |
1703 |
document = job.get ('job-name', _("Unknown")) |
|
1704 |
printer_uri = job.get ('job-printer-uri') |
|
1705 |
if printer_uri != None: |
|
1706 |
# Determine if this printer is remote. There's no need to
|
|
1707 |
# show a notification if the printer is connected to this
|
|
1708 |
# machine.
|
|
1709 |
||
1710 |
# Find out the device URI. We might already have
|
|
1711 |
# determined this if authentication was required.
|
|
1712 |
device_uri = job.get ('device-uri') |
|
1713 |
||
1714 |
if device_uri == None: |
|
1715 |
pattrs = ['device-uri'] |
|
1716 |
c = authconn.Connection (self.JobsWindow, |
|
1717 |
host=self.host, |
|
1718 |
port=self.port, |
|
1719 |
encryption=self.encryption) |
|
1720 |
try: |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
1721 |
attrs = c.getPrinterAttributes (uri=printer_uri, |
1722 |
requested_attributes=pattrs) |
|
1723 |
except cups.IPPError: |
|
1724 |
return
|
|
1725 |
||
1726 |
device_uri = attrs.get ('device-uri') |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1727 |
|
1728 |
if device_uri != None: |
|
1729 |
(scheme, rest) = urllib.splittype (device_uri) |
|
1730 |
if scheme not in ['socket', 'ipp', 'http', 'smb']: |
|
1731 |
return
|
|
1732 |
||
1733 |
printer = job.get ('job-printer-name', _("Unknown")) |
|
1734 |
notification = pynotify.Notification (_("Document printed"), |
|
1735 |
_("Document `%s' has been sent " |
|
1736 |
"to `%s' for printing.") % |
|
1737 |
(document, printer), |
|
1738 |
'printer') |
|
1739 |
notification.set_urgency (pynotify.URGENCY_LOW) |
|
1740 |
notification.connect ('closed', |
|
1741 |
self.on_completed_job_notification_closed) |
|
1742 |
notification.set_data ('jobid', jobid) |
|
1743 |
self.completed_job_notifications[jobid] = notification |
|
1744 |
self.set_statusicon_visibility () |
|
1745 |
try: |
|
1746 |
notification.show () |
|
1747 |
except gobject.GError: |
|
1748 |
nonfatalException () |
|
1749 |
||
1750 |
def on_completed_job_notification_closed (self, notification, reason=None): |
|
1751 |
jobid = notification.get_data ('jobid') |
|
1752 |
del self.completed_job_notifications[jobid] |
|
1753 |
self.set_statusicon_visibility () |
|
1754 |
||
1755 |
## Monitor signal handlers
|
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1756 |
def on_refresh (self, mon): |
1757 |
self.store.clear () |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1758 |
self.jobs = {} |
1.1.41
by Till Kamppeter
Import upstream version 1.0.5+git20080819 |
1759 |
self.active_jobs = set() |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1760 |
self.jobiters = {} |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1761 |
self.printer_uri_index = PrinterURIIndex () |
1762 |
||
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1763 |
def job_added (self, mon, jobid, eventname, event, jobdata): |
1764 |
uri = jobdata.get ('job-printer-uri', '') |
|
1765 |
try: |
|
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
1766 |
printer = self.printer_uri_index.lookup (uri) |
1767 |
except KeyError: |
|
1768 |
printer = uri |
|
1769 |
||
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1770 |
if self.specific_dests and printer not in self.specific_dests: |
1771 |
return
|
|
1772 |
||
1773 |
jobdata['job-printer-name'] = printer |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1774 |
|
1775 |
# We may be showing this job already, perhaps because we are showing
|
|
1776 |
# completed jobs and one was reprinted.
|
|
1777 |
if not self.jobiters.has_key (jobid): |
|
1778 |
self.add_job (jobid, jobdata) |
|
1779 |
||
1780 |
if self.job_is_active (jobdata): |
|
1.1.43
by Till Kamppeter
Import upstream version 1.1.3+git20090217 |
1781 |
self.active_jobs.add (jobid) |
1782 |
elif jobid in self.active_jobs: |
|
1783 |
self.active_jobs.remove (jobid) |
|
1784 |
||
1785 |
self.update_status (have_jobs=True) |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1786 |
if self.applet: |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1787 |
if not self.job_is_active (jobdata): |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1788 |
return
|
1789 |
||
1790 |
for reason in self.printer_state_reasons.get (printer, []): |
|
1791 |
if not reason.user_notified: |
|
1792 |
self.notify_printer_state_reason_if_important (reason) |
|
1793 |
||
1794 |
def job_event (self, mon, jobid, eventname, event, jobdata): |
|
1795 |
uri = jobdata.get ('job-printer-uri', '') |
|
1796 |
try: |
|
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
1797 |
printer = self.printer_uri_index.lookup (uri) |
1798 |
except KeyError: |
|
1799 |
printer = uri |
|
1800 |
||
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1801 |
if self.specific_dests and printer not in self.specific_dests: |
1802 |
return
|
|
1803 |
||
1804 |
jobdata['job-printer-name'] = printer |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1805 |
|
1806 |
if self.job_is_active (jobdata): |
|
1807 |
self.active_jobs.add (jobid) |
|
1808 |
elif jobid in self.active_jobs: |
|
1809 |
self.active_jobs.remove (jobid) |
|
1810 |
||
1811 |
self.update_job (jobid, jobdata) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1812 |
self.update_status () |
1.1.46
by Till Kamppeter
Import upstream version 1.1.10+git20090731 |
1813 |
|
1.1.55
by Till Kamppeter
Import upstream version 1.2.6+20110127 |
1814 |
# Check that the job still exists, as update_status re-enters
|
1815 |
# the main loop in order to paint/hide the tray icon. Really
|
|
1816 |
# that should probably be deferred to the idle handler, but
|
|
1817 |
# for the moment just deal with the fact that the job might
|
|
1818 |
# have gone (bug #640904).
|
|
1819 |
if not self.jobs.has_key (jobid): |
|
1820 |
return
|
|
1821 |
||
1822 |
jobdata = self.jobs[jobid] |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1823 |
|
1824 |
# If the job has finished, let the user know.
|
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1825 |
if self.applet and (eventname == 'job-completed' or |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1826 |
(eventname == 'job-state-changed' and |
1827 |
event['job-state'] == cups.IPP_JOB_COMPLETED)): |
|
1828 |
reasons = event['job-state-reasons'] |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1829 |
if type (reasons) != list: |
1830 |
reasons = [reasons] |
|
1831 |
||
1832 |
canceled = False |
|
1833 |
for reason in reasons: |
|
1834 |
if reason.startswith ("job-canceled"): |
|
1835 |
canceled = True |
|
1836 |
break
|
|
1837 |
||
1838 |
if not canceled: |
|
1839 |
self.notify_completed_job (jobid) |
|
1840 |
||
1841 |
# Look out for stopped jobs.
|
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1842 |
if (self.applet and |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1843 |
(eventname == 'job-stopped' or |
1.1.45
by Till Kamppeter
Import upstream version 1.1.10+git20090725 |
1844 |
(eventname == 'job-state-changed' and |
1845 |
event['job-state'] in [cups.IPP_JOB_STOPPED, |
|
1.1.47
by Till Kamppeter
Import upstream version 1.1.11+git20090820 |
1846 |
cups.IPP_JOB_PENDING])) and |
1847 |
not jobid in self.stopped_job_prompts): |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
1848 |
# Why has the job stopped? It might be due to a job error
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1849 |
# of some sort, or it might be that the backend requires
|
1850 |
# authentication. If the latter, the job will be held not
|
|
1851 |
# stopped, and the job-hold-until attribute will be
|
|
1852 |
# 'auth-info-required'. This was already checked for in
|
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1853 |
# update_job.
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1854 |
may_be_problem = True |
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
1855 |
jstate = jobdata['job-state'] |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1856 |
if (jstate == cups.IPP_JOB_PROCESSING or |
1.1.47
by Till Kamppeter
Import upstream version 1.1.11+git20090820 |
1857 |
(jstate == cups.IPP_JOB_HELD and |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1858 |
jobdata['job-hold-until'] == 'auth-info-required')): |
1859 |
# update_job already dealt with this.
|
|
1860 |
may_be_problem = False |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
1861 |
else: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1862 |
# Other than that, unfortunately the only
|
1863 |
# clue we get is the notify-text, which is not
|
|
1864 |
# translated into our native language. We'd better
|
|
1865 |
# try parsing it. In CUPS-1.3.6 the possible strings
|
|
1866 |
# are:
|
|
1867 |
#
|
|
1868 |
# "Job stopped due to filter errors; please consult
|
|
1869 |
# the error_log file for details."
|
|
1870 |
#
|
|
1871 |
# "Job stopped due to backend errors; please consult
|
|
1872 |
# the error_log file for details."
|
|
1873 |
#
|
|
1874 |
# "Job held due to backend errors; please consult the
|
|
1875 |
# error_log file for details."
|
|
1876 |
#
|
|
1877 |
# "Authentication is required for job %d."
|
|
1878 |
# [This case is handled in the update_job method.]
|
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
1879 |
#
|
1880 |
# "Job stopped due to printer being paused"
|
|
1881 |
# [This should be ignored, as the job was doing just
|
|
1882 |
# fine until the printer was stopped for other reasons.]
|
|
1883 |
notify_text = event['notify-text'] |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1884 |
document = jobdata['job-name'] |
1885 |
if notify_text.find ("backend errors") != -1: |
|
1886 |
message = _("There was a problem sending document `%s' " |
|
1887 |
"(job %d) to the printer.") % (document, jobid) |
|
1888 |
elif notify_text.find ("filter errors") != -1: |
|
1889 |
message = _("There was a problem processing document `%s' " |
|
1890 |
"(job %d).") % (document, jobid) |
|
1891 |
elif (notify_text.find ("being paused") != -1 or |
|
1.1.47
by Till Kamppeter
Import upstream version 1.1.11+git20090820 |
1892 |
jstate != cups.IPP_JOB_STOPPED): |
1893 |
may_be_problem = False |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
1894 |
else: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1895 |
# Give up and use the provided message untranslated.
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
1896 |
message = _("There was a problem printing document `%s' " |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1897 |
"(job %d): `%s'.") % (document, jobid, |
1898 |
notify_text) |
|
1899 |
||
1900 |
if may_be_problem: |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
1901 |
debugprint ("Problem detected") |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1902 |
self.toggle_window_display (None, force_show=True) |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1903 |
dialog = gtk.Dialog (_("Print Error"), self.JobsWindow, 0, |
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
1904 |
(_("_Diagnose"), gtk.RESPONSE_NO, |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1905 |
gtk.STOCK_OK, gtk.RESPONSE_OK)) |
1906 |
dialog.set_default_response (gtk.RESPONSE_OK) |
|
1907 |
dialog.set_border_width (6) |
|
1908 |
dialog.set_resizable (False) |
|
1909 |
dialog.set_icon_name (ICON) |
|
1910 |
hbox = gtk.HBox (False, 12) |
|
1911 |
hbox.set_border_width (6) |
|
1912 |
image = gtk.Image () |
|
1913 |
image.set_from_stock (gtk.STOCK_DIALOG_ERROR, |
|
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
1914 |
gtk.ICON_SIZE_DIALOG) |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1915 |
hbox.pack_start (image, False, False, 0) |
1916 |
vbox = gtk.VBox (False, 12) |
|
1917 |
||
1918 |
markup = ('<span weight="bold" size="larger">' + |
|
1919 |
_("Print Error") + '</span>\n\n' + |
|
1920 |
saxutils.escape (message)) |
|
1.1.53
by Till Kamppeter
Import upstream version 1.2.3+20100713 |
1921 |
try: |
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1922 |
if event['printer-state'] == cups.IPP_PRINTER_STOPPED: |
1923 |
name = event['printer-name'] |
|
1924 |
markup += ' ' |
|
1925 |
markup += (_("The printer called `%s' has " |
|
1926 |
"been disabled.") % name) |
|
1927 |
except KeyError: |
|
1928 |
pass
|
|
1929 |
||
1930 |
label = gtk.Label (markup) |
|
1931 |
label.set_use_markup (True) |
|
1932 |
label.set_line_wrap (True) |
|
1933 |
label.set_alignment (0, 0) |
|
1934 |
vbox.pack_start (label, False, False, 0) |
|
1935 |
hbox.pack_start (vbox, False, False, 0) |
|
1936 |
dialog.vbox.pack_start (hbox) |
|
1937 |
dialog.connect ('response', |
|
1.1.35
by Till Kamppeter
Import upstream version 1.0.0+git20080609 |
1938 |
self.print_error_dialog_response, jobid) |
1939 |
self.stopped_job_prompts.add (jobid) |
|
1940 |
dialog.show_all () |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1941 |
|
1942 |
def job_removed (self, mon, jobid, eventname, event): |
|
1943 |
# If the job has finished, let the user know.
|
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1944 |
if self.applet and (eventname == 'job-completed' or |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1945 |
(eventname == 'job-state-changed' and |
1946 |
event['job-state'] == cups.IPP_JOB_COMPLETED)): |
|
1947 |
reasons = event['job-state-reasons'] |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1948 |
debugprint (reasons) |
1949 |
if type (reasons) != list: |
|
1950 |
reasons = [reasons] |
|
1951 |
||
1952 |
canceled = False |
|
1953 |
for reason in reasons: |
|
1954 |
if reason.startswith ("job-canceled"): |
|
1955 |
canceled = True |
|
1956 |
break
|
|
1957 |
||
1958 |
if not canceled: |
|
1959 |
self.notify_completed_job (jobid) |
|
1960 |
||
1961 |
if self.jobiters.has_key (jobid): |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1962 |
self.store.remove (self.jobiters[jobid]) |
1963 |
del self.jobiters[jobid] |
|
1964 |
del self.jobs[jobid] |
|
1965 |
||
1966 |
if jobid in self.active_jobs: |
|
1967 |
self.active_jobs.remove (jobid) |
|
1968 |
||
1969 |
if self.jobs_attrs.has_key (jobid): |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
1970 |
del self.jobs_attrs[jobid] |
1971 |
||
1972 |
self.update_status () |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1973 |
|
1974 |
def state_reason_added (self, mon, reason): |
|
1975 |
(title, text) = reason.get_description () |
|
1976 |
printer = reason.get_printer () |
|
1977 |
||
1978 |
try: |
|
1979 |
l = self.printer_state_reasons[printer] |
|
1980 |
except KeyError: |
|
1981 |
l = [] |
|
1982 |
self.printer_state_reasons[printer] = l |
|
1983 |
||
1984 |
reason.user_notified = False |
|
1985 |
l.append (reason) |
|
1986 |
self.update_status () |
|
1987 |
self.treeview.queue_draw () |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
1988 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1989 |
if not self.applet: |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
1990 |
return
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
1991 |
|
1992 |
# Find out if the user has jobs queued for that printer.
|
|
1993 |
for job, data in self.jobs.iteritems (): |
|
1994 |
if not self.job_is_active (data): |
|
1995 |
continue
|
|
1996 |
if data['job-printer-name'] == printer: |
|
1997 |
# Yes! Notify them of the state reason, if necessary.
|
|
1998 |
self.notify_printer_state_reason_if_important (reason) |
|
1999 |
break
|
|
2000 |
||
2001 |
def state_reason_removed (self, mon, reason): |
|
2002 |
printer = reason.get_printer () |
|
2003 |
try: |
|
2004 |
reasons = self.printer_state_reasons[printer] |
|
2005 |
except KeyError: |
|
2006 |
debugprint ("Printer not found") |
|
2007 |
return
|
|
2008 |
||
2009 |
try: |
|
2010 |
i = reasons.index (reason) |
|
2011 |
except IndexError: |
|
2012 |
debugprint ("Reason not found") |
|
2013 |
return
|
|
2014 |
||
2015 |
del reasons[i] |
|
2016 |
||
2017 |
self.update_status () |
|
2018 |
self.treeview.queue_draw () |
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
2019 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
2020 |
if not self.applet: |
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
2021 |
return
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
2022 |
|
2023 |
tuple = reason.get_tuple () |
|
2024 |
try: |
|
2025 |
notification = self.state_reason_notifications[tuple] |
|
2026 |
if notification.get_data ('closed') != True: |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
2027 |
try: |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
2028 |
notification.close () |
2029 |
except glib.GError: |
|
2030 |
# Can fail if the notification wasn't even shown
|
|
2031 |
# yet (as in bug #545733).
|
|
2032 |
pass
|
|
2033 |
||
2034 |
del self.state_reason_notifications[tuple] |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
2035 |
self.set_statusicon_visibility () |
2036 |
except KeyError: |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
2037 |
pass
|
2038 |
||
2039 |
def still_connecting (self, mon, reason): |
|
2040 |
if not self.applet: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
2041 |
return
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
2042 |
|
2043 |
self.notify_printer_state_reason (reason) |
|
2044 |
||
2045 |
def now_connected (self, mon, printer): |
|
2046 |
if not self.applet: |
|
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
2047 |
return
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
2048 |
|
2049 |
# Find the connecting-to-device state reason.
|
|
2050 |
try: |
|
2051 |
reasons = self.printer_state_reasons[printer] |
|
2052 |
reason = None |
|
2053 |
for r in reasons: |
|
2054 |
if r.get_reason () == "connecting-to-device": |
|
2055 |
reason = r |
|
2056 |
break
|
|
2057 |
except KeyError: |
|
2058 |
debugprint ("Couldn't find state reason (no reasons)!") |
|
2059 |
||
2060 |
if reason != None: |
|
2061 |
tuple = reason.get_tuple () |
|
2062 |
else: |
|
2063 |
debugprint ("Couldn't find state reason in list!") |
|
2064 |
for (level, |
|
2065 |
p, |
|
2066 |
r) in self.state_reason_notifications.keys (): |
|
2067 |
if p == printer and r == "connecting-to-device": |
|
2068 |
debugprint ("Found from notifications list") |
|
2069 |
tuple = (level, p, r) |
|
2070 |
break
|
|
2071 |
||
2072 |
try: |
|
2073 |
notification = self.state_reason_notifications[tuple] |
|
2074 |
except KeyError: |
|
2075 |
debugprint ("Unexpected now_connected signal") |
|
2076 |
return
|
|
2077 |
||
2078 |
if notification.get_data ('closed') != True: |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
2079 |
try: |
1.1.52
by Till Kamppeter
Import upstream version 1.2.0+20100408 |
2080 |
notification.close () |
2081 |
except glib.GError: |
|
2082 |
# Can fail if the notification wasn't even shown
|
|
2083 |
pass
|
|
2084 |
notification.set_data ('closed', True) |
|
1.1.42
by Till Kamppeter
Import upstream version 1.1.2+git20090125 |
2085 |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
2086 |
def printer_added (self, mon, printer): |
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
2087 |
self.printer_uri_index.add_printer (printer) |
2088 |
||
2089 |
def printer_event (self, mon, printer, eventname, event): |
|
1.1.36
by Till Kamppeter
Import upstream version 1.0.2+git20080620 |
2090 |
self.printer_uri_index.update_from_attrs (printer, event) |
2091 |
||
2092 |
def printer_removed (self, mon, printer): |
|
2093 |
self.printer_uri_index.remove_printer (printer) |
|
2094 |
||
2095 |
### Cell data functions
|
|
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
2096 |
def _set_job_job_number_text (self, column, cell, model, iter, *data): |
2097 |
cell.set_property("text", str (model.get_value (iter, 0))) |
|
2098 |
||
2099 |
def _set_job_user_text (self, column, cell, model, iter, *data): |
|
2100 |
jobid = model.get_value (iter, 0) |
|
2101 |
job = self.jobs[jobid] |
|
2102 |
cell.set_property("text", job.get ('job-originating-user-name', |
|
2103 |
_("Unknown"))) |
|
2104 |
||
2105 |
def _set_job_document_text (self, column, cell, model, iter, *data): |
|
2106 |
jobid = model.get_value (iter, 0) |
|
2107 |
job = self.jobs[jobid] |
|
2108 |
cell.set_property("text", job.get('job-name', _("Unknown"))) |
|
2109 |
||
2110 |
def _set_job_printer_text (self, column, cell, model, iter, *data): |
|
2111 |
jobid = model.get_value (iter, 0) |
|
2112 |
reasons = self.jobs[jobid].get('job-state-reasons') |
|
1.1.50
by Till Kampeter
Import upstream version 1.1.16+git20100209 |
2113 |
if reasons == 'printer-stopped': |
2114 |
reason = ' - ' + _("disabled") |
|
2115 |
else: |
|
2116 |
reason = '' |
|
2117 |
cell.set_property("text", self.jobs[jobid]['job-printer-name']+reason) |
|
2118 |
||
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
2119 |
def _set_job_size_text (self, column, cell, model, iter, *data): |
2120 |
jobid = model.get_value (iter, 0) |
|
2121 |
job = self.jobs[jobid] |
|
2122 |
size = _("Unknown") |
|
2123 |
if job.has_key ('job-k-octets'): |
|
2124 |
size = str (job['job-k-octets']) + 'k' |
|
2125 |
cell.set_property("text", size) |
|
2126 |
||
2127 |
def _find_job_state_text (self, job): |
|
2128 |
data = self.jobs[job] |
|
2129 |
jstate = data.get ('job-state', cups.IPP_JOB_PROCESSING) |
|
2130 |
s = int (jstate) |
|
2131 |
job_requires_auth = (s == cups.IPP_JOB_HELD and |
|
2132 |
data.get ('job-hold-until', 'none') == |
|
2133 |
'auth-info-required') |
|
2134 |
state = None |
|
2135 |
if job_requires_auth: |
|
2136 |
state = _("Held for authentication") |
|
2137 |
elif s == cups.IPP_JOB_HELD: |
|
2138 |
state = _("Held") |
|
2139 |
until = data.get ('job-hold-until') |
|
2140 |
if until != None: |
|
2141 |
try: |
|
2142 |
colon1 = until.find (':') |
|
2143 |
if colon1 != -1: |
|
2144 |
now = time.gmtime () |
|
2145 |
hh = int (until[:colon1]) |
|
2146 |
colon2 = until[colon1 + 1:].find (':') |
|
2147 |
if colon2 != -1: |
|
2148 |
colon2 += colon1 + 1 |
|
2149 |
mm = int (until[colon1 + 1:colon2]) |
|
2150 |
ss = int (until[colon2 + 1:]) |
|
2151 |
else: |
|
2152 |
mm = int (until[colon1 + 1:]) |
|
2153 |
ss = 0 |
|
2154 |
||
2155 |
day = now.tm_mday |
|
2156 |
if (hh < now.tm_hour or |
|
2157 |
(hh == now.tm_hour and |
|
2158 |
(mm < now.tm_min or |
|
2159 |
(mm == now.tm_min and ss < now.tm_sec)))): |
|
2160 |
day += 1 |
|
2161 |
||
2162 |
hold = (now.tm_year, now.tm_mon, day, |
|
2163 |
hh, mm, ss, 0, 0, -1) |
|
2164 |
old_tz = os.environ.get("TZ") |
|
2165 |
os.environ["TZ"] = "UTC" |
|
2166 |
simpletime = time.mktime (hold) |
|
2167 |
||
2168 |
if old_tz == None: |
|
2169 |
del os.environ["TZ"] |
|
2170 |
else: |
|
2171 |
os.environ["TZ"] = old_tz |
|
2172 |
||
2173 |
local = time.localtime (simpletime) |
|
2174 |
state = _("Held until %s") % time.strftime ("%X", local) |
|
2175 |
except ValueError: |
|
2176 |
pass
|
|
2177 |
if until == "day-time": |
|
2178 |
state = _("Held until day-time") |
|
2179 |
elif until == "evening": |
|
2180 |
state = _("Held until evening") |
|
2181 |
elif until == "night": |
|
2182 |
state = _("Held until night-time") |
|
2183 |
elif until == "second-shift": |
|
2184 |
state = _("Held until second shift") |
|
2185 |
elif until == "third-shift": |
|
2186 |
state = _("Held until third shift") |
|
2187 |
elif until == "weekend": |
|
2188 |
state = _("Held until weekend") |
|
2189 |
else: |
|
2190 |
try: |
|
2191 |
state = { cups.IPP_JOB_PENDING: _("Pending"), |
|
2192 |
cups.IPP_JOB_PROCESSING: _("Processing"), |
|
2193 |
cups.IPP_JOB_STOPPED: _("Stopped"), |
|
2194 |
cups.IPP_JOB_CANCELED: _("Canceled"), |
|
2195 |
cups.IPP_JOB_ABORTED: _("Aborted"), |
|
2196 |
cups.IPP_JOB_COMPLETED: _("Completed") }[s] |
|
2197 |
except IndexError: |
|
2198 |
pass
|
|
2199 |
||
2200 |
if state == None: |
|
2201 |
state = _("Unknown") |
|
2202 |
||
2203 |
return state |
|
2204 |
||
2205 |
def _set_job_status_icon (self, column, cell, model, iter, *data): |
|
2206 |
jobid = model.get_value (iter, 0) |
|
2207 |
data = self.jobs[jobid] |
|
2208 |
jstate = data.get ('job-state', cups.IPP_JOB_PROCESSING) |
|
2209 |
s = int (jstate) |
|
2210 |
if s == cups.IPP_JOB_PROCESSING: |
|
2211 |
icon = self.icon_jobs_processing |
|
2212 |
else: |
|
2213 |
icon = self.icon_jobs |
|
2214 |
||
2215 |
if s == cups.IPP_JOB_HELD: |
|
2216 |
theme = gtk.icon_theme_get_default () |
|
2217 |
emblem = theme.load_icon (gtk.STOCK_MEDIA_PAUSE, 22 / 2, 0) |
|
2218 |
copy = icon.copy () |
|
2219 |
emblem.composite (copy, 0, 0, |
|
2220 |
copy.get_width (), |
|
2221 |
copy.get_height (), |
|
2222 |
copy.get_width () / 2 - 1, |
|
2223 |
copy.get_height () / 2 - 1, |
|
2224 |
1.0, 1.0, |
|
2225 |
gtk.gdk.INTERP_NEAREST, 255) |
|
2226 |
icon = copy |
|
2227 |
else: |
|
2228 |
# Check state reasons.
|
|
2229 |
printer = data['job-printer-name'] |
|
2230 |
icon = self.add_state_reason_emblem (icon, printer=printer) |
|
2231 |
||
2232 |
cell.set_property ("pixbuf", icon) |
|
2233 |
||
2234 |
def _set_job_status_text (self, column, cell, model, iter, *data): |
|
2235 |
jobid = model.get_value (iter, 0) |
|
2236 |
data = self.jobs[jobid] |
|
2237 |
try: |
|
1.1.34
by Till Kamppeter
Import upstream version 0.9.90+svn2385 |
2238 |
text = data['_status_text'] |
1.1.48
by Till Kamppeter
Import upstream version 1.1.11+git20090825 |
2239 |
except KeyError: |
2240 |
text = self._find_job_state_text (jobid) |
|
2241 |
data['_status_text'] = text |
|
2242 |
||
2243 |
printer = data['job-printer-name'] |
|
2244 |
reasons = self.printer_state_reasons.get (printer, []) |
|
2245 |
if len (reasons) > 0: |
|
2246 |
worst_reason = reasons[0] |
|
2247 |
for reason in reasons[1:]: |
|
2248 |
if reason > worst_reason: |
|
2249 |
worst_reason = reason |
|
2250 |
(title, unused) = worst_reason.get_description () |
|
2251 |
text += " - " + title |
|
2252 |
||
2253 |
cell.set_property ("text", text) |
|
2254 |
||
1.1.58
by Till Kamppeter
Import upstream version 1.3.1 |
2255 |
gobject.type_register (JobViewer) |
2256 |