Tizen 2.1 base
[platform/upstream/hplip.git] / ui / scrollfax.py
1 # -*- coding: utf-8 -*-
2 #
3 # (c) Copyright 2001-2009 Hewlett-Packard Development Company, L.P.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # Author: Don Welch
20 #
21
22 # Local
23 from base.g import *
24 from base import utils, magic, pml
25 from prnt import cups
26 from ui_utils import load_pixmap
27
28 # Qt
29 from qt import *
30 from scrollview import ScrollView, PixmapLabelButton
31 from allowabletypesdlg import AllowableTypesDlg
32 from waitform import WaitForm
33
34 # Std Lib
35 import os.path, os
36 import struct, Queue, time
37
38
39 fax_enabled = prop.fax_build
40
41 if fax_enabled:
42     try:
43         from fax import fax
44     except ImportError:
45         # This can fail on Python < 2.3 due to the datetime module
46         # or if fax was diabled during the build
47         log.warn("Fax send disabled - Python 2.3+ required.")
48         fax_enabled = False
49
50
51 coverpages_enabled = False
52 if fax_enabled:
53     try:
54         import reportlab
55         ver = reportlab.Version
56         try:
57             ver_f = float(ver)
58         except ValueError:
59             ver_f = 0.0
60
61         if ver_f >= 2.0:
62             coverpages_enabled = True
63         else:
64             log.warn("Pre-2.0 version of Reportlab installed. Fax coverpages disabled.")
65
66     except ImportError:
67         log.warn("Reportlab not installed. Fax coverpages disabled.")
68
69
70 if not coverpages_enabled:
71     log.warn("Please install version 2.0+ of Reportlab for coverpage support.")
72
73 if fax_enabled and coverpages_enabled:
74     from fax import coverpages
75     from coverpageform import CoverpageForm
76
77
78 # Used to store MIME types for files
79 # added directly in interface.
80 job_types = {} # { job_id : "mime_type", ...}
81
82 class FileListViewItem(QListViewItem):
83     def __init__(self, parent, order, title, mime_type_desc, str_pages, path):
84         QListViewItem.__init__(self, parent, order, title, mime_type_desc, str_pages, path)
85         self.path = path
86
87
88 class RecipientListViewItem(QListViewItem):
89     def __init__(self, parent, order, name, fax, notes):
90         QListViewItem.__init__(self, parent, order, name, fax, notes)
91         self.name = name
92         #self.entry = entry
93
94
95 class PhoneNumValidator(QValidator):
96     def __init__(self, parent=None, name=None):
97         QValidator.__init__(self, parent, name)
98
99     def validate(self, input, pos):
100         input = unicode(input)
101         if not input:
102             return QValidator.Acceptable, pos
103         elif input[pos-1] not in u'0123456789-(+) *#':
104             return QValidator.Invalid, pos
105         elif len(input) > 50:
106             return QValidator.Invalid, pos
107         else:
108             return QValidator.Acceptable, pos
109
110
111
112 class ScrollFaxView(ScrollView):
113     def __init__(self, service, parent = None, form=None, name = None,fl = 0):
114         ScrollView.__init__(self, service, parent, name, fl)
115
116         global fax_enabled
117         if service is None:
118             fax_enabled = False
119
120         self.form = form
121         self.file_list = []
122         self.pages_button_group = 0
123         self.recipient_list = []
124         self.username = prop.username
125         self.busy = False
126         self.allowable_mime_types = cups.getAllowableMIMETypes()
127         self.cover_page_func, cover_page_png = None, None
128         self.cover_page_message = ''
129         self.cover_page_re = ''
130         self.cover_page_name = ''
131         self.update_queue = Queue.Queue() # UI updates from send thread
132         self.event_queue = Queue.Queue() # UI events (cancel) to send thread
133         self.prev_selected_file_path = ''
134         self.prev_selected_recipient = ''
135         self.preserve_formatting = False
136         self.waitdlg = None
137         log.debug(self.allowable_mime_types)
138         self.last_job_id = 0
139         self.dev = None
140         self.lock_file = None
141
142
143         self.db =  fax.FaxAddressBook()
144         self.last_db_modification = self.db.last_modification_time()
145
146         self.MIME_TYPES_DESC = \
147         {
148             "application/pdf" : (self.__tr("PDF Document"), '.pdf'),
149             "application/postscript" : (self.__tr("Postscript Document"), '.ps'),
150             "application/vnd.hp-HPGL" : (self.__tr("HP Graphics Language File"), '.hgl, .hpg, .plt, .prn'),
151             "application/x-cshell" : (self.__tr("C Shell Script"), '.csh, .sh'),
152             "application/x-csource" : (self.__tr("C Source Code"), '.c'),
153             "text/cpp": (self.__tr("C++ Source Code"), '.cpp, .cxx'),
154             "application/x-perl" : (self.__tr("Perl Script"), '.pl'),
155             "application/x-python" : (self.__tr("Python Program"), '.py'),
156             "application/x-shell" : (self.__tr("Shell Script"), '.sh'),
157             "application/x-sh" : (self.__tr("Shell Script"), '.sh'),
158             "text/plain" : (self.__tr("Plain Text"), '.txt, .log, etc'),
159             "text/html" : (self.__tr("HTML Dcoument"), '.htm, .html'),
160             "image/gif" : (self.__tr("GIF Image"), '.gif'),
161             "image/png" : (self.__tr("PNG Image"), '.png'),
162             "image/jpeg" : (self.__tr("JPEG Image"), '.jpg, .jpeg'),
163             "image/tiff" : (self.__tr("TIFF Image"), '.tif, .tiff'),
164             "image/x-bitmap" : (self.__tr("Bitmap (BMP) Image"), '.bmp'),
165             "image/x-bmp" : (self.__tr("Bitmap (BMP) Image"), '.bmp'),
166             "image/x-photocd" : (self.__tr("Photo CD Image"), '.pcd'),
167             "image/x-portable-anymap" : (self.__tr("Portable Image (PNM)"), '.pnm'),
168             "image/x-portable-bitmap" : (self.__tr("Portable B&W Image (PBM)"), '.pbm'),
169             "image/x-portable-graymap" : (self.__tr("Portable Grayscale Image (PGM)"), '.pgm'),
170             "image/x-portable-pixmap" : (self.__tr("Portable Color Image (PPM)"), '.ppm'),
171             "image/x-sgi-rgb" : (self.__tr("SGI RGB"), '.rgb'),
172             "image/x-xbitmap" : (self.__tr("X11 Bitmap (XBM)"), '.xbm'),
173             "image/x-xpixmap" : (self.__tr("X11 Pixmap (XPM)"), '.xpm'),
174             "image/x-sun-raster" : (self.__tr("Sun Raster Format"), '.ras'),
175         }
176
177
178         user_settings = utils.UserSettings()
179         self.cmd_fab = user_settings.cmd_fab
180         log.debug("FAB command: %s" % self.cmd_fab)
181
182         if fax_enabled:
183             self.check_timer = QTimer(self, "CheckTimer")
184             self.connect(self.check_timer, SIGNAL('timeout()'), self.PeriodicCheck)
185             self.check_timer.start(3000)
186
187
188     def fillControls(self):
189         ScrollView.fillControls(self)
190
191         if fax_enabled:
192             if self.addPrinterFaxList(): #faxes=True, printers=False):
193
194                 self.addGroupHeading("files_to_fax", self.__tr("File(s) to Fax"))
195                 self.addFileList()
196
197                 if coverpages_enabled:
198                     self.addGroupHeading("coverpage", self.__tr("Add/Edit Fax Coverpage"))
199                     self.addCoverpage()
200
201                 self.addGroupHeading("recipients", self.__tr("Recipient(s)"))
202
203                 self.addRecipientList()
204
205                 self.addGroupHeading("recipient_add_from_fab", self.__tr("Add Recipients from the Fax Address Book"))
206
207                 self.addRecipientAddFromFAB()
208
209                 self.addGroupHeading("recipient_quick_add", self.__tr("<i>Quick Add</i> an Individual Recipient"))
210
211                 self.addRecipientQuickAdd()
212
213                 self.addGroupHeading("space1", "")
214
215                 self.faxButton = self.addActionButton("bottom_nav", self.__tr("Send Fax Now"),
216                                         self.faxButton_clicked, 'fax.png', 'fax.png',
217                                         self.__tr("Close"), self.funcButton_clicked)
218
219                 self.faxButton.setEnabled(False)
220
221                 self.updateRecipientCombos()
222
223                 self.maximizeControl()
224
225             else:
226                 QApplication.restoreOverrideCursor()
227                 self.form.FailureUI("<b>Fax is disabled.</b><p>No CUPS fax queue found for this device.")
228                 self.funcButton_clicked()
229
230         else:
231             QApplication.restoreOverrideCursor()
232             self.form.FailureUI("<b>Fax is disabled.</b><p>Python version 2.3 or greater required or fax was disabled during build.")
233             self.funcButton_clicked()
234
235
236
237     def onUpdate(self, cur_device=None):
238         log.debug("ScrollPrintView.onUpdate()")
239         self.updateFileList()
240         self.updateRecipientList()
241
242
243     def PeriodicCheck(self): # called by check_timer every 3 sec
244         #print self
245         if not self.busy:
246             log.debug("Checking for incoming faxes...")
247
248             result = list(self.service.CheckForWaitingFax(self.cur_device.device_uri,
249                           prop.username, self.last_job_id))
250
251             fax_file = str(result[7])
252
253             if fax_file:
254                 self.last_job_id = 0
255                 log.debug("A new fax has arrived: %s" % fax_file)
256                 job_id = int(result[4])
257                 title = str(result[5])
258
259                 if self.form.isMinimized():
260                     self.form.showNormal()
261
262                 self.check_timer.stop()
263                 self.addFileFromJob(0, title, prop.username, job_id, fax_file)
264                 self.check_timer.start(3000)
265                 return
266
267             log.debug("Not found.")
268
269             # Check for updated FAB
270             last_db_modification = self.db.last_modification_time()
271
272             if last_db_modification > self.last_db_modification:
273                 QApplication.setOverrideCursor(QApplication.waitCursor)
274                 log.debug("FAB has been modified. Re-reading...")
275                 self.last_db_modification = last_db_modification
276                 self.updateRecipientCombos()
277                 QApplication.restoreOverrideCursor()
278
279
280     def onPrinterChange(self, printer_name):
281         if printer_name != self.cur_printer:
282             self.unlock()
283             self.lock(printer_name)
284             #utils.unlock(self.lock_file)
285             #ok, self.lock_file = utils.lock_app('hp-sendfax-%s' % printer_name, True)
286
287         ScrollView.onPrinterChange(self, printer_name)
288
289     def unlock(self):
290         utils.unlock(self.lock_file)
291
292     def lock(self, printer_name=None):
293         if printer_name is None:
294             printer_name = self.cur_printer
295
296         ok, self.lock_file = utils.lock_app('hp-sendfax-%s' % printer_name, True)
297
298
299
300     # Event handler for adding files from a external print job (not during fax send thread)
301     def addFileFromJob(self, event, title, username, job_id, fax_file):
302         QApplication.setOverrideCursor(QApplication.waitCursor)
303         self.busy = True
304
305         try:
306             f = file(fax_file, 'r')
307             header = f.read(fax.FILE_HEADER_SIZE)
308
309             if len(header) != fax.FILE_HEADER_SIZE:
310                 log.error("Invalid fax file! (truncated header or no data)")
311                 sys.exit(1)
312
313             mg, version, total_pages, hort_dpi, vert_dpi, page_size, \
314                 resolution, encoding, reserved1, reserved2 = \
315                 struct.unpack(">8sBIHHBBBII", header[:fax.FILE_HEADER_SIZE])
316
317             log.debug("Magic=%s Ver=%d Pages=%d hDPI=%d vDPI=%d Size=%d Res=%d Enc=%d" %
318                       (mg, version, total_pages, hort_dpi, vert_dpi, page_size, resolution, encoding))
319
320             if total_pages > 0:
321                 mime_type = job_types.get(job_id, "application/hplip-fax")
322                 mime_type_desc = self.MIME_TYPES_DESC.get(mime_type, ('Unknown', 'n/a'))[0]
323                 log.debug("%s (%s)" % (mime_type, mime_type_desc))
324                 self.file_list.append((fax_file, mime_type, mime_type_desc, title, total_pages))
325                 self.prev_selected_file_path = fax_file
326             else:
327                 self.form.FailureUI("<b>Render Failure:</b><p>Rendered document contains no data.")
328
329             self.updateFileList()
330
331         finally:
332             self.busy = False
333
334             if self.waitdlg is not None:
335                 self.waitdlg.hide()
336                 self.waitdlg.close()
337                 self.waitdlg = None
338
339             QApplication.restoreOverrideCursor()
340
341
342     def add_fax_canceled(self):
343             pass
344
345     #
346     # FILE LIST
347     #
348
349     def addFileList(self):
350         widget = self.getWidget()
351
352         layout37 = QGridLayout(widget,1,1,5,10,"layout37")
353
354         self.addFilePushButton = PixmapLabelButton(widget, "list_add.png",
355             "list_add.png", name='addFilePushButton')
356
357         layout37.addWidget(self.addFilePushButton,2,0)
358
359         self.removeFilePushButton = PixmapLabelButton(widget,
360             "list_remove.png", "list_remove.png", name='removeFilePushButton')
361
362         layout37.addWidget(self.removeFilePushButton,2,1)
363
364         self.moveFileUpPushButton = PixmapLabelButton(widget, "up.png",
365             "up.png", name='moveFileUpPushButton')
366
367         layout37.addWidget(self.moveFileUpPushButton,2,2)
368
369         self.moveFileDownPushButton = PixmapLabelButton(widget, "down.png",
370             "down.png", name='moveFileDownPushButton')
371
372         layout37.addWidget(self.moveFileDownPushButton,2,3)
373
374         self.showTypesPushButton = PixmapLabelButton(widget, "mimetypes.png",
375             None, name='showTypesPushButton')
376
377         layout37.addWidget(self.showTypesPushButton,2,5)
378
379
380         self.fileListView = QListView(widget,"fileListView")
381         self.fileListView.addColumn(self.__tr("Order"))
382         self.fileListView.addColumn(self.__tr("Name"))
383         self.fileListView.addColumn(self.__tr("Type"))
384         self.fileListView.addColumn(self.__tr("Pages"))
385         self.fileListView.addColumn(self.__tr("Path"))
386         self.fileListView.setAllColumnsShowFocus(1)
387         self.fileListView.setShowSortIndicator(1)
388         self.fileListView.setColumnWidth(0, 100) # Order
389         self.fileListView.setColumnWidth(1, 150) # Name
390         self.fileListView.setColumnWidth(2, 100) # Type
391         self.fileListView.setColumnWidth(3, 100) # Pages
392         self.fileListView.setColumnWidth(4, 300) # Path
393         self.fileListView.setItemMargin(2)
394         self.fileListView.setSorting(-1)
395
396         layout37.addMultiCellWidget(self.fileListView,1,1,0,5)
397
398         spacer26 = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
399         layout37.addItem(spacer26,2,4)
400
401         self.addFilePushButton.setText(self.__tr("Add File..."))
402         self.showTypesPushButton.setText(self.__tr("Show Types..."))
403         self.removeFilePushButton.setText(self.__tr("Remove File"))
404         self.moveFileDownPushButton.setText(self.__tr("Move Down"))
405         self.moveFileUpPushButton.setText(self.__tr("Move Up"))
406
407         self.removeFilePushButton.setEnabled(False)
408         self.moveFileDownPushButton.setEnabled(False)
409         self.moveFileUpPushButton.setEnabled(False)
410         self.connect(self.addFilePushButton, SIGNAL("clicked()"), self.addFile_clicked)
411         self.connect(self.removeFilePushButton, SIGNAL("clicked()"), self.removeFile_clicked)
412         self.connect(self.showTypesPushButton, SIGNAL("clicked()"), self.showFileTypes_clicked)
413
414         self.connect(self.moveFileUpPushButton, SIGNAL("clicked()"), self.moveFileUp_clicked)
415         self.connect(self.moveFileDownPushButton, SIGNAL("clicked()"), self.moveFileDown_clicked)
416
417         self.connect(self.fileListView,SIGNAL("rightButtonClicked(QListViewItem*,const QPoint&, int)"),self.fileListView_rightButtonClicked)
418
419         self.connect(self.fileListView, SIGNAL("selectionChanged(QListViewItem*)"), self.fileListView_selectionChanged)
420
421         self.addWidget(widget, "file_list", maximize=True)
422
423     def fileListView_selectionChanged(self, i):
424         try:
425             self.prev_selected_file_path = i.path
426         except AttributeError:
427             pass
428         else:
429             flv = self.fileListView
430             selected_item = flv.selectedItem()
431             file_count = flv.childCount()
432             last_item = flv.firstChild()
433             while last_item.nextSibling():
434                 last_item = last_item.nextSibling()
435
436             self.moveFileDownPushButton.setEnabled(file_count > 1 and selected_item is not last_item)
437             self.moveFileUpPushButton.setEnabled(file_count > 1 and selected_item is not flv.firstChild())
438
439
440     def moveFileUp_clicked(self):
441         try:
442             path = self.fileListView.selectedItem().path
443         except AttributeError:
444             return
445         else:
446             for i in range(1, len(self.file_list)):
447                 if self.file_list[i][0] == path:
448                     self.file_list[i-1],self.file_list[i] = self.file_list[i], self.file_list[i-1]
449
450             self.updateFileList()
451
452     def moveFileDown_clicked(self):
453         try:
454             path = self.fileListView.selectedItem().path
455         except AttributeError:
456             return
457         else:
458             for i in range(len(self.file_list) - 2, -1, -1):
459                 if self.file_list[i][0] == path:
460                     self.file_list[i], self.file_list[i+1] = self.file_list[i+1], self.file_list[i]
461
462             self.updateFileList()
463
464
465     def fileListView_rightButtonClicked(self, item, pos, col):
466         popup = QPopupMenu(self)
467
468         popup.insertItem(QIconSet(load_pixmap('list_add', '16x16')),
469             self.__tr("Add File..."), self.addFile_clicked)
470
471         if item is not None:
472             popup.insertItem(QIconSet(load_pixmap('list_remove', '16x16')),
473                 self.__tr("Remove File"), self.removeFile_clicked)
474
475             if self.fileListView.childCount() > 1:
476                 last_item = self.fileListView.firstChild()
477                 while last_item is not None and last_item.nextSibling():
478                     last_item = last_item.nextSibling()
479
480                 if item is not self.fileListView.firstChild():
481                     popup.insertItem(QIconSet(load_pixmap('up', '16x16')),
482                         self.__tr("Move Up"), self.moveFileUp_clicked)
483
484                 if item is not last_item:
485                     popup.insertItem(QIconSet(load_pixmap('down', '16x16')),
486                         self.__tr("Move Down"), self.moveFileDown_clicked)
487
488
489         popup.insertSeparator(-1)
490         popup.insertItem(QIconSet(load_pixmap('mimetypes', '16x16')),
491             self.__tr("Show File Types..."), self.showFileTypes_clicked)
492
493         popup.popup(pos)
494
495
496     def addFile(self, path, title, mime_type, mime_type_desc, pages):
497         self.file_list.append((path, mime_type, mime_type_desc, title, pages))
498         self.prev_selected_file_path = path
499
500         self.updateFileList()
501
502     def processFile(self, path, title=''): # Process an arbitrary file ("Add file...")
503         path = os.path.realpath(path)
504         if not title:
505             title = os.path.basename(path)
506
507         if os.path.exists(path) and os.access(path, os.R_OK):
508             mime_type = magic.mime_type(path)
509             mime_type_desc = mime_type
510
511             if mime_type == 'application/hplip-fax':
512                 mime_type_desc = self.MIME_TYPES_DESC[mime_type][0]
513
514                 fax_file_fd = file(path, 'r')
515                 header = fax_file_fd.read(fax.FILE_HEADER_SIZE)
516
517                 mg, version, pages, hort_dpi, vert_dpi, page_size, \
518                     resolution, encoding, reserved1, reserved2 = self.decode_fax_header(header)
519
520                 if mg != 'hplip_g3':
521                     log.error("Invalid file header. Bad magic.")
522                     self.form.WarningUI(self.__tr("<b>Invalid HPLIP Fax file.</b><p>Bad magic!"))
523                     return
524
525                 self.addFile(path, title, mime_type, mime_type_desc, pages)
526
527             else:
528                 log.debug(repr(mime_type))
529                 try:
530                     mime_type_desc = self.MIME_TYPES_DESC[mime_type][0]
531                 except KeyError:
532                     self.form.WarningUI(self.__tr("<b>You are trying to add a file that cannot be directly faxed with this utility.</b><p>To print this file, use the print command in the application that created it."))
533                     return
534                 else:
535                     log.debug("Adding file: title='%s' file=%s mime_type=%s mime_desc=%s)" % (title, path, mime_type, mime_type_desc))
536
537                     all_pages = True
538                     page_range = ''
539                     page_set = 0
540                     #nup = 1
541
542                     cups.resetOptions()
543
544                     self.cups_printers = cups.getPrinters()
545
546                     printer_state = cups.IPP_PRINTER_STATE_STOPPED
547                     for p in self.cups_printers:
548                         if p.name == self.cur_printer:
549                             printer_state = p.state
550
551                     log.debug("Printer state = %d" % printer_state)
552
553                     if printer_state == cups.IPP_PRINTER_STATE_IDLE:
554                         log.debug("Printing: %s on %s" % (path, self.cur_printer))
555                         sent_job_id = cups.printFile(self.cur_printer, path, os.path.basename(path))
556                         self.last_job_id = sent_job_id
557                         job_types[sent_job_id] = mime_type # save for later
558                         log.debug("Job ID=%d" % sent_job_id)
559
560                         QApplication.setOverrideCursor(QApplication.waitCursor)
561
562                         self.waitdlg = WaitForm(0, self.__tr("Processing fax file..."), None, self, modal=1) # self.add_fax_canceled
563                         self.waitdlg.show()
564
565                     else:
566                         self.form.FailureUI(self.__tr("<b>Printer '%1' is in a stopped or error state.</b><p>Check the printer queue in CUPS and try again.").arg(self.cur_printer))
567                         cups.resetOptions()
568                         return
569
570                     cups.resetOptions()
571                     QApplication.restoreOverrideCursor()
572
573         else:
574             self.form.FailureUI(self.__tr("<b>Unable to add file '%1' to file list (file not found or insufficient permissions).</b><p>Check the file name and try again.").arg(path))
575
576
577
578     def updateFileList(self):
579         self.fileListView.clear()
580         temp = self.file_list[:]
581         temp.reverse()
582         order = len(temp)
583         last_item = None
584         selected_item = None
585
586         for path, mime_type, mime_type_desc, title, pages in temp:
587             i = FileListViewItem(self.fileListView, str(order), title, mime_type_desc, str(pages), path)
588
589             if not self.prev_selected_file_path or self.prev_selected_file_path == path:
590                 self.fileListView.setSelected(i, True)
591                 selected_item = i
592                 self.prev_selected_file_path = path
593
594             order -= 1
595
596         last_item = self.fileListView.firstChild()
597         while last_item is not None and last_item.nextSibling():
598             last_item = last_item.nextSibling()
599
600         file_count = self.fileListView.childCount()
601         self.moveFileDownPushButton.setEnabled(file_count > 1 and selected_item is not last_item)
602         self.moveFileUpPushButton.setEnabled(file_count > 1 and selected_item is not self.fileListView.firstChild())
603         self.checkSendFaxButton()
604         self.removeFilePushButton.setEnabled(file_count > 0)
605
606
607
608     def addFile_clicked(self):
609         dlg = QFileDialog(user_conf.workingDirectory(), QString.null, None, None, True)
610
611         dlg.setCaption("openfile")
612         dlg.setMode(QFileDialog.ExistingFile)
613         dlg.show()
614
615         if dlg.exec_loop() == QDialog.Accepted:
616                 results = dlg.selectedFile()
617                 working_directory = unicode(dlg.dir().absPath())
618                 log.debug("results: %s" % results)
619                 user_conf.setWorkingDirectory(working_directory)
620
621                 if results:
622                     path = unicode(results)
623                     self.processFile(path)
624
625
626     def removeFile_clicked(self):
627         try:
628             path = self.fileListView.selectedItem().path
629         except AttributeError:
630             return
631         else:
632             temp = self.file_list[:]
633             index = 0
634             for p, t, d, x, g in temp:
635                 if p == path:
636                     del self.file_list[index]
637
638                     if t == 'application/hplip-fax-coverpage':
639                         self.addCoverpagePushButton.setEnabled(coverpages_enabled)
640                         self.editCoverpagePushButton.setEnabled(False)
641
642                     self.prev_selected_file_path = ''
643                     self.updateFileList()
644                     break
645
646                 index += 1
647
648
649     def showFileTypes_clicked(self):
650         x = {}
651         for a in self.allowable_mime_types:
652             x[a] = self.MIME_TYPES_DESC.get(a, ('Unknown', 'n/a'))
653
654         log.debug(x)
655         dlg = AllowableTypesDlg(x, self)
656         dlg.exec_loop()
657
658
659     #
660     # COVERPAGE
661     #
662
663     def addCoverpage(self):
664         widget = self.getWidget()
665
666         layout14 = QGridLayout(widget,1,1,5,10,"layout14")
667
668         self.editCoverpagePushButton = PixmapLabelButton(widget,
669             "edit.png", "edit.png", name='')
670
671         layout14.addWidget(self.editCoverpagePushButton,0,1)
672
673         self.addCoverpagePushButton = PixmapLabelButton(widget,
674             "list_add.png", "list_add.png", name='')
675
676         layout14.addWidget(self.addCoverpagePushButton,0,2)
677         spacer12_2 = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
678         layout14.addItem(spacer12_2,0,0)
679
680         self.editCoverpagePushButton.setText(self.__tr("Edit..."))
681         self.editCoverpagePushButton.setEnabled(False)
682
683         self.addCoverpagePushButton.setText(self.__tr("Add..."))
684
685         self.connect(self.editCoverpagePushButton,SIGNAL("clicked()"),self.editCoverpagePushButton_clicked)
686         self.connect(self.addCoverpagePushButton,SIGNAL("clicked()"),self.addCoverpagePushButton_clicked)
687
688         self.addWidget(widget, "coverpage")
689
690     def editCoverpagePushButton_clicked(self):
691         self.showCoverPageDlg()
692
693     def addCoverpagePushButton_clicked(self):
694         if self.showCoverPageDlg():
695             self.file_list.insert(0, ('n/a', "application/hplip-fax-coverpage",
696                 self.__tr("HP Fax Coverpage"), self.__tr("Cover Page"), 1))
697
698             self.updateFileList()
699             self.addCoverpagePushButton.setEnabled(False)
700             self.editCoverpagePushButton.setEnabled(True)
701
702     def showCoverPageDlg(self):
703         dlg = CoverpageForm(self.cover_page_name, self.preserve_formatting, parent=self)
704         dlg.messageTextEdit.setText(self.cover_page_message)
705         dlg.regardingTextEdit.setText(self.cover_page_re)
706
707         if dlg.exec_loop() == QDialog.Accepted:
708
709             self.cover_page_func, cover_page_png = dlg.data
710             self.cover_page_message = unicode(dlg.messageTextEdit.text())
711             self.cover_page_re = unicode(dlg.regardingTextEdit.text())
712             self.cover_page_name = dlg.coverpage_name
713             self.preserve_formatting = dlg.preserve_formatting
714             return True
715
716         return False
717
718
719
720     #
721     # RECIPIENT LIST
722     #
723
724     def addRecipientList(self):
725         widget = self.getWidget()
726
727         layout9 = QGridLayout(widget,1,1,5,10,"layout9")
728
729         self.moveDownPushButton = PixmapLabelButton(widget,
730             "down_user.png", "down_user.png", name='')
731
732         layout9.addWidget(self.moveDownPushButton,1,2)
733
734         self.recipientListView = QListView(widget,"recipientListView")
735         self.recipientListView.addColumn(self.__tr("Order"))
736         self.recipientListView.addColumn(self.__tr("Name"))
737         self.recipientListView.addColumn(self.__tr("Fax Number"))
738         self.recipientListView.addColumn(self.__tr("Notes"))
739
740         self.recipientListView.setAllColumnsShowFocus(1)
741         self.recipientListView.setShowSortIndicator(1)
742         self.recipientListView.setColumnWidth(0, 100) # Order
743         self.recipientListView.setColumnWidth(1, 150) # Name
744         self.recipientListView.setColumnWidth(2, 200) # Fax Number
745         self.recipientListView.setColumnWidth(3, 250) # Notes
746         self.recipientListView.setItemMargin(2)
747         self.recipientListView.setSorting(-1)
748
749         widget.setMaximumHeight(250)
750
751         layout9.addMultiCellWidget(self.recipientListView,0,0,0,4)
752
753         self.fabPushButton = PixmapLabelButton(widget,
754                     "fab", None, name='')
755
756         layout9.addWidget(self.fabPushButton,1,4)
757
758         self.removeRecipientPushButton = PixmapLabelButton(widget,
759             "remove_user.png", "remove_user.png", name='')
760
761         self.removeRecipientPushButton.setEnabled(1)
762
763         layout9.addWidget(self.removeRecipientPushButton,1,0)
764         spacer10 = QSpacerItem(20,20,QSizePolicy.MinimumExpanding,QSizePolicy.Minimum)
765         layout9.addItem(spacer10,1,3)
766
767         self.moveUpPushButton = PixmapLabelButton(widget,
768             "up_user.png", "up_user.png", name='')
769
770         layout9.addWidget(self.moveUpPushButton,1,1)
771
772         self.moveDownPushButton.setEnabled(False)
773         self.moveUpPushButton.setEnabled(False)
774         self.removeRecipientPushButton.setEnabled(False)
775
776         self.moveDownPushButton.setText(self.__tr("Move Down"))
777         self.fabPushButton.setText(self.__tr("Fax Address Book..."))
778         self.removeRecipientPushButton.setText(self.__tr("Remove"))
779         self.moveUpPushButton.setText(self.__tr("Move Up"))
780
781
782         self.connect(self.recipientListView,SIGNAL("rightButtonClicked(QListViewItem*,const QPoint&,int)"),self.recipientListView_rightButtonClicked)
783
784         self.connect(self.removeRecipientPushButton,SIGNAL("clicked()"),self.removeRecipientPushButton_clicked)
785         self.connect(self.moveUpPushButton,SIGNAL("clicked()"),self.moveUpPushButton_clicked)
786         self.connect(self.moveDownPushButton,SIGNAL("clicked()"),self.moveDownPushButton_clicked)
787         self.connect(self.fabPushButton,SIGNAL("clicked()"),self.fabPushButton_clicked)
788
789         self.connect(self.recipientListView, SIGNAL("selectionChanged(QListViewItem*)"), self.recipientListView_selectionChanged)
790
791         self.addWidget(widget, "recipient_list", maximize=False)
792
793
794     def recipientListView_selectionChanged(self, i):
795         try:
796             self.prev_selected_recipient = i.name
797         except AttributeError:
798             pass
799         else:
800             rlv = self.recipientListView
801             selected_item = rlv.selectedItem()
802             recipient_count = rlv.childCount()
803             last_item = rlv.firstChild()
804             while last_item.nextSibling():
805                 last_item = last_item.nextSibling()
806
807             self.moveDownPushButton.setEnabled(recipient_count > 1 and selected_item is not last_item)
808             self.moveUpPushButton.setEnabled(recipient_count > 1 and selected_item is not rlv.firstChild())
809
810
811
812     def updateRecipientList(self):
813         self.recipientListView.clear()
814         temp = self.recipient_list[:]
815         temp.reverse()
816         last_item = None
817         selected_item = None
818         order = len(temp)
819
820         for name in temp:
821             entry = self.db.get(name)
822             # TODO: If entry was in list prior to name change in hp-fab,
823             # this code will remove it instead of following the name change
824             # Ref: CDP-1675
825             if entry is not None:
826                 i = RecipientListViewItem(self.recipientListView, str(order), name, entry['fax'], entry['notes'])
827
828                 if not self.prev_selected_recipient or self.prev_selected_recipient == name:
829                     self.recipientListView.setSelected(i, True)
830                     selected_item = i
831                     self.prev_selected_recipient = name
832
833                 order -= 1
834
835         last_item = self.recipientListView.firstChild()
836         while last_item is not None and last_item.nextSibling():
837             last_item = last_item.nextSibling()
838
839         child_count = self.recipientListView.childCount()
840         self.removeRecipientPushButton.setEnabled(child_count > 0)
841         self.moveDownPushButton.setEnabled(child_count > 1 and selected_item is not last_item)
842         self.moveUpPushButton.setEnabled(child_count > 1 and selected_item is not self.recipientListView.firstChild())
843
844         self.checkSendFaxButton()
845
846
847
848     def recipientListView_rightButtonClicked(self, item, pos, col):
849         self.ind_map = {}
850         self.grp_map = {}
851         popup = QPopupMenu(self)
852         ind = QPopupMenu(popup)
853         grp = QPopupMenu(popup)
854
855         all_entries = self.db.get_all_records()
856         if all_entries:
857             popup.insertItem(QIconSet(load_pixmap('add_user', '16x16')),
858                 self.__tr("Add Individual"), ind)
859
860             for e, v in all_entries.items():
861                 if not e.startswith('__'):
862                     self.ind_map[ind.insertItem(QIconSet(load_pixmap('add_user', '16x16')), e, None)] = e
863
864         all_groups = self.db.get_all_groups()
865         if all_groups:
866             popup.insertItem(QIconSet(load_pixmap('add_users', '16x16')),
867                 self.__tr("Add Group"), grp)
868
869             for g in all_groups:
870                 self.grp_map[grp.insertItem(QIconSet(load_pixmap('add_users', '16x16')),
871                     g, None)] = g
872
873         if item is not None:
874             popup.insertSeparator(-1)
875
876             popup.insertItem(QIconSet(load_pixmap('remove_user', '16x16')),
877                 self.__tr("Remove"), self.removeRecipientPushButton_clicked)
878
879             if self.recipientListView.childCount() > 1:
880                 last_item = self.recipientListView.firstChild()
881                 while last_item is not None and last_item.nextSibling():
882                     last_item = last_item.nextSibling()
883
884                 if item is not self.recipientListView.firstChild():
885                     popup.insertItem(QIconSet(load_pixmap('up_user', '16x16')),
886                         self.__tr("Move Up"), self.moveUpPushButton_clicked)
887
888                 if item is not last_item:
889                     popup.insertItem(QIconSet(load_pixmap('down_user', '16x16')),
890                         self.__tr("Move Down"), self.moveDownPushButton_clicked)
891
892         popup.insertSeparator(-1)
893         popup.insertItem(QIconSet(load_pixmap('fab', '16x16')),
894             self.__tr("Fax Address Book..."), self.fabPushButton_clicked)
895
896         self.connect(ind, SIGNAL("activated(int)"), self.ind_popup_activated)
897         self.connect(grp, SIGNAL("activated(int)"), self.grp_popup_activated)
898
899         popup.popup(pos)
900
901
902     def ind_popup_activated(self, i):
903         self.addRecipient(self.ind_map[i])
904
905     def grp_popup_activated(self, i):
906         self.addRecipient(self.grp_map[i], True)
907
908     def moveUpPushButton_clicked(self):
909         try:
910             name = self.recipientListView.selectedItem().name
911         except AttributeError:
912             return
913         else:
914             utils.list_move_up(self.recipient_list, name)
915             self.updateRecipientList()
916
917     def moveDownPushButton_clicked(self):
918         try:
919             name = self.recipientListView.selectedItem().name
920         except AttributeError:
921             return
922         else:
923             utils.list_move_down(self.recipient_list, name)
924             self.updateRecipientList()
925
926
927     def fabPushButton_clicked(self):
928         log.debug(self.cmd_fab)
929         #print self.cmd_fab
930         cmd = ''.join([self.cur_device.device_vars.get(x, x) \
931                          for x in self.cmd_fab.split('%')])
932         log.debug(cmd)
933
934         path = cmd.split()[0]
935         args = cmd.split()
936
937         self.CleanupChildren()
938         #os.spawnvp(os.P_NOWAIT, path, args)
939         os.system(cmd)
940
941         self.db.load()
942         self.updateRecipientList()
943         self.updateRecipientCombos()
944
945
946     def CleanupChildren(self):
947         log.debug("Cleaning up child processes.")
948         try:
949             os.waitpid(-1, os.WNOHANG)
950         except OSError:
951             pass
952
953
954     def removeRecipientPushButton_clicked(self):
955         try:
956             name = self.recipientListView.selectedItem().name
957         except AttributeError:
958             return
959         else:
960             temp = self.recipient_list[:]
961             index = 0
962             for n in temp:
963                 if name == n:
964                     del self.recipient_list[index]
965
966                     self.prev_selected_recipient = ''
967                     self.updateRecipientList()
968                     break
969
970                 index += 1
971
972
973
974     #
975     # ADD FROM ADDRESS BOOK
976     #
977
978     def addRecipientAddFromFAB(self):
979         widget = self.getWidget()
980
981         layout13 = QGridLayout(widget,1,1,5,10,"layout13")
982
983         self.groupComboBox = QComboBox(0,widget,"groupComboBox")
984         self.groupComboBox.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.Fixed,0,0,self.groupComboBox.sizePolicy().hasHeightForWidth()))
985
986         layout13.addWidget(self.groupComboBox,1,2)
987         spacer12 = QSpacerItem(20,20,QSizePolicy.Preferred,QSizePolicy.Minimum)
988         layout13.addItem(spacer12,1,1)
989
990         self.textLabel1 = QLabel(widget,"textLabel1")
991         self.textLabel1.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Preferred,0,0,self.textLabel1.sizePolicy().hasHeightForWidth()))
992
993         layout13.addWidget(self.textLabel1,0,0)
994
995         self.individualComboBox = QComboBox(0,widget,"individualComboBox")
996         self.individualComboBox.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.Fixed,0,0,self.individualComboBox.sizePolicy().hasHeightForWidth()))
997
998         layout13.addWidget(self.individualComboBox,0,2)
999
1000         self.textLabel2 = QLabel(widget,"textLabel2")
1001         self.textLabel2.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.Preferred,0,0,self.textLabel2.sizePolicy().hasHeightForWidth()))
1002
1003         layout13.addWidget(self.textLabel2,1,0)
1004         spacer11 = QSpacerItem(30,20,QSizePolicy.Preferred,QSizePolicy.Minimum)
1005         layout13.addItem(spacer11,0,1)
1006
1007         self.addGroupPushButton = PixmapLabelButton(widget,
1008                     "add_users.png", "add_users.png", name='addGroupPushButton')
1009
1010         layout13.addWidget(self.addGroupPushButton,1,3)
1011
1012         self.addIndividualPushButton = PixmapLabelButton(widget,
1013                     "add_user.png", "add_user.png", name='addIndividualPushButton')
1014
1015
1016         layout13.addWidget(self.addIndividualPushButton,0,3)
1017
1018         self.textLabel1.setText(self.__tr("Add an <b>individual </b>from the fax address book:"))
1019         self.textLabel2.setText(self.__tr("Add a <b>group</b> from the fax address book:"))
1020         self.addGroupPushButton.setText(self.__tr("Add"))
1021         self.addIndividualPushButton.setText(self.__tr("Add"))
1022
1023         self.connect(self.addIndividualPushButton,SIGNAL("clicked()"),self.addIndividualPushButton_clicked)
1024         self.connect(self.addGroupPushButton,SIGNAL("clicked()"),self.addGroupPushButton_clicked)
1025
1026
1027         self.addWidget(widget, "recipient_add_from_fab")
1028
1029     def addIndividualPushButton_clicked(self):
1030         self.addRecipient(unicode(self.individualComboBox.currentText()))
1031
1032     def addGroupPushButton_clicked(self):
1033         self.addRecipient(unicode(self.groupComboBox.currentText()), True)
1034
1035     def addRecipient(self, name, is_group=False):
1036         if is_group:
1037             for i in self.db.group_members(name):
1038             #for i in self.db.GroupEntries(name):
1039                 if not i.startswith('__'):
1040                     self.recipient_list.append(i)
1041                     self.prev_selected_recipient = self.recipient_list[-1]
1042         else:
1043             self.recipient_list.append(name)
1044             self.prev_selected_recipient = name
1045
1046         self.updateRecipientList()
1047
1048     def updateRecipientCombos(self):
1049         # Individuals
1050         self.individualComboBox.clear()
1051         all_entries = self.db.get_all_records()
1052         self.addIndividualPushButton.setEnabled(len(all_entries))
1053
1054         for e, v in all_entries.items():
1055             if not e.startswith('__'):
1056                 self.individualComboBox.insertItem(e)
1057
1058         # Groups
1059         self.groupComboBox.clear()
1060         all_groups = self.db.get_all_groups()
1061         self.addGroupPushButton.setEnabled(len(all_groups))
1062
1063         for g in all_groups:
1064             self.groupComboBox.insertItem(g)
1065
1066
1067     #
1068     # QUICK ADD
1069     #
1070
1071     def addRecipientQuickAdd(self):
1072         widget = self.getWidget()
1073
1074         layout12 = QGridLayout(widget,1,1,5,10,"layout12")
1075         self.quickAddFaxLineEdit = QLineEdit(widget,"quickAddFaxLineEdit")
1076
1077         self.quickAddFaxLineEdit.setValidator(PhoneNumValidator(self.quickAddFaxLineEdit))
1078         layout12.addWidget(self.quickAddFaxLineEdit,0,3)
1079
1080         self.quickAddNameLineEdit = QLineEdit(widget,"quickAddNameLineEdit")
1081         layout12.addWidget(self.quickAddNameLineEdit,0,1)
1082
1083         self.textLabel4 = QLabel(widget,"textLabel4")
1084         layout12.addWidget(self.textLabel4,0,0)
1085
1086         self.quickAddPushButton = PixmapLabelButton(widget,
1087                     "add_user_quick.png", "add_user_quick.png", name='quickAddPushButton')
1088
1089         layout12.addWidget(self.quickAddPushButton,0,4)
1090
1091         self.textLabel5 = QLabel(widget,"textLabel5")
1092         layout12.addWidget(self.textLabel5,0,2)
1093
1094         self.textLabel4.setText(self.__tr("Name:"))
1095         self.quickAddPushButton.setText(self.__tr("Add"))
1096         self.textLabel5.setText(self.__tr("Fax Number:"))
1097
1098         self.quickAddPushButton.setEnabled(False)
1099
1100         self.connect(self.quickAddPushButton,SIGNAL("clicked()"),self.quickAddPushButton_clicked)
1101         self.connect(self.quickAddNameLineEdit,SIGNAL("textChanged(const QString&)"),self.quickAddNameLineEdit_textChanged)
1102         self.connect(self.quickAddFaxLineEdit,SIGNAL("textChanged(const QString&)"),self.quickAddFaxLineEdit_textChanged)
1103
1104         self.addWidget(widget, "recipient_quick_add")
1105
1106
1107     def quickAddPushButton_clicked(self):
1108         name =  unicode(self.quickAddNameLineEdit.text())
1109         self.db.set(name, u'', u'', u'', unicode(self.quickAddFaxLineEdit.text()), [], self.__tr('Added with Quick Add'))
1110         self.db.save()
1111         self.addRecipient(name)
1112
1113         self.quickAddNameLineEdit.setText("")
1114         self.quickAddFaxLineEdit.setText("")
1115
1116
1117     def enableQuickAddButton(self, name=None, fax=None):
1118         if name is None:
1119             name = unicode(self.quickAddNameLineEdit.text())
1120         if fax is None:
1121             fax = unicode(self.quickAddFaxLineEdit.text())
1122
1123         existing_name = False
1124         if name:
1125             existing_name = name in self.db.get_all_names()
1126
1127         if existing_name:
1128             try:
1129                 self.quickAddNameLineEdit.setPaletteBackgroundColor(QColor("yellow"))
1130             except AttributeError:
1131                 pass
1132         else:
1133             try:
1134                 self.quickAddNameLineEdit.setPaletteBackgroundColor(QColor("white"))
1135             except AttributeError:
1136                 pass
1137
1138         if name and not existing_name and fax:
1139             self.quickAddPushButton.setEnabled(True)
1140         else:
1141             self.quickAddPushButton.setEnabled(False)
1142
1143
1144     def quickAddNameLineEdit_textChanged(self, name):
1145         self.enableQuickAddButton(unicode(name))
1146
1147
1148     def quickAddFaxLineEdit_textChanged(self, fax):
1149         self.enableQuickAddButton(None, unicode(fax))
1150
1151
1152     def checkSendFaxButton(self):
1153         self.faxButton.setEnabled(len(self.file_list) and len(self.recipient_list))
1154
1155     def faxButton_clicked(self):
1156         self.check_timer.stop()
1157         phone_num_list = []
1158
1159         log.debug("Current printer=%s" % self.cur_printer)
1160         ppd_file = cups.getPPD(self.cur_printer)
1161
1162         if ppd_file is not None and os.path.exists(ppd_file):
1163             if file(ppd_file, 'r').read().find('HP Fax') == -1:
1164                 self.form.FailureUI(self.__tr("<b>Fax configuration error.</b><p>The CUPS fax queue for '%1' is incorrectly configured.<p>Please make sure that the CUPS fax queue is configured with the 'HPLIP Fax' Model/Driver.").arg(self.cur_printer))
1165                 return
1166
1167         QApplication.setOverrideCursor(QApplication.waitCursor)
1168
1169         self.dev = fax.getFaxDevice(self.cur_device.device_uri,
1170                                    self.cur_printer, None,
1171                                    self.cur_device.mq['fax-type'])
1172
1173         try:
1174             try:
1175                 self.dev.open()
1176             except Error, e:
1177                 log.warn(e.msg)
1178
1179             try:
1180                 self.dev.queryDevice(quick=True)
1181             except Error, e:
1182                 log.error("Query device error (%s)." % e.msg)
1183                 self.dev.error_state = ERROR_STATE_ERROR
1184
1185         finally:
1186             self.dev.close()
1187             QApplication.restoreOverrideCursor()
1188
1189         if self.dev.error_state > ERROR_STATE_MAX_OK and \
1190             self.dev.error_state not in (ERROR_STATE_LOW_SUPPLIES, ERROR_STATE_LOW_PAPER):
1191
1192             self.form.FailureUI(self.__tr("<b>Device is busy or in an error state (code=%1)</b><p>Please wait for the device to become idle or clear the error and try again.").arg(self.cur_device.status_code))
1193             return
1194
1195         # Check to make sure queue in CUPS is idle
1196         self.cups_printers = cups.getPrinters()
1197         for p in self.cups_printers:
1198             if p.name == self.cur_printer:
1199                 if p.state == cups.IPP_PRINTER_STATE_STOPPED:
1200                     self.form.FailureUI(self.__tr("<b>The CUPS queue for '%1' is in a stopped or busy state.</b><p>Please check the queue and try again.").arg(self.cur_printer))
1201                     return
1202                 break
1203
1204         log.debug("Recipient list:")
1205
1206         for p in self.recipient_list:
1207             entry = self.db.get(p)
1208             phone_num_list.append(entry)
1209             log.debug("Name=%s Number=%s" % (entry["name"], entry["fax"]))
1210
1211         log.debug("File list:")
1212
1213
1214         for f in self.file_list:
1215             log.debug(unicode(f))
1216
1217         self.busy = True
1218
1219         self.dev.sendEvent(EVENT_START_FAX_JOB, self.cur_printer, 0, '')
1220
1221         if not self.dev.sendFaxes(phone_num_list, self.file_list, self.cover_page_message,
1222                                   self.cover_page_re, self.cover_page_func, self.preserve_formatting,
1223                                   self.cur_printer, self.update_queue, self.event_queue):
1224
1225             self.form.FailureUI(self.__tr("<b>Send fax is active.</b><p>Please wait for operation to complete."))
1226             self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.cur_printer, 0, '')
1227             self.busy = False
1228             return
1229
1230
1231         self.waitdlg = WaitForm(0, self.__tr("Initializing..."), self.send_fax_canceled, self, modal=1)
1232         self.waitdlg.show()
1233
1234         self.send_fax_timer = QTimer(self, "SendFaxTimer")
1235         self.connect(self.send_fax_timer, SIGNAL('timeout()'), self.send_fax_timer_timeout)
1236         self.send_fax_timer.start(1000) # 1 sec UI updates
1237
1238     def send_fax_canceled(self):
1239         self.event_queue.put((fax.EVENT_FAX_SEND_CANCELED, '', '', ''))
1240         self.dev.sendEvent(EVENT_FAX_JOB_CANCELED, self.cur_printer, 0, '')
1241
1242     def send_fax_timer_timeout(self):
1243         while self.update_queue.qsize():
1244             try:
1245                 status, page_num, arg = self.update_queue.get(0)
1246             except Queue.Empty:
1247                 break
1248
1249             if status == fax.STATUS_IDLE:
1250                 self.busy = False
1251                 self.send_fax_timer.stop()
1252
1253                 if self.waitdlg is not None:
1254                     self.waitdlg.hide()
1255                     self.waitdlg.close()
1256                     self.waitdlg = None
1257
1258             elif status == fax.STATUS_PROCESSING_FILES:
1259                 self.waitdlg.setMessage(self.__tr("Processing page %1...").arg(page_num))
1260
1261             elif status == fax.STATUS_SENDING_TO_RECIPIENT:
1262                 self.waitdlg.setMessage(self.__tr("Sending fax to %1...").arg(arg))
1263
1264             elif status == fax.STATUS_DIALING:
1265                 self.waitdlg.setMessage(self.__tr("Dialing %1...").arg(arg))
1266
1267             elif status == fax.STATUS_CONNECTING:
1268                 self.waitdlg.setMessage(self.__tr("Connecting to %1...").arg(arg))
1269
1270             elif status == fax.STATUS_SENDING:
1271                 self.waitdlg.setMessage(self.__tr("Sending page %1 to %2...").arg(page_num).arg(arg))
1272
1273             elif status == fax.STATUS_CLEANUP:
1274                 self.waitdlg.setMessage(self.__tr("Cleaning up..."))
1275
1276             elif status in (fax.STATUS_ERROR, fax.STATUS_BUSY, fax.STATUS_COMPLETED):
1277                 self.busy = False
1278                 self.send_fax_timer.stop()
1279
1280                 if self.waitdlg is not None:
1281                     self.waitdlg.hide()
1282                     self.waitdlg.close()
1283                     self.waitdlg = None
1284
1285                 if status == fax.STATUS_ERROR:
1286                     result_code, error_state = self.dev.getPML(pml.OID_FAX_DOWNLOAD_ERROR)
1287                     if error_state == pml.DN_ERROR_NONE:
1288                         self.form.FailureUI(self.__tr("<b>Fax send error (Possible cause: No answer or dialtone)"))
1289                     else:
1290                         self.form.FailureUI(self.__tr("<b>Fax send error (%s).</b><p>" % pml.DN_ERROR_STR.get(error_state, "Unknown error")))
1291                     self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.cur_printer, 0, '')
1292
1293                 elif status == fax.STATUS_BUSY:
1294                     self.form.FailureUI(self.__tr("<b>Fax device is busy.</b><p>Please try again later."))
1295                     self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.cur_printer, 0, '')
1296
1297                 elif status == fax.STATUS_COMPLETED:
1298                     self.dev.sendEvent(EVENT_END_FAX_JOB, self.cur_printer, 0, '')
1299
1300                     self.funcButton_clicked()
1301
1302
1303     def cleanup(self):
1304         self.unlock()
1305
1306         if fax_enabled:
1307             self.check_timer.stop()
1308
1309     def funcButton_clicked(self):
1310         self.cleanup()
1311         self.form.close()
1312
1313     def __tr(self,s,c = None):
1314         return qApp.translate("ScrollFaxView",s,c)