1 # -*- coding: utf-8 -*-
3 # (c) Copyright 2001-2009 Hewlett-Packard Development Company, L.P.
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.
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.
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
29 from base import device, utils, pml
31 from base.codes import *
32 from ui_utils import *
35 from PyQt4.QtCore import *
36 from PyQt4.QtGui import *
39 from sendfaxdialog_base import Ui_Dialog
40 from filetable import FileTable, FILETABLE_TYPE_FAX
41 from printernamecombobox import PrinterNameComboBox, PRINTERNAMECOMBOBOX_TYPE_FAX_ONLY
42 from printsettingsdialog import PrintSettingsDialog
43 from faxsetupdialog import FaxSetupDialog
53 STATUS_INFORMATION = 0
57 MIME_TYPE_COVERPAGE = "application/hplip-fax-coverpage"
59 fax_enabled = prop.fax_build
65 # This can fail on Python < 2.3 due to the datetime module
66 # or if fax was diabled during the build
70 log.warn("Fax disabled.")
72 coverpages_enabled = False
76 ver = reportlab.Version
83 coverpages_enabled = True
85 log.warn("Pre-2.0 version of Reportlab installed. Fax coverpages disabled.")
88 log.warn("Reportlab not installed. Fax coverpages disabled.")
90 if not coverpages_enabled:
91 log.warn("Please install version 2.0+ of Reportlab for coverpage support.")
94 from fabwindow import FABWindow
96 if coverpages_enabled:
97 from fax import coverpages
100 class SendFaxDialog(QDialog, Ui_Dialog):
101 def __init__(self, parent, printer_name, device_uri=None, args=None):
102 QDialog.__init__(self, parent)
105 self.printer_name = printer_name
106 if device_uri is not None:
107 self.device_uri = device_uri
109 self.device_uri = device.getDeviceURIByPrinterName(self.printer_name)
114 self.dbus_avail, self.service, session_bus = device.init_dbus()
116 self.CheckTimer = None
117 self.lock_file = None
119 self.recipient_list = []
123 if self.printer_name:
124 if coverpages_enabled:
125 QTimer.singleShot(0, self.displayCoverpagePage)
128 QTimer.singleShot(0, self.displayFilesPage)
130 QTimer.singleShot(0, self.displaySelectFaxPage)
134 # connect signals/slots
135 self.connect(self.CancelButton, SIGNAL("clicked()"), self.CancelButton_clicked)
136 self.connect(self.BackButton, SIGNAL("clicked()"), self.BackButton_clicked)
137 self.connect(self.NextButton, SIGNAL("clicked()"), self.NextButton_clicked)
139 self.initSelectFaxPage()
140 self.initCoverpagePage()
142 self.initRecipientsPage()
143 self.initSendFaxPage()
146 self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128')))
149 def lockAndLoad(self):
150 # Start up check timer here, since the fax name is now known
151 if self.CheckTimer is None:
152 self.CheckTimer = QTimer(self)
153 self.connect(self.CheckTimer, SIGNAL("timeout()"), self.CheckTimer_timeout)
154 self.CheckTimer.start(3000)
157 if self.printer_name and self.lock_file is None:
158 ok, self.lock_file = utils.lock_app('hp-sendfax-%s' % self.printer_name, True)
161 log.error("hp-sendfax is already running for fax %s" % self.printer_name)
168 def initSelectFaxPage(self):
169 self.FaxComboBox.setType(PRINTERNAMECOMBOBOX_TYPE_FAX_ONLY)
170 self.connect(self.FaxComboBox, SIGNAL("PrinterNameComboBox_currentChanged"), self.FaxComboBox_currentChanged)
171 self.connect(self.FaxComboBox, SIGNAL("PrinterNameComboBox_noPrinters"), self.FaxComboBox_noPrinters)
172 self.connect(self.FaxOptionsButton, SIGNAL("clicked()"), self.FaxOptionsButton_clicked)
173 self.connect(self.FaxSetupButton, SIGNAL("clicked()"), self.FaxSetupButton_clicked)
175 if self.printer_name is not None:
176 self.FaxComboBox.setInitialPrinter(self.printer_name)
179 def displaySelectFaxPage(self):
180 self.BackButton.setEnabled(False)
181 self.updateStepText(PAGE_SELECT_FAX)
184 FailureUI(self, self.__tr("<b>PC send fax support is not enabled.</b><p>Re-install HPLIP with fax support or use the device front panel to send a fax.</p><p>Click <i>OK</i> to exit.</p>"))
188 if not self.dbus_avail:
189 FailureUI(self, self.__tr("<b>PC send fax support requires DBus and hp-systray.</b><p>Please check the HPLIP installation for proper installation of DBus and hp-systray support.</p><p>Click <i>OK</i> to exit.</p>"))
193 self.FaxComboBox.updateUi()
194 self.displayPage(PAGE_SELECT_FAX)
197 def FaxComboBox_currentChanged(self, device_uri, printer_name):
198 self.printer_name = printer_name
199 self.device_uri = device_uri
202 def FaxComboBox_noPrinters(self):
204 .__tr("<b>No installed fax devices found.</b><p>Please setup a fax device and try again (try using 'hp-setup').</p><p>Click <i>OK</i> to exit.</p>"))
208 def FaxOptionsButton_clicked(self):
209 dlg = PrintSettingsDialog(self, self.printer_name, fax_mode=True)
213 def FaxSetupButton_clicked(self):
214 dlg = FaxSetupDialog(self, self.device_uri)
221 def initCoverpagePage(self):
222 self.cover_page_message = ''
223 self.cover_page_re = ''
224 self.preserve_formatting = False
225 self.cover_page_func, cover_page_png = None, None
228 self.PrevCoverPageButton.setIcon(QIcon(load_pixmap("prev", "16x16")))
229 self.NextCoverPageButton.setIcon(QIcon(load_pixmap("next", "16x16")))
231 if coverpages_enabled:
232 self.cover_page_list = coverpages.COVERPAGES.keys()
233 self.cover_page_index = self.cover_page_list.index("basic")
234 self.cover_page_max = len(self.cover_page_list)-1
235 self.cover_page_name = self.cover_page_list[self.cover_page_index]
237 self.connect(self.PrevCoverPageButton, SIGNAL("clicked()"), self.PrevCoverPageButton_clicked)
238 self.connect(self.NextCoverPageButton, SIGNAL("clicked()"), self.NextCoverPageButton_clicked)
239 self.connect(self.CoverPageGroupBox, SIGNAL("toggled(bool)"), self.CoverPageGroupBox_toggled)
240 self.connect(self.MessageEdit, SIGNAL("textChanged()"), self.MessageEdit_textChanged)
241 self.connect(self.RegardingEdit, SIGNAL("textChanged(const QString &)"), self.RegardingEdit_textChanged)
242 self.connect(self.PreserveFormattingCheckBox, SIGNAL("toggled(bool)"),
243 self.PreserveFormattingCheckBox_toggled)
245 self.CoverPageGroupBox.setEnabled(False)
248 def displayCoverpagePage(self):
249 self.BackButton.setEnabled(False) # No going back once printer is chosen
250 self.NextButton.setEnabled(True)
254 self.updateCoverpageButtons()
255 self.displayCoverpagePreview()
256 self.displayPage(PAGE_COVERPAGE)
259 def MessageEdit_textChanged(self):
260 self.cover_page_message = unicode(self.MessageEdit.toPlainText())
263 def RegardingEdit_textChanged(self, t):
264 self.cover_page_re = unicode(t)
267 def PreserveFormattingCheckBox_toggled(self, b):
268 self.preserve_formatting = b
271 def PrevCoverPageButton_clicked(self):
272 self.cover_page_index -= 1
273 if self.cover_page_index < 0:
274 self.cover_page_index = 0
276 self.updateCoverpageButtons()
277 self.displayCoverpagePage()
280 def NextCoverPageButton_clicked(self):
281 self.cover_page_index += 1
282 if self.cover_page_index > self.cover_page_max:
283 self.cover_page_index = self.cover_page_max
285 self.updateCoverpageButtons()
286 self.displayCoverpagePage()
289 def displayCoverpagePreview(self):
290 self.cover_page_name = self.cover_page_list[self.cover_page_index]
291 self.cover_page_func = coverpages.COVERPAGES[self.cover_page_name][0]
292 self.CoverPageName.setText(QString('<i>"%1"</i>').arg(self.cover_page_name))
293 self.CoverPagePreview.setPixmap(load_pixmap(coverpages.COVERPAGES[self.cover_page_name][1], 'other'))
295 if self.CoverPageGroupBox.isChecked():
298 self.removeCoverPage()
301 def updateCoverpageButtons(self):
302 enabled = self.CoverPageGroupBox.isChecked()
303 self.PrevCoverPageButton.setEnabled(enabled and self.cover_page_index != 0)
304 self.NextCoverPageButton.setEnabled(enabled and self.cover_page_index != self.cover_page_max)
307 def CoverPageGroupBox_toggled(self, b):
308 self.updateCoverpageButtons()
312 self.removeCoverPage()
315 def addCoverPage(self):
316 self.removeCoverPage()
317 self.FilesTable.addFile(self.cover_page_name, MIME_TYPE_COVERPAGE,
318 self.__tr('HP Fax Coverpage: "%1"').arg(self.cover_page_name),
319 self.__tr("Cover Page"), 1)
322 def removeCoverPage(self):
323 self.FilesTable.removeFileByMIMEType(MIME_TYPE_COVERPAGE)
326 def toggleCoverPage(self, b):
327 self.disconnect(self.CoverPageGroupBox, SIGNAL("toggled(bool)"), self.CoverPageGroupBox_toggled)
328 self.CoverPageGroupBox.setChecked(b)
329 self.connect(self.CoverPageGroupBox, SIGNAL("toggled(bool)"), self.CoverPageGroupBox_toggled)
336 def initFilesPage(self):
337 self.FilesTable.setType(FILETABLE_TYPE_FAX)
338 self.FilesTable.setFaxCallback(self.FileTable_callback)
339 self.connect(self.FilesTable, SIGNAL("isEmpty"), self.FilesTable_isEmpty)
340 self.connect(self.FilesTable, SIGNAL("isNotEmpty"), self.FilesTable_isNotEmpty)
341 self.connect(self.FilesTable, SIGNAL("fileListChanged"), self.FilesTable_fileListChanged)
344 def displayFilesPage(self):
345 self.FilesTable.updateUi(False)
347 if self.args is not None:
349 f = os.path.abspath(os.path.expanduser(a))
350 if os.path.exists(f) and os.access(f, os.R_OK):
355 self.restoreNextButton()
356 self.NextButton.setEnabled(self.FilesTable.isNotEmpty())
357 self.BackButton.setEnabled(coverpages_enabled)
358 self.FilesPageNote.setText(self.__tr("Note: You may also add files to the fax by printing from any application to the '%1' fax printer.").arg(self.printer_name))
359 self.displayPage(PAGE_FILES)
362 def FilesTable_isEmpty(self):
363 if self.StackedWidget.currentIndex() == PAGE_FILES:
364 self.NextButton.setEnabled(False)
367 def FilesTable_isNotEmpty(self):
368 if self.StackedWidget.currentIndex() == PAGE_FILES:
369 self.NextButton.setEnabled(True)
372 def FilesTable_fileListChanged(self):
373 self.file_list = self.FilesTable.file_list
374 self.toggleCoverPage(self.FilesTable.isMIMETypeInList(MIME_TYPE_COVERPAGE))
381 def initRecipientsPage(self):
383 self.QuickAddFaxEdit.setValidator(PhoneNumValidator(self.QuickAddFaxEdit))
385 # Fax address book database
386 self.db = fax.FaxAddressBook()
388 # Fax address book window
389 self.fab = FABWindow(self)
390 self.fab.setWindowFlags(Qt.Tool) # Keeps the Fab window on top
392 self.connect(self.fab, SIGNAL("databaseChanged"), self.FABWindow_databaseChanged)
395 self.connect(self.QuickAddFaxEdit, SIGNAL("textChanged(const QString &)"),
396 self.QuickAddFaxEdit_textChanged)
397 self.connect(self.QuickAddNameEdit, SIGNAL("textChanged(const QString &)"),
398 self.QuickAddNameEdit_textChanged)
399 self.connect(self.QuickAddButton, SIGNAL("clicked()"), self.QuickAddButton_clicked)
400 self.connect(self.FABButton, SIGNAL("clicked()"), self.FABButton_clicked)
401 self.connect(self.AddIndividualButton, SIGNAL("clicked()"), self.AddIndividualButton_clicked)
402 self.connect(self.AddGroupButton, SIGNAL("clicked()"), self.AddGroupButton_clicked)
403 self.connect(self.RemoveRecipientButton, SIGNAL("clicked()"), self.RemoveRecipientButton_clicked)
404 self.connect(self.MoveRecipientUpButton, SIGNAL("clicked()"), self.MoveRecipientUpButton_clicked)
405 self.connect(self.MoveRecipientDownButton, SIGNAL("clicked()"), self.MoveRecipientDownButton_clicked)
406 self.connect(self.RecipientsTable, SIGNAL("itemSelectionChanged()"),
407 self.RecipientsTable_itemSelectionChanged)
408 self.connect(self.RecipientsTable, SIGNAL("itemDoubleClicked(QTableWidgetItem *)"),
409 self.RecipientsTable_itemDoubleClicked)
412 self.FABButton.setIcon(QIcon(load_pixmap("fab", "16x16")))
413 self.AddIndividualButton.setIcon(QIcon(load_pixmap("add_user", "16x16")))
414 self.AddGroupButton.setIcon(QIcon(load_pixmap("add_users", "16x16")))
415 self.RemoveRecipientButton.setIcon(QIcon(load_pixmap("remove_user", "16x16")))
416 self.MoveRecipientUpButton.setIcon(QIcon(load_pixmap("up_user", "16x16")))
417 self.MoveRecipientDownButton.setIcon(QIcon(load_pixmap("down_user", "16x16")))
418 self.QuickAddButton.setIcon(QIcon(load_pixmap("add_user_quick", "16x16")))
420 # setup initial state
421 self.QuickAddButton.setEnabled(False)
423 self.recipient_headers = [self.__tr("Name"), self.__tr("Fax number"), self.__tr("Notes")]
426 def FABWindow_databaseChanged(self, action, s1='', s2=''):
429 if action in (FAB_NAME_ADD, FAB_GROUP_ADD, FAB_GROUP_RENAME,
430 FAB_GROUP_REMOVE, FAB_GROUP_MEMBERSHIP_CHANGED):
432 log.debug("Fax address book has changed")
433 self.updateAddressBook()
435 elif action == FAB_NAME_REMOVE:
436 log.debug("Fax address book has changed: '%s' removed" % s1)
437 all_names = self.db.get_all_names()
438 self.recipient_list = filter(lambda x: x in self.recipient_list, all_names)
439 self.updateAddressBook()
440 self.updateRecipientTable()
442 elif action == FAB_NAME_RENAME:
443 log.debug("Fax address book has changed: '%s' renamed to '%s'" % (s1, s2))
444 for i, n in enumerate(self.recipient_list):
446 self.recipient_list[i] = s2
447 self.updateRecipientTable()
450 self.updateAddressBook()
452 elif action == FAB_NAME_DETAILS_CHANGED:
453 log.debug("Fax address book has changed: '%s' details changed" % s1)
454 self.updateRecipientTable()
457 def displayRecipientsPage(self):
458 self.updateAddressBook()
459 self.updateRecipientTable()
460 self.enableQuickAddButton()
461 self.displayPage(PAGE_RECIPIENTS)
462 self.restoreNextButton()
463 self.BackButton.setEnabled(True)
466 def updateAddressBook(self):
467 names = [n for n in self.db.get_all_names() if not n.startswith('__')]
468 groups = self.db.get_all_groups()
469 self.AddIndividualComboBox.clear()
470 self.AddGroupComboBox.clear()
475 if n not in self.recipient_list:
476 data = self.db.get(n)
478 self.AddIndividualComboBox.addItem(n)
482 self.AddIndividualButton.setEnabled(True)
483 self.AddIndividualComboBox.setEnabled(True)
484 #self.AddIndividualButton.setIcon(QIcon(load_pixmap("add_user", "16x16")))
487 self.AddIndividualButton.setEnabled(False)
488 self.AddIndividualComboBox.setEnabled(False)
489 #self.AddIndividualButton.setIcon(QIcon(load_pixmap("add_user-disabled", "16x16")))
494 for n in self.db.group_members(g):
495 if not n.startswith('__') and n not in self.recipient_list:
496 self.AddGroupComboBox.addItem(g)
501 self.AddGroupButton.setEnabled(True)
502 self.AddGroupComboBox.setEnabled(True)
503 #self.AddGroupButton.setIcon(QIcon(load_pixmap("add_users", "16x16")))
506 self.AddGroupButton.setEnabled(False)
507 self.AddGroupComboBox.setEnabled(False)
508 #self.AddGroupButton.setIcon(QIcon(load_pixmap("add_users-disabled", "16x16")))
511 def updateRecipientTable(self):
513 prev = self.getCurrentRecipient()
514 except (TypeError, AttributeError):
517 self.RecipientsTable.clear()
518 self.RecipientsTable.setRowCount(0)
519 self.RecipientsTable.setColumnCount(0)
521 if self.recipient_list:
522 num_recipients = len(self.recipient_list)
524 self.RecipientsTable.setColumnCount(len(self.recipient_headers))
525 self.RecipientsTable.setHorizontalHeaderLabels(self.recipient_headers)
526 self.RecipientsTable.setRowCount(num_recipients)
527 flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
530 for row, n in enumerate(self.recipient_list):
531 i = QTableWidgetItem(QString(n))
533 self.RecipientsTable.setItem(row, 0, i)
534 if prev is not None and n == prev:
541 i = QTableWidgetItem(QString(k['fax']))
543 self.RecipientsTable.setItem(row, 1, i)
545 i = QTableWidgetItem(QString(k['notes']))
547 self.RecipientsTable.setItem(row, 2, i)
549 self.RecipientsTable.resizeColumnsToContents()
550 self.RecipientsTable.resizeRowsToContents()
553 self.RecipientsTable.setCurrentItem(j)
555 self.RecipientsTable.setCurrentItem(self.RecipientsTable.item(0, 0))
557 self.NextButton.setEnabled(True)
560 self.enableRecipientListButtons()
561 self.NextButton.setEnabled(False)
564 def RecipientsTable_itemSelectionChanged(self):
565 current_row = self.RecipientsTable.currentRow()
566 num_recipients = len(self.recipient_list)
567 self.enableRecipientListButtons(num_recipients > 0, # remove
568 num_recipients > 1 and current_row > 0, # up
569 num_recipients > 1 and current_row < (num_recipients-1)) # down
572 def enableRecipientListButtons(self, enable_remove=False, enable_up_move=False, enable_down_move=False):
574 self.RemoveRecipientButton.setEnabled(True)
576 self.RemoveRecipientButton.setEnabled(False)
579 self.MoveRecipientUpButton.setEnabled(True)
581 self.MoveRecipientUpButton.setEnabled(False)
584 self.MoveRecipientDownButton.setEnabled(True)
586 self.MoveRecipientDownButton.setEnabled(False)
589 def QuickAddFaxEdit_textChanged(self, fax):
590 self.enableQuickAddButton(None, unicode(fax))
593 def QuickAddNameEdit_textChanged(self, name):
594 self.enableQuickAddButton(unicode(name))
597 def enableQuickAddButton(self, name=None, fax=None):
599 name = unicode(self.QuickAddNameEdit.text())
601 fax = unicode(self.QuickAddFaxEdit.text())
603 existing_name = False
605 existing_name = name in self.db.get_all_names()
609 self.QuickAddNameEdit.setStyleSheet("background-color: yellow")
610 except AttributeError:
614 self.QuickAddNameEdit.setStyleSheet("")
615 except AttributeError:
618 if name and not existing_name and fax:
619 self.QuickAddButton.setEnabled(True)
621 self.QuickAddButton.setEnabled(False)
624 def QuickAddButton_clicked(self):
625 name = unicode(self.QuickAddNameEdit.text())
626 fax = unicode(self.QuickAddFaxEdit.text())
627 self.fab.addName(name, fax)
628 self.addRecipient(name)
629 self.updateRecipientTable()
630 self.QuickAddNameEdit.clear()
631 self.QuickAddFaxEdit.clear()
632 self.enableQuickAddButton('', '')
635 def AddIndividualButton_clicked(self):
636 self.addRecipient(unicode(self.AddIndividualComboBox.currentText()))
639 def AddGroupButton_clicked(self):
640 self.addGroup(unicode(self.AddGroupComboBox.currentText()))
643 def RemoveRecipientButton_clicked(self):
644 name = self.getCurrentRecipient()
645 temp = self.recipient_list[:]
646 for i, n in enumerate(temp):
648 del self.recipient_list[i]
649 self.updateRecipientTable()
650 self.updateAddressBook()
654 def MoveRecipientUpButton_clicked(self):
655 utils.list_move_up(self.recipient_list, self.getCurrentRecipient())
656 self.updateRecipientTable()
659 def MoveRecipientDownButton_clicked(self):
660 utils.list_move_down(self.recipient_list, self.getCurrentRecipient())
661 self.updateRecipientTable()
664 def getCurrentRecipient(self):
665 item = self.RecipientsTable.item(self.RecipientsTable.currentRow(), 0)
667 return unicode(item.text())
672 def addRecipient(self, name, update=True):
673 if name not in self.recipient_list and not name.startswith('__'):
674 self.recipient_list.append(name)
676 self.updateRecipientTable()
677 self.updateAddressBook()
680 def addGroup(self, group):
681 for n in self.db.group_members(group):
682 self.addRecipient(n, False)
684 self.updateRecipientTable()
685 self.updateAddressBook()
688 def FABButton_clicked(self):
692 def RecipientsTable_itemDoubleClicked(self, item):
694 row, col = item.row(), item.column()
696 item = self.RecipientsTable.item(row, 0)
698 self.fab.selectByName(unicode(item.text()))
706 def initSendFaxPage(self):
707 self.info_icon = QIcon(load_pixmap("info", "16x16"))
708 self.warn_icon = QIcon(load_pixmap("warning", "16x16"))
709 self.error_icon = QIcon(load_pixmap("error", "16x16"))
710 self.busy_icon = QIcon(load_pixmap("busy", "16x16"))
711 self.update_queue = Queue.Queue() # UI updates from send thread
712 self.event_queue = Queue.Queue() # UI events (cancel) to send thread
713 self.send_fax_active = False
716 def displaySendFaxPage(self):
717 self.displayPage(PAGE_SEND_FAX)
718 self.addStatusMessage(self.__tr("Ready to send fax."), self.info_icon)
719 self.NextButton.setText(self.__tr("Send Fax"))
727 def executeSendFax(self):
728 self.NextButton.setEnabled(False)
729 self.BackButton.setEnabled(False)
730 self.CheckTimer.stop()
734 ppd_file = cups.getPPD(self.printer_name)
736 if ppd_file is not None and os.path.exists(ppd_file):
737 if file(ppd_file, 'r').read().find('HP Fax') == -1:
738 FailureUI(self, 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.printer_name))
744 mq = device.queryModelByURI(self.device_uri)
746 self.dev = fax.getFaxDevice(self.device_uri,
747 self.printer_name, None,
757 self.dev.queryDevice(quick=True)
759 log.error("Query device error (%s)." % e.msg)
760 self.dev.error_state = ERROR_STATE_ERROR
766 if self.dev.error_state > ERROR_STATE_MAX_OK and \
767 self.dev.error_state not in (ERROR_STATE_LOW_SUPPLIES, ERROR_STATE_LOW_PAPER):
769 FailureUI(self, 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.dev.status_code))
770 self.NextButton.setEnabled(True)
773 # Check to make sure queue in CUPS is idle
774 self.cups_printers = cups.getPrinters()
775 for p in self.cups_printers:
776 if p.name == self.printer_name:
777 if p.state == cups.IPP_PRINTER_STATE_STOPPED:
778 FailureUI(self, 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.printer_name))
779 self.NextButton.setEnabled(False)
783 log.debug("Recipient list:")
785 for p in self.recipient_list:
786 entry = self.db.get(p)
787 phone_num_list.append(entry)
788 log.debug("Name=%s Number=%s" % (entry["name"], entry["fax"]))
790 log.debug("File list:")
792 for f in self.file_list:
795 self.dev.sendEvent(EVENT_START_FAX_JOB, self.printer_name, 0, '')
797 if not self.dev.sendFaxes(phone_num_list, self.file_list, self.cover_page_message,
798 self.cover_page_re, self.cover_page_func, self.preserve_formatting,
799 self.printer_name, self.update_queue, self.event_queue):
801 FailureUI(self, self.__tr("<b>Send fax is active.</b><p>Please wait for operation to complete."))
802 self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.printer_name, 0, '')
804 self.send_fax_active = False
805 #self.NextButton.setEnabled(False)
806 self.setCancelCloseButton()
809 self.send_fax_active = True
810 self.setCancelCloseButton()
811 self.SendFaxTimer = QTimer(self)
812 self.connect(self.SendFaxTimer, SIGNAL('timeout()'), self.SendFaxTimer_timeout)
813 self.SendFaxTimer.start(1000) # 1 sec UI updates
816 def setCancelCloseButton(self):
817 if self.send_fax_active:
818 self.CancelButton.setText(self.__tr("Cancel Send"))
820 self.CancelButton.setText(self.__tr("Close"))
823 def CancelButton_clicked(self):
824 if self.send_fax_active:
825 self.addStatusMessage(self.__tr("Cancelling job..."), self.warn_icon)
826 self.event_queue.put((fax.EVENT_FAX_SEND_CANCELED, '', '', ''))
827 self.dev.sendEvent(EVENT_FAX_JOB_CANCELED, self.printer_name, 0, '')
832 def SendFaxTimer_timeout(self):
833 while self.update_queue.qsize():
835 status, page_num, arg = self.update_queue.get(0)
839 if status == fax.STATUS_IDLE:
841 self.send_fax_active = False
842 self.setCancelCloseButton()
843 self.SendFaxTimer.stop()
845 elif status == fax.STATUS_PROCESSING_FILES:
846 self.addStatusMessage(self.__tr("Processing page %1...").arg(page_num), self.busy_icon)
848 elif status == fax.STATUS_SENDING_TO_RECIPIENT:
849 self.addStatusMessage(self.__tr("Sending fax to %1...").arg(arg), self.busy_icon)
851 elif status == fax.STATUS_DIALING:
852 self.addStatusMessage(self.__tr("Dialing %1...").arg(arg), self.busy_icon)
854 elif status == fax.STATUS_CONNECTING:
855 self.addStatusMessage(self.__tr("Connecting to %1...").arg(arg), self.busy_icon)
857 elif status == fax.STATUS_SENDING:
858 self.addStatusMessage(self.__tr("Sending page %1 to %2...").arg(page_num).arg(arg),
861 elif status == fax.STATUS_CLEANUP:
862 self.addStatusMessage(self.__tr("Cleaning up..."), self.busy_icon)
864 elif status in (fax.STATUS_ERROR, fax.STATUS_BUSY, fax.STATUS_COMPLETED, fax.STATUS_ERROR_IN_CONNECTING,
865 fax.STATUS_ERROR_IN_TRANSMITTING, fax.STATUS_ERROR_PROBLEM_IN_FAXLINE, fax.STATUS_JOB_CANCEL ):
867 self.send_fax_active = False
868 self.setCancelCloseButton()
869 self.SendFaxTimer.stop()
871 if status == fax.STATUS_ERROR:
872 result_code, error_state = self.dev.getPML(pml.OID_FAX_DOWNLOAD_ERROR)
873 #FailureUI(self, self.__tr("<b>Fax send error (%s).</b><p>" % pml.DN_ERROR_STR.get(error_state, "Unknown error")))
874 if error_state == pml.DN_ERROR_NONE:
875 self.addStatusMessage(self.__tr("Fax send error (Possible cause: No answer or dialtone)"), self.error_icon)
877 self.addStatusMessage(self.__tr("Fax send error (%1)").arg(pml.DN_ERROR_STR.get(error_state, "Unknown error")), self.error_icon)
878 self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.printer_name, 0, '')
880 elif status == fax.STATUS_ERROR_IN_CONNECTING:
881 self.addStatusMessage(self.__tr("Fax send error (Error in connecting)"), self.error_icon)
882 self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.printer_name, 0, '')
884 elif status == fax.STATUS_ERROR_IN_TRANSMITTING:
885 self.addStatusMessage(self.__tr("Fax send error (Error in transmitting)"), self.error_icon)
886 self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.printer_name, 0, '')
888 elif status == fax.STATUS_ERROR_PROBLEM_IN_FAXLINE:
889 self.addStatusMessage(self.__tr("Fax send error (Problem with the fax line)"), self.error_icon)
890 self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.printer_name, 0, '')
892 elif status == fax.STATUS_JOB_CANCEL:
893 self.addStatusMessage(self.__tr("(Fax Job Cancelled)"), self.error_icon)
894 self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.printer_name, 0, '')
896 elif status == fax.STATUS_BUSY:
897 #FailureUI(self, self.__tr("<b>Fax device is busy.</b><p>Please try again later."))
898 self.addStatusMessage(self.__tr("Fax is busy."), self.error_icon)
899 self.dev.sendEvent(EVENT_FAX_JOB_FAIL, self.printer_name, 0, '')
901 elif status == fax.STATUS_COMPLETED:
902 self.addStatusMessage(self.__tr("Send fax job complete."), self.info_icon)
904 self.dev.sendEvent(EVENT_END_FAX_JOB, self.printer_name, 0, '')
907 def addStatusMessage(self, text, icon):
909 #self.StatusList.addItem(QListWidgetItem(icon, text, self.StatusList))
910 QListWidgetItem(icon, text, self.StatusList)
913 # CheckTimer and Fax Rendering
916 def FileTable_callback(self, f):
917 # Called by FileTable when user adds a file using "Add file..."
918 log.debug("FileTable_callback(%s)" % f)
922 def renderFile(self, f):
926 self.last_job_id = cups.printFile(self.printer_name, f, os.path.basename(f))
932 def CheckTimer_timeout(self):
934 #log.debug("Checking for incoming faxes...")
935 device_uri, printer_name, event_code, username, job_id, title, timedate, fax_file = \
936 self.service.CheckForWaitingFax(self.device_uri, prop.username, self.last_job_id)
940 log.debug("A new fax has arrived: %s (%d)" % (fax_file, job_id))
941 self.addFileFromJob(fax_file, title)
944 def addFileFromJob(self, fax_file, title):
948 ok, num_pages, hort_dpi, vert_dpi, page_size, resolution, encoding = \
949 self.getFileInfo(fax_file)
951 self.FilesTable.addFile(fax_file, 'application/hplip-fax', 'HPLIP Fax', title, num_pages)
958 def getFileInfo(self, fax_file):
959 f = file(fax_file, 'r')
960 header = f.read(fax.FILE_HEADER_SIZE)
963 if len(header) != fax.FILE_HEADER_SIZE:
964 log.error("Invalid fax file! (truncated header or no data)")
965 return (False, 0, 0, 0, 0, 0, 0)
967 mg, version, num_pages, hort_dpi, vert_dpi, page_size, \
968 resolution, encoding, reserved1, reserved2 = \
969 struct.unpack(">8sBIHHBBBII", header[:fax.FILE_HEADER_SIZE])
971 log.debug("Magic=%s Ver=%d Pages=%d hDPI=%d vDPI=%d Size=%d Res=%d Enc=%d" %
972 (mg, version, num_pages, hort_dpi, vert_dpi, page_size, resolution, encoding))
974 return (True, num_pages, hort_dpi, vert_dpi, page_size, resolution, encoding)
981 def closeEvent(self, e):
982 if self.lock_file is not None:
983 utils.unlock(self.lock_file)
987 def displayPage(self, page):
988 self.updateStepText(page)
989 self.StackedWidget.setCurrentIndex(page)
992 # def CancelButton_clicked(self):
996 def BackButton_clicked(self):
997 p = self.StackedWidget.currentIndex()
998 if p == PAGE_SELECT_FAX:
999 log.error("Invalid!")
1001 elif p == PAGE_COVERPAGE:
1002 log.error("Invalid!")
1004 elif p == PAGE_FILES:
1005 self.StackedWidget.setCurrentIndex(PAGE_COVERPAGE)
1006 self.displayCoverpagePage()
1008 elif p == PAGE_RECIPIENTS:
1009 self.StackedWidget.setCurrentIndex(PAGE_FILES)
1010 self.displayFilesPage()
1012 elif p == PAGE_SEND_FAX:
1013 self.StackedWidget.setCurrentIndex(PAGE_RECIPIENTS)
1014 self.displayRecipientsPage()
1017 def NextButton_clicked(self):
1018 p = self.StackedWidget.currentIndex()
1019 if p == PAGE_SELECT_FAX:
1020 self.StackedWidget.setCurrentIndex(PAGE_COVERPAGE)
1021 self.displayCoverpagePage()
1023 elif p == PAGE_COVERPAGE:
1024 self.StackedWidget.setCurrentIndex(PAGE_FILES)
1025 self.displayFilesPage()
1027 elif p == PAGE_FILES:
1028 self.StackedWidget.setCurrentIndex(PAGE_RECIPIENTS)
1029 self.displayRecipientsPage()
1031 elif p == PAGE_RECIPIENTS:
1032 self.StackedWidget.setCurrentIndex(PAGE_SEND_FAX)
1033 self.displaySendFaxPage()
1035 elif p == PAGE_SEND_FAX:
1036 self.executeSendFax()
1039 def updateStepText(self, p):
1040 self.StepText.setText(self.__tr("Step %1 of %2").arg(p+1).arg(PAGE_MAX+1))
1043 def restoreNextButton(self):
1044 self.NextButton.setText(self.__tr("Next >"))
1047 def __tr(self,s,c = None):
1048 return qApp.translate("SendFaxDialog",s,c)