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
19 # Authors: Don Welch, Naga Samrat Chowdary Narla
29 from base import device, utils, models, pkit
31 from base.codes import *
32 from ui_utils import *
33 #from installer import core_install
34 from installer.core_install import CoreInstall
37 from PyQt4.QtCore import *
38 from PyQt4.QtGui import *
41 from setupdialog_base import Ui_Dialog
42 from plugindialog import PluginDialog
43 from wifisetupdialog import WifiSetupDialog, SUCCESS_CONNECTED
50 # This can fail on Python < 2.3 due to the datetime module
52 log.warning("Fax setup disabled - Python 2.3+ required.")
63 BUTTON_ADD_PRINTER = 2
70 DEVICE_DESC_SINGLE_FUNC = 1
71 DEVICE_DESC_MULTI_FUNC = 2
77 class PasswordDialog(QDialog):
78 def __init__(self, prompt, parent=None, name=None, modal=0, fl=0):
79 QDialog.__init__(self, parent)
81 self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128')))
84 Layout= QGridLayout(self)
88 self.PromptTextLabel = QLabel(self)
89 Layout.addWidget(self.PromptTextLabel,0,0,1,3)
91 self.UsernameTextLabel = QLabel(self)
92 Layout.addWidget(self.UsernameTextLabel,1,0)
94 self.UsernameLineEdit = QLineEdit(self)
95 self.UsernameLineEdit.setEchoMode(QLineEdit.Normal)
96 Layout.addWidget(self.UsernameLineEdit,1,1,1,2)
98 self.PasswordTextLabel = QLabel(self)
99 Layout.addWidget(self.PasswordTextLabel,2,0)
101 self.PasswordLineEdit = QLineEdit(self)
102 self.PasswordLineEdit.setEchoMode(QLineEdit.Password)
103 Layout.addWidget(self.PasswordLineEdit,2,1,1,2)
105 self.OkPushButton = QPushButton(self)
106 Layout.addWidget(self.OkPushButton,3,2)
108 self.languageChange()
110 self.resize(QSize(420,163).expandedTo(self.minimumSizeHint()))
112 self.connect(self.OkPushButton, SIGNAL("clicked()"), self.accept)
113 self.connect(self.PasswordLineEdit, SIGNAL("returnPressed()"), self.accept)
115 def setDefaultUsername(self, defUser, allowUsernameEdit = True):
116 self.UsernameLineEdit.setText(defUser)
117 if not allowUsernameEdit:
118 self.UsernameLineEdit.setReadOnly(True)
119 self.UsernameLineEdit.setStyleSheet("QLineEdit {background-color: lightgray}")
121 def getUsername(self):
122 return unicode(self.UsernameLineEdit.text())
125 def getPassword(self):
126 return unicode(self.PasswordLineEdit.text())
129 def languageChange(self):
130 self.setWindowTitle(self.__tr("HP Device Manager - Enter Username/Password"))
131 self.PromptTextLabel.setText(self.__tr(self.prompt))
132 self.UsernameTextLabel.setText(self.__tr("Username:"))
133 self.PasswordTextLabel.setText(self.__tr("Password:"))
134 self.OkPushButton.setText(self.__tr("OK"))
137 def __tr(self,s,c = None):
138 return qApp.translate("SetupDialog",s,c)
142 def showPasswordUI(prompt, userName=None, allowUsernameEdit=True):
144 dlg = PasswordDialog(prompt, None)
147 dlg.setDefaultUsername(userName, allowUsernameEdit)
149 if dlg.exec_() == QDialog.Accepted:
150 return (dlg.getUsername(), dlg.getPassword())
159 class DeviceTableWidgetItem(QTableWidgetItem):
160 def __init__(self, text, device_uri):
161 QTableWidgetItem.__init__(self, text, QTableWidgetItem.UserType)
162 self.device_uri = device_uri
166 class SetupDialog(QDialog, Ui_Dialog):
167 def __init__(self, parent, param, jd_port, device_uri=None, remove=False):
168 QDialog.__init__(self, parent)
172 self.jd_port = jd_port
173 self.device_uri = device_uri
177 log.info("Using device: %s" % device_uri)
182 QTimer.singleShot(0, self.showRemovePage)
184 if self.skip_discovery:
185 QTimer.singleShot(0, self.showDevicesPage)
187 QTimer.singleShot(0, self.showDiscoveryPage)
189 cups.setPasswordCallback(showPasswordUI)
197 self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128')))
199 # connect signals/slots
200 self.connect(self.CancelButton, SIGNAL("clicked()"), self.CancelButton_clicked)
201 self.connect(self.BackButton, SIGNAL("clicked()"), self.BackButton_clicked)
202 self.connect(self.NextButton, SIGNAL("clicked()"), self.NextButton_clicked)
203 self.connect(self.ManualGroupBox, SIGNAL("clicked(bool)"), self.ManualGroupBox_clicked)
206 self.initRemovePage()
209 self.initDiscoveryPage()
210 self.initDevicesPage()
211 self.initAddPrinterPage()
212 self.max_page = PAGE_ADD_PRINTER
218 def initDiscoveryPage(self):
219 self.UsbRadioButton.setChecked(True)
220 self.setUsbRadioButton(True)
221 self.ManualGroupBox.setChecked(False)
223 self.advanced = False
225 self.skip_discovery = False
226 self.discovery_method = 0
227 self.NetworkRadioButton.setEnabled(prop.net_build)
228 self.WirelessButton.setEnabled(prop.net_build)
229 self.ParallelRadioButton.setEnabled(prop.par_build)
235 self.print_test_page = False
236 self.device_desc = DEVICE_DESC_ALL
239 log.info("Searching for device...")
242 self.ManualParamLineEdit.setText(self.param)
243 self.JetDirectSpinBox.setValue(self.jd_port)
244 self.ManualGroupBox.setChecked(True)
245 self.DiscoveryOptionsGroupBox.setEnabled(False)
247 if self.manualDiscovery():
248 self.skip_discovery = True
250 FailureUI(self, self.__tr("<b>Device not found.</b> <p>Please make sure your printer is properly connected and powered-on."))
252 match = device.usb_pat.match(self.param)
253 if match is not None:
254 self.UsbRadioButton.setChecked(True)
255 self.setUsbRadioButton(True)
258 match = device.dev_pat.match(self.param)
259 if match is not None and prop.par_build:
260 self.ParallelRadioButton.setChecked(True)
261 self.setParallelRadioButton(True)
264 match = device.ip_pat.match(self.param)
265 if match is not None and prop.net_build:
266 self.NetworkRadioButton.setChecked(True)
267 self.setNetworkRadioButton(True)
270 FailureUI(self, self.__tr("<b>Invalid manual discovery parameter.</b>"))
272 elif self.device_uri: # If device URI specified on the command line, skip discovery
273 # if the device URI is well-formed (but not necessarily valid)
275 back_end, is_hp, self.bus, model, serial, dev_file, host, zc, port = \
276 device.parseDeviceURI(self.device_uri)
279 log.error("Invalid device URI specified: %s" % self.device_uri)
283 if self.bus == 'net':
285 log.debug("Trying to get hostname for device...")
286 name = socket.gethostbyaddr(host)[0]
287 except socket.herror:
290 log.debug("Host name=%s" % name)
292 self.devices = {self.device_uri : (model, model, name)}
293 self.skip_discovery = True
295 # If no network or parallel, usb is only option, skip initial page...
296 elif not prop.par_build and not prop.net_build:
297 self.skip_discovery = True
299 self.UsbRadioButton.setChecked(True)
300 self.setUsbRadioButton(True)
302 if prop.fax_build and prop.scan_build:
303 self.DeviceTypeComboBox.addItem("All devices/printers", QVariant(DEVICE_DESC_ALL))
304 self.DeviceTypeComboBox.addItem("Single function printers only", QVariant(DEVICE_DESC_SINGLE_FUNC))
305 self.DeviceTypeComboBox.addItem("All-in-one/MFP devices only", QVariant(DEVICE_DESC_MULTI_FUNC))
307 self.DeviceTypeComboBox.setEnabled(False)
309 self.connect(self.AdvancedButton, SIGNAL("clicked()"), self.AdvancedButton_clicked)
310 self.connect(self.UsbRadioButton, SIGNAL("toggled(bool)"), self.UsbRadioButton_toggled)
311 self.connect(self.NetworkRadioButton, SIGNAL("toggled(bool)"), self.NetworkRadioButton_toggled)
312 self.connect(self.WirelessButton, SIGNAL("toggled(bool)"), self.WirelessButton_toggled)
313 self.connect(self.ParallelRadioButton, SIGNAL("toggled(bool)"), self.ParallelRadioButton_toggled)
314 self.connect(self.NetworkTTLSpinBox, SIGNAL("valueChanged(int)"), self.NetworkTTLSpinBox_valueChanged)
315 self.connect(self.NetworkTimeoutSpinBox, SIGNAL("valueChanged(int)"),
316 self.NetworkTimeoutSpinBox_valueChanged)
317 self.connect(self.ManualGroupBox, SIGNAL("toggled(bool)"), self.ManualGroupBox_toggled)
322 def ManualGroupBox_toggled(self, checked):
323 self.DiscoveryOptionsGroupBox.setEnabled(not checked)
326 def manualDiscovery(self):
328 device_uri, sane_uri, fax_uri = device.makeURI(self.param, self.jd_port)
331 log.info("Found device: %s" % device_uri)
332 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
333 device.parseDeviceURI(device_uri)
338 name = socket.gethostbyaddr(host)[0]
339 except (socket.herror, socket.gaierror):
342 self.devices = {device_uri : (model, model, name)}
345 self.UsbRadioButton.setChecked(True)
346 self.setUsbRadioButton(True)
348 elif bus == 'net' and prop.net_build:
349 self.NetworkRadioButton.setChecked(True)
350 self.setNetworkRadioButton(True)
352 elif bus == 'par' and prop.par_build:
353 self.ParallelRadioButton.setChecked(True)
354 self.setParallelRadioButton(True)
362 def ManualGroupBox_clicked(self, checked):
363 self.manual = checked
364 network = self.NetworkRadioButton.isChecked()
365 self.setJetDirect(network)
368 def showDiscoveryPage(self):
369 self.BackButton.setEnabled(False)
370 self.NextButton.setEnabled(True)
371 self.setNextButton(BUTTON_NEXT)
372 self.displayPage(PAGE_DISCOVERY)
375 def AdvancedButton_clicked(self):
376 self.advanced = not self.advanced
380 def showAdvanced(self):
382 self.AdvancedStackedWidget.setCurrentIndex(ADVANCED_SHOW)
383 self.AdvancedButton.setText(self.__tr("Hide Advanced Options"))
384 self.AdvancedButton.setIcon(QIcon(load_pixmap("minus", "16x16")))
386 self.AdvancedStackedWidget.setCurrentIndex(ADVANCED_HIDE)
387 self.AdvancedButton.setText(self.__tr("Show Advanced Options"))
388 self.AdvancedButton.setIcon(QIcon(load_pixmap("plus", "16x16")))
391 def setJetDirect(self, enabled):
392 self.JetDirectLabel.setEnabled(enabled and self.manual)
393 self.JetDirectSpinBox.setEnabled(enabled and self.manual)
396 def setNetworkOptions(self, enabled):
397 self.NetworkTimeoutLabel.setEnabled(enabled)
398 self.NetworkTimeoutSpinBox.setEnabled(enabled)
399 self.NetworkTTLLabel.setEnabled(enabled)
400 self.NetworkTTLSpinBox.setEnabled(enabled)
403 def setSearchOptions(self, enabled):
404 self.SearchLineEdit.setEnabled(enabled)
405 self.DeviceTypeComboBox.setEnabled(enabled)
406 self.DeviceTypeLabel.setEnabled(enabled)
409 def setManualDiscovery(self, enabled):
410 self.ManualGroupBox.setEnabled(enabled)
413 def setNetworkDiscovery(self, enabled):
414 self.NetworkDiscoveryMethodLabel.setEnabled(enabled)
415 self.NetworkDiscoveryMethodComboBox.setEnabled(enabled)
416 self.NetworkDiscoveryMethodComboBox.setCurrentIndex(1)
419 def UsbRadioButton_toggled(self, radio_enabled):
420 self.setUsbRadioButton(radio_enabled)
423 def setUsbRadioButton(self, checked):
424 self.setNetworkDiscovery(not checked)
425 self.setJetDirect(not checked)
426 self.setNetworkOptions(not checked)
427 self.setSearchOptions(checked)
428 self.setManualDiscovery(checked)
431 self.ManualParamLabel.setText(self.__tr("USB bus ID:device ID (bbb:ddd):"))
433 # TODO: Set bbb:ddd validator
436 def NetworkRadioButton_toggled(self, radio_enabled):
437 self.setNetworkRadioButton(radio_enabled)
440 def setNetworkRadioButton(self, checked):
441 self.setNetworkDiscovery(checked)
442 self.setJetDirect(checked)
443 self.setNetworkOptions(checked)
444 self.setSearchOptions(checked)
445 self.setManualDiscovery(checked)
449 self.ManualParamLabel.setText(self.__tr("IP Address or network name:"))
451 # TODO: Reset validator
453 def WirelessButton_toggled(self, radio_enabled):
454 self.setWirelessButton(radio_enabled)
457 def setWirelessButton(self, checked):
458 self.setNetworkDiscovery(not checked)
459 self.setJetDirect(not checked)
460 self.setNetworkOptions(not checked)
461 self.setSearchOptions(not checked)
462 self.setManualDiscovery(not checked)
466 self.ManualParamLabel.setText(self.__tr("IP Address or network name:"))
470 def ParallelRadioButton_toggled(self, radio_enabled):
471 self.setParallelRadioButton(radio_enabled)
474 def setParallelRadioButton(self, checked):
475 self.setNetworkDiscovery(not checked)
476 self.setJetDirect(not checked)
477 self.setNetworkOptions(not checked)
478 self.setSearchOptions(not checked)
479 self.setManualDiscovery(not checked)
483 self.ManualParamLabel.setText(self.__tr("Device node (/dev/...):"))
485 # TODO: Set /dev/... validator
488 def NetworkTTLSpinBox_valueChanged(self, ttl):
492 def NetworkTimeoutSpinBox_valueChanged(self, timeout):
493 self.timeout = timeout
499 def initDevicesPage(self):
500 self.connect(self.RefreshButton, SIGNAL("clicked()"), self.RefreshButton_clicked)
503 def showDevicesPage(self):
504 self.BackButton.setEnabled(True)
505 self.setNextButton(BUTTON_NEXT)
508 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
511 if self.manual and self.param: # manual, but not passed-in on command line
512 self.manualDiscovery()
517 if self.bus == 'net':
518 if self.discovery_method == 0:
519 net_search_type = "slp"
521 net_search_type = "mdns"
523 log.info("Searching... (bus=%s, timeout=%d, ttl=%d, search=%s desc=%d, method=%s)" %
524 (self.bus, self.timeout, self.ttl, self.search or "(None)",
525 self.device_desc, net_search_type))
527 log.info("Searching... (bus=%s, search=%s, desc=%d)" %
528 (self.bus, self.search or "(None)", self.device_desc))
530 if self.device_desc == DEVICE_DESC_SINGLE_FUNC:
531 filter_dict = {'scan-type' : (operator.le, SCAN_TYPE_NONE)}
533 elif self.device_desc == DEVICE_DESC_MULTI_FUNC:
534 filter_dict = {'scan-type': (operator.gt, SCAN_TYPE_NONE)}
536 else: # DEVICE_DESC_ALL
539 self.devices = device.probeDevices([self.bus], self.timeout, self.ttl,
540 filter_dict, self.search, net_search=net_search_type)
542 QApplication.restoreOverrideCursor()
544 self.clearDevicesTable()
547 self.NextButton.setEnabled(True)
548 self.DevicesFoundIcon.setPixmap(load_pixmap('info', '16x16'))
550 if len(self.devices) == 1:
551 self.DevicesFoundLabel.setText(self.__tr("<b>1 device found.</b> Click <i>Next</i> to continue."))
553 self.DevicesFoundLabel.setText(self.__tr("<b>%1 devices found.</b> Select the device to install and click <i>Next</i> to continue.").arg(len(self.devices)))
555 self.loadDevicesTable()
558 self.NextButton.setEnabled(False)
559 self.DevicesFoundIcon.setPixmap(load_pixmap('error', '16x16'))
560 log.error("No devices found on bus: %s" % self.bus)
561 self.DevicesFoundLabel.setText(self.__tr("<b>No devices found.</b><br>Click <i>Back</i> to change discovery options, or <i>Refresh</i> to search again."))
563 self.displayPage(PAGE_DEVICES)
566 def loadDevicesTable(self):
567 self.DevicesTableWidget.setRowCount(len(self.devices))
569 if self.bus == 'net':
570 if self.discovery_method == 0:
571 headers = [self.__tr('Model'), self.__tr('IP Address'), self.__tr('Host Name'), self.__tr('Device URI')]
574 headers = [self.__tr('Model'), self.__tr('Host Name'), self.__tr('Device URI')]
577 headers = [self.__tr('Model'), self.__tr('Device URI')]
580 self.DevicesTableWidget.setColumnCount(len(headers))
581 self.DevicesTableWidget.setHorizontalHeaderLabels(headers)
582 flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
584 for row, d in enumerate(self.devices):
585 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(d)
586 model_ui = models.normalizeModelUIName(model)
588 i = DeviceTableWidgetItem(QString(model_ui), d)
590 self.DevicesTableWidget.setItem(row, 0, i)
592 i = QTableWidgetItem(QString(d))
594 self.DevicesTableWidget.setItem(row, device_uri_col, i)
596 if self.bus == 'net':
597 i = QTableWidgetItem(QString(host))
599 self.DevicesTableWidget.setItem(row, 1, i)
601 if self.discovery_method == 0:
602 i = QTableWidgetItem(QString(self.devices[d][2]))
604 self.DevicesTableWidget.setItem(row, 2, i)
606 self.DevicesTableWidget.resizeColumnsToContents()
607 self.DevicesTableWidget.selectRow(0)
608 self.DevicesTableWidget.setSortingEnabled(True)
609 self.DevicesTableWidget.sortItems(0)
612 def clearDevicesTable(self):
613 self.DevicesTableWidget.clear()
614 self.DevicesTableWidget.setRowCount(0)
615 self.DevicesTableWidget.setColumnCount(0)
618 def RefreshButton_clicked(self):
619 self.clearDevicesTable()
621 QTimer.singleShot(0, self.showDevicesPage)
627 def initAddPrinterPage(self):
630 self.connect(self.PrinterNameLineEdit, SIGNAL("textEdited(const QString &)"),
631 self.PrinterNameLineEdit_textEdited)
633 self.connect(self.FaxNameLineEdit, SIGNAL("textEdited(const QString &)"),
634 self.FaxNameLineEdit_textEdited)
636 self.PrinterNameLineEdit.setValidator(PrinterNameValidator(self.PrinterNameLineEdit))
637 self.FaxNameLineEdit.setValidator(PrinterNameValidator(self.FaxNameLineEdit))
638 self.FaxNumberLineEdit.setValidator(PhoneNumValidator(self.FaxNumberLineEdit))
640 self.OtherPPDButton.setIcon(QIcon(load_pixmap('folder_open', '16x16')))
641 self.connect(self.OtherPPDButton, SIGNAL("clicked(bool)"), self.OtherPPDButton_clicked)
643 self.OtherPPDButton.setToolTip(self.__tr("Browse for an alternative PPD file for this printer."))
645 self.printer_fax_names_same = False
646 self.printer_name = ''
648 self.fax_setup_ok = True
649 self.fax_setup = False
652 def showAddPrinterPage(self):
653 # Install the plugin if needed...
655 plugin = self.mq.get('plugin', PLUGIN_NONE)
656 plugin_reason = self.mq.get('plugin-reason', PLUGIN_REASON_NONE)
657 if plugin > PLUGIN_NONE:
659 if core.check_for_plugin() != PLUGIN_INSTALLED:
660 ok, sudo_ok = pkit.run_plugin_command(plugin == PLUGIN_REQUIRED, plugin_reason)
662 FailureUI(self, self.__tr("<b>Unable to find an appropriate su/sudo utiltity to run hp-plugin.</b><p>Install kdesu, gnomesu, or gksu.</p>"))
664 if not ok or core.check_for_plugin() != PLUGIN_INSTALLED:
665 if plugin == PLUGIN_REQUIRED:
666 FailureUI(self, self.__tr("<b>The printer you are trying to setup requires a binary driver plug-in and it failed to install.</b><p>Please check your internet connection and try again.</p><p>Visit <u>http://hplipopensource.com</u> for more infomation.</p>"))
669 WarningUI(self, self.__tr("Either you have chosen to skip the installation of the optional plug-in or that installation has failed. Your printer may not function at optimal performance."))
671 self.setNextButton(BUTTON_ADD_PRINTER)
673 if not self.printer_name:
674 self.setDefaultPrinterName()
676 self.findPrinterPPD()
678 if fax_import_ok and prop.fax_build and \
679 self.mq.get('fax-type', FAX_TYPE_NONE) not in (FAX_TYPE_NONE, FAX_TYPE_NOT_SUPPORTED):
681 self.fax_setup = True
682 self.SetupFaxGroupBox.setChecked(True)
683 self.SetupFaxGroupBox.setEnabled(True)
685 if not self.fax_name:
686 self.setDefaultFaxName()
690 self.readwriteFaxInformation()
693 self.SetupFaxGroupBox.setChecked(False)
694 self.SetupFaxGroupBox.setEnabled(False)
696 self.fax_name_ok = True
697 self.fax_setup = False
698 self.fax_setup_ok = True
701 self.setAddPrinterButton()
702 self.displayPage(PAGE_ADD_PRINTER)
708 if self.print_ppd is None:
709 log.error("No appropriate print PPD file found for model %s" % self.model)
710 self.PPDFileLineEdit.setText(self.__tr('(Not found. Click browse button to select a PPD file.)'))
712 self.PPDFileLineEdit.setStyleSheet("background-color: yellow")
713 except AttributeError:
715 self.PrinterDescriptionLineEdit.setText(QString(""))
718 self.PPDFileLineEdit.setText(self.print_ppd[0])
719 self.PrinterDescriptionLineEdit.setText(self.print_ppd[1])
721 self.PPDFileLineEdit.setStyleSheet("")
722 except AttributeError:
726 def OtherPPDButton_clicked(self, b):
727 ppd_file = unicode(QFileDialog.getOpenFileName(self, self.__tr("Select PPD File"),
728 sys_conf.get('dirs', 'ppd'),
729 self.__tr("PPD Files (*.ppd *.ppd.gz);;All Files (*)")))
731 if ppd_file and os.path.exists(ppd_file):
732 self.print_ppd = (ppd_file, cups.getPPDDescription(ppd_file))
734 self.setAddPrinterButton()
737 def findPrinterPPD(self):
738 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
740 self.print_ppd = None
741 self.ppds = cups.getSystemPPDs()
743 #Check if common ppd name is already given in models.dat(This is needed because in case of devices having more than one derivatives
744 #will have diffrent model name strings in device ID, because of which we don't get the common ppd name for search)
746 ppd_name = self.mq.get('ppd-name',0)
748 if ppd_name == 0: #Means ppd-name is not provided So follow earlier path of getting name from device ID.
749 model = cups.stripModel2(self.model)
750 self.print_ppd = cups.getPPDFile2(model, self.ppds)
752 self.print_ppd = cups.getPPDFile2(ppd_name, self.ppds)
755 QApplication.restoreOverrideCursor()
758 def findFaxPPD(self):
759 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
761 log.debug("Searching for fax PPD for model %s" % self.model)
763 if prop.hpcups_build:
764 if self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_MARVELL:
765 fax_ppd_name = "HP-Fax3-hpcups" # Fixed width (2528 pixels) and 300dpi rendering
766 nick = "HP Fax3 hpcups"
767 elif self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_SOAP or self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_LEDMSOAP:
768 fax_ppd_name = "HP-Fax2-hpcups" # Fixed width (2528 pixels) and 300dpi rendering
769 nick = "HP Fax2 hpcups"
770 elif self.mq.get('fax-type', FAX_TYPE_LEDM) == FAX_TYPE_LEDM:
771 fax_ppd_name = "HP-Fax4-hpcups"# Fixed width (2528 pixels) and 300dpi rendering
772 nick = "HP Fax4 hpcups"
774 fax_ppd_name = "HP-Fax-hpcups" # Standard
775 nick = "HP Fax hpcups"
778 if self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_MARVELL:
779 fax_ppd_name = "HP-Fax3-hpijs" # Fixed width (2528 pixels) and 300dpi rendering
780 nick = "HP Fax3 hpijs"
781 if self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_SOAP or self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_LEDMSOAP:
782 fax_ppd_name = "HP-Fax2-hpijs" # Fixed width (2528 pixels) and 300dpi rendering
783 nick = "HP Fax2 hpijs"
784 if self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_LEDM:
785 fax_ppd_name = "HP-Fax4-hpijs" # Fixed width (2528 pixels) and 300dpi rendering
786 nick = "HP Fax4 hpijs"
788 fax_ppd_name = "HP-Fax-hpijs" # Standard
789 nick = "HP Fax hpijs"
793 for f in utils.walkFiles(sys_conf.get('dirs', 'ppd'), pattern="HP-Fax*.ppd*", abs_paths=True):
797 if f.find(fax_ppd_name) >= 0 and cups.getPPDDescription(f) == nick:
799 self.fax_setup_ok = True
800 log.debug("Found fax PPD: %s" % f)
804 self.fax_setup_ok = False
805 FailureUI(self, self.__tr("<b>Unable to locate the HPLIP Fax PPD file:</b><p>%1.ppd.gz</p><p>Fax setup has been disabled.").arg(fax_ppd_name))
806 self.fax_setup = False
807 self.SetupFaxGroupBox.setChecked(False)
808 self.SetupFaxGroupBox.setEnabled(False)
811 QApplication.restoreOverrideCursor()
815 def setDefaultPrinterName(self):
816 self.installed_print_devices = device.getSupportedCUPSDevices(['hp'])
817 log.debug(self.installed_print_devices)
819 self.installed_queues = [p.name for p in cups.getPrinters()]
821 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(self.device_uri)
822 default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_')
824 printer_name = default_model
825 installed_printer_names = device.getSupportedCUPSPrinterNames(['hp'])
826 # Check for duplicate names
827 if (self.device_uri in self.installed_print_devices and printer_name in self.installed_print_devices[self.device_uri]) \
828 or (printer_name in installed_printer_names):
831 t = printer_name + "_%d" % i
832 if (t not in installed_printer_names) and (self.device_uri not in self.installed_print_devices or t not in self.installed_print_devices[self.device_uri]):
833 printer_name += "_%d" % i
837 self.printer_name_ok = True
838 self.PrinterNameLineEdit.setText(printer_name)
839 log.debug(printer_name)
840 self.printer_name = printer_name
843 def setDefaultFaxName(self):
844 self.installed_fax_devices = device.getSupportedCUPSDevices(['hpfax'])
845 log.debug(self.installed_fax_devices)
847 self.fax_uri = self.device_uri.replace('hp:', 'hpfax:')
849 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(self.fax_uri)
850 default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_')
852 fax_name = default_model + "_fax"
853 installed_fax_names = device.getSupportedCUPSPrinterNames(['hpfax'])
854 # Check for duplicate names
855 if (self.fax_uri in self.installed_fax_devices and fax_name in self.installed_fax_devices[self.fax_uri]) \
856 or (fax_name in installed_fax_names):
859 t = fax_name + "_%d" % i
860 if (t not in installed_fax_names) and (self.fax_uri not in self.installed_fax_devices or t not in self.installed_fax_devices[self.fax_uri]):
861 fax_name += "_%d" % i
865 self.fax_name_ok = True
866 self.FaxNameLineEdit.setText(fax_name)
867 self.fax_name = fax_name
870 def PrinterNameLineEdit_textEdited(self, t):
871 self.printer_name = unicode(t)
872 self.printer_name_ok = True
874 if not self.printer_name:
875 self.PrinterNameLineEdit.setToolTip(self.__tr('You must enter a name for the printer.'))
876 self.printer_name_ok = False
878 elif self.fax_name == self.printer_name:
879 s = self.__tr('The printer name and fax name must be different. Please choose different names.')
880 self.PrinterNameLineEdit.setToolTip(s)
881 self.FaxNameLineEdit.setToolTip(s)
882 self.fax_name_ok = False
883 self.printer_name_ok = False
884 self.printer_fax_names_same = True
886 elif self.printer_name in self.installed_queues:
887 self.PrinterNameLineEdit.setToolTip(self.__tr('A printer already exists with this name. Please choose a different name.'))
888 self.printer_name_ok = False
890 elif self.printer_fax_names_same:
891 if self.fax_name != self.printer_name:
892 self.printer_fax_names_same = False
893 self.printer_name_ok = True
895 self.FaxNameLineEdit.emit(SIGNAL("textEdited(const QString &)"),
896 self.FaxNameLineEdit.text())
899 self.setAddPrinterButton()
902 def FaxNameLineEdit_textEdited(self, t):
903 self.fax_name = unicode(t)
904 self.fax_name_ok = True
906 if not self.fax_name:
907 self.FaxNameLineEdit.setToolTip(self.__tr('You must enter a fax name.'))
908 self.fax_name_ok = False
910 elif self.fax_name == self.printer_name:
911 s = self.__tr('The printer name and fax name must be different. Please choose different names.')
912 self.PrinterNameLineEdit.setToolTip(s)
913 self.FaxNameLineEdit.setToolTip(s)
914 self.printer_name_ok = False
915 self.fax_name_ok = False
916 self.printer_fax_names_same = True
918 elif self.fax_name in self.installed_queues:
919 self.FaxNameLineEdit.setToolTip(self.__tr('A fax already exists with this name. Please choose a different name.'))
920 self.fax_name_ok = False
922 elif self.printer_fax_names_same:
923 if self.fax_name != self.printer_name:
924 self.printer_fax_names_same = False
925 self.fax_name_ok = True
927 self.PrinterNameLineEdit.emit(SIGNAL("textEdited(const QString&)"),
928 self.PrinterNameLineEdit.text())
931 self.setAddPrinterButton()
934 def setIndicators(self):
935 if self.printer_name_ok:
936 self.PrinterNameLineEdit.setToolTip(QString(""))
938 self.PrinterNameLineEdit.setStyleSheet("")
939 except AttributeError:
943 self.PrinterNameLineEdit.setStyleSheet("background-color: yellow")
944 except AttributeError:
948 self.FaxNameLineEdit.setToolTip(QString(""))
950 self.PrinterNameLineEdit.setStyleSheet("")
951 except AttributeError:
955 self.PrinterNameLineEdit.setStyleSheet("background-color: yellow")
956 except AttributeError:
960 def setAddPrinterButton(self):
961 self.NextButton.setEnabled((self.printer_name_ok and self.print_ppd is not None) and
962 ((self.fax_setup and self.fax_name_ok) or not self.fax_setup))
969 def addPrinter(self):
974 self.readwriteFaxInformation(False)
976 if self.print_test_page:
987 def setupPrinter(self):
988 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
990 cups.setPasswordPrompt("You do not have permission to add a printer.")
991 if not os.path.exists(self.print_ppd[0]): # assume foomatic: or some such
992 status, status_str = cups.addPrinter(self.printer_name.encode('utf8'), self.device_uri,
993 self.print_location, '', self.print_ppd[0], self.print_desc)
995 status, status_str = cups.addPrinter(self.printer_name.encode('utf8'), self.device_uri,
996 self.print_location, self.print_ppd[0], '', self.print_desc)
998 log.debug("addPrinter() returned (%d, %s)" % (status, status_str))
999 self.installed_print_devices = device.getSupportedCUPSDevices(['hp'])
1001 log.debug(self.installed_print_devices)
1003 if self.device_uri not in self.installed_print_devices or \
1004 self.printer_name not in self.installed_print_devices[self.device_uri]:
1006 QApplication.restoreOverrideCursor()
1007 if os.geteuid!=0 and utils.addgroup()!=[]:
1008 FailureUI(self, self.__tr("<b>Printer queue setup failed. Could not connect to CUPS Server</b><p>Is user added to %s group(s)" %utils.list_to_string(utils.addgroup())))
1011 #service.sendEvent(self.hpssd_sock, EVENT_CUPS_QUEUES_CHANGED, device_uri=self.device_uri)
1015 QApplication.restoreOverrideCursor()
1019 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
1021 cups.setPasswordPrompt("You do not have permission to add a fax device.")
1022 if not os.path.exists(self.fax_ppd):
1023 status, status_str = cups.addPrinter(self.fax_name.encode('utf8'),
1024 self.fax_uri, self.fax_location, '', self.fax_ppd, self.fax_desc)
1026 status, status_str = cups.addPrinter(self.fax_name.encode('utf8'),
1027 self.fax_uri, self.fax_location, self.fax_ppd, '', self.fax_desc)
1029 log.debug("addPrinter() returned (%d, %s)" % (status, status_str))
1030 self.installed_fax_devices = device.getSupportedCUPSDevices(['hpfax'])
1032 log.debug(self.installed_fax_devices)
1034 if self.fax_uri not in self.installed_fax_devices or \
1035 self.fax_name not in self.installed_fax_devices[self.fax_uri]:
1037 QApplication.restoreOverrideCursor()
1038 FailureUI(self, self.__tr("<b>Fax queue setup failed.</b><p>Please restart CUPS and try again."))
1042 #service.sendEvent(self.hpssd_sock, EVENT_CUPS_QUEUES_CHANGED, device_uri=self.fax_uri)
1045 QApplication.restoreOverrideCursor()
1048 def readwriteFaxInformation(self, read=True):
1050 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
1052 d = fax.getFaxDevice(self.fax_uri, disable_dbus=True)
1058 error_text = self.__tr("Unable to communicate with the device. Please check the device and try again.")
1059 log.error(unicode(error_text))
1060 if QMessageBox.critical(self,
1063 QMessageBox.Retry | QMessageBox.Default,
1064 QMessageBox.Cancel | QMessageBox.Escape,
1065 QMessageBox.NoButton) == QMessageBox.Cancel:
1078 self.fax_number = unicode(d.getPhoneNum())
1079 self.fax_name_company = unicode(d.getStationName())
1081 d.setStationName(self.fax_name_company)
1082 d.setPhoneNum(self.fax_number)
1085 error_text = self.__tr("<b>Device I/O Error</b><p>Could not communicate with device. Device may be busy.")
1086 log.error(unicode(error_text))
1088 if QMessageBox.critical(self,
1091 QMessageBox.Retry | QMessageBox.Default,
1092 QMessageBox.Cancel | QMessageBox.Escape,
1093 QMessageBox.NoButton) == QMessageBox.Cancel:
1111 self.FaxNumberLineEdit.setText(self.fax_number)
1112 self.NameCompanyLineEdit.setText(self.fax_name_company)
1117 QApplication.restoreOverrideCursor()
1120 def printTestPage(self):
1122 d = device.Device(self.device_uri)
1124 FailureUI(self, self.__tr("<b>Device error:</b><p>%s (%s)." % (e.msg, e.opt)))
1130 FailureUI(self, self.__tr("<b>Unable to print to printer.</b><p>Please check device and try again."))
1132 if d.isIdleAndNoError():
1136 d.printTestPage(self.printer_name)
1138 if e.opt == ERROR_NO_CUPS_QUEUE_FOUND_FOR_DEVICE:
1139 FailureUI(self, self.__tr("<b>No CUPS queue found for device.</b><p>Please install the printer in CUPS and try again."))
1141 FailureUI(self, self.__tr("<b>Printer Error</b><p>An error occured: %s (code=%d)." % (e.msg, e.opt)))
1143 FailureUI(self, self.__tr("<b>Printer Error.</b><p>Printer is busy, offline, or in an error state. Please check the device and try again."))
1150 def initRemovePage(self):
1154 def showRemovePage(self):
1155 self.displayPage(PAGE_REMOVE)
1156 self.StepText.setText(self.__tr("Step 1 of 1"))
1157 self.setNextButton(BUTTON_REMOVE)
1158 self.BackButton.setEnabled(False)
1159 self.NextButton.setEnabled(False)
1161 self.RemoveDevicesTableWidget.verticalHeader().hide()
1163 self.installed_printers = device.getSupportedCUPSPrinters(['hp', 'hpfax'])
1164 log.debug(self.installed_printers)
1166 if not self.installed_printers:
1167 FailureUI(self, self.__tr("<b>No printers or faxes found to remove.</b><p>You must setup a least one printer or fax before you can remove it."))
1171 self.RemoveDevicesTableWidget.setRowCount(len(self.installed_printers))
1173 headers = [self.__tr("Select"), self.__tr('Printer (Queue) Name'), self.__tr('Type'), self.__tr('Device URI')]
1175 self.RemoveDevicesTableWidget.setColumnCount(len(headers))
1176 self.RemoveDevicesTableWidget.setHorizontalHeaderLabels(headers)
1177 flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
1180 for p in self.installed_printers:
1181 widget = QCheckBox(self.RemoveDevicesTableWidget)
1182 self.connect(widget, SIGNAL("stateChanged(int)"), self.CheckBox_stateChanged)
1183 self.RemoveDevicesTableWidget.setCellWidget(row, 0, widget)
1185 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
1186 device.parseDeviceURI(p.device_uri)
1188 if self.device_uri is not None and self.device_uri == p.device_uri:
1189 widget.setCheckState(Qt.Checked)
1191 i = QTableWidgetItem(QString(p.name))
1193 i.setData(Qt.UserRole, QVariant(p.name))
1194 self.RemoveDevicesTableWidget.setItem(row, 1, i)
1196 if back_end == 'hpfax':
1197 typ = self.__tr("Fax")
1199 typ = self.__tr("Printer")
1201 i = QTableWidgetItem(typ)
1203 self.RemoveDevicesTableWidget.setItem(row, 2, i)
1205 i = QTableWidgetItem(QString(p.device_uri))
1207 self.RemoveDevicesTableWidget.setItem(row, 3, i)
1211 self.RemoveDevicesTableWidget.resizeColumnsToContents()
1214 def CheckBox_stateChanged(self, i):
1215 for row in xrange(self.RemoveDevicesTableWidget.rowCount()):
1216 widget = self.RemoveDevicesTableWidget.cellWidget(row, 0)
1217 if widget.checkState() == Qt.Checked:
1218 self.NextButton.setEnabled(True)
1221 self.NextButton.setEnabled(False)
1228 def NextButton_clicked(self):
1229 p = self.StackedWidget.currentIndex()
1230 if p == PAGE_DISCOVERY:
1231 self.manual = self.ManualGroupBox.isChecked()
1232 self.param = unicode(self.ManualParamLineEdit.text())
1233 self.jd_port = self.JetDirectSpinBox.value()
1234 self.search = unicode(self.SearchLineEdit.text())
1235 self.device_desc = int(self.DeviceTypeComboBox.itemData(self.DeviceTypeComboBox.currentIndex()).toInt()[0])
1236 self.discovery_method = self.NetworkDiscoveryMethodComboBox.currentIndex()
1238 if self.WirelessButton.isChecked():
1239 dlg = WifiSetupDialog(self, device_uri=None, standalone=False)
1242 if dlg.success == SUCCESS_CONNECTED:
1246 if not self.WirelessButton.isChecked():
1247 self.showDevicesPage()
1249 elif p == PAGE_DEVICES:
1250 row = self.DevicesTableWidget.currentRow()
1251 self.device_uri = self.DevicesTableWidget.item(row, 0).device_uri
1252 self.mq = device.queryModelByURI(self.device_uri)
1253 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(self.device_uri)
1254 self.model = models.normalizeModelName(model).lower()
1255 self.showAddPrinterPage()
1257 elif p == PAGE_ADD_PRINTER:
1258 self.print_test_page = self.SendTestPageCheckBox.isChecked()
1259 self.print_desc = unicode(self.PrinterDescriptionLineEdit.text()).encode('utf8')
1260 self.print_location = unicode(self.PrinterLocationLineEdit.text()).encode('utf8')
1261 self.fax_setup = self.SetupFaxGroupBox.isChecked()
1262 self.fax_desc = unicode(self.FaxDescriptionLineEdit.text()).encode('utf8')
1263 self.fax_location = unicode(self.FaxLocationLineEdit.text()).encode('utf8')
1264 self.fax_name_company = unicode(self.NameCompanyLineEdit.text()).encode('utf8')
1265 self.fax_number = unicode(self.FaxNumberLineEdit.text()).encode('utf8')
1268 elif p == PAGE_REMOVE:
1269 for row in xrange(self.RemoveDevicesTableWidget.rowCount()):
1270 widget = self.RemoveDevicesTableWidget.cellWidget(row, 0)
1271 if widget.checkState() == Qt.Checked:
1272 item = self.RemoveDevicesTableWidget.item(row, 1)
1273 printer = unicode(item.data(Qt.UserRole).toString()).encode('utf-8')
1274 log.debug("Removing printer: %s" % printer)
1275 if cups.delPrinter(printer) == 0 and os.geteuid!=0 and utils.addgroup()!=[]:
1276 FailureUI(self, self.__tr("<b>Unable to delete printer queue. Could not connect to CUPS Server</b><p>Is user added to %s group(s)" %utils.list_to_string(utils.addgroup())))
1280 log.error("Invalid page!") # shouldn't happen!
1283 def BackButton_clicked(self):
1284 p = self.StackedWidget.currentIndex()
1285 if p == PAGE_DEVICES:
1287 self.showDiscoveryPage()
1289 elif p == PAGE_ADD_PRINTER:
1290 self.showDevicesPage()
1293 log.error("Invalid page!") # shouldn't happen!
1296 def CancelButton_clicked(self):
1300 def displayPage(self, page):
1301 self.StackedWidget.setCurrentIndex(page)
1302 self.updateStepText(page)
1305 def setNextButton(self, typ=BUTTON_FINISH):
1306 if typ == BUTTON_ADD_PRINTER:
1307 self.NextButton.setText(self.__tr("Add Printer"))
1308 elif typ == BUTTON_NEXT:
1309 self.NextButton.setText(self.__tr("Next >"))
1310 elif typ == BUTTON_FINISH:
1311 self.NextButton.setText(self.__tr("Finish"))
1312 elif typ == BUTTON_REMOVE:
1313 self.NextButton.setText(self.__tr("Remove"))
1316 def updateStepText(self, p):
1317 self.StepText.setText(self.__tr("Step %1 of %2").arg(p+1).arg(self.max_page+1))
1320 def __tr(self,s,c = None):
1321 return qApp.translate("SetupDialog",s,c)