1#!/usr/local/bin/python3.8
2# -*- coding: utf-8 -*-
3#
4# (c) Copyright 2001-2015 HP Development Company, L.P.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19#
20# Authors: Don Welch, Naga Samrat Chowdary Narla
21#
22
23# StdLib
24import socket
25import operator
26import subprocess
27import signal
28
29# Local
30from base.g import *
31from base import device, utils, models, pkit
32from prnt import cups
33from base.codes import *
34from .ui_utils import *
35from installer import pluginhandler
36from base.sixext import to_unicode, PY3, from_unicode_to_str
37# Qt
38try:
39    from PyQt5.QtCore import *
40    from PyQt5.QtGui import *
41except ImportError:
42    from PyQt5.QtCore import *
43    from PyQt5.QtGui import *
44    from PyQt5.QtWidgets import *
45
46
47# Ui
48from .setupdialog_base import Ui_Dialog
49from .plugindialog import PluginDialog
50from .wifisetupdialog import WifiSetupDialog, SUCCESS_CONNECTED
51
52# Fax
53try:
54    from fax import fax
55    fax_import_ok = True
56except ImportError:
57    # This can fail on Python < 2.3 due to the datetime module
58    fax_import_ok = False
59    log.warning("Fax setup disabled - Python 2.3+ required.")
60
61
62PAGE_DISCOVERY = 0
63PAGE_DEVICES = 1
64PAGE_ADD_PRINTER = 2
65PAGE_REMOVE = 3
66
67
68BUTTON_NEXT = 0
69BUTTON_FINISH = 1
70BUTTON_ADD_PRINTER = 2
71BUTTON_REMOVE = 3
72
73ADVANCED_SHOW = 0
74ADVANCED_HIDE = 1
75
76DEVICE_DESC_ALL = 0
77DEVICE_DESC_SINGLE_FUNC = 1
78DEVICE_DESC_MULTI_FUNC = 2
79
80
81class PasswordDialog(QDialog):
82    def __init__(self, prompt, parent=None, name=None, modal=0, fl=0):
83        QDialog.__init__(self, parent)
84        # Application icon
85        self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128')))
86        self.prompt = prompt
87
88        Layout= QGridLayout(self)
89        Layout.setContentsMargins(11, 11, 11, 11)
90        Layout.setSpacing(6)
91
92        self.PromptTextLabel = QLabel(self)
93        Layout.addWidget(self.PromptTextLabel,0,0,1,3)
94
95        self.UsernameTextLabel = QLabel(self)
96        Layout.addWidget(self.UsernameTextLabel,1,0)
97
98        self.UsernameLineEdit = QLineEdit(self)
99        self.UsernameLineEdit.setEchoMode(QLineEdit.Normal)
100        Layout.addWidget(self.UsernameLineEdit,1,1,1,2)
101
102        self.PasswordTextLabel = QLabel(self)
103        Layout.addWidget(self.PasswordTextLabel,2,0)
104
105        self.PasswordLineEdit = QLineEdit(self)
106        self.PasswordLineEdit.setEchoMode(QLineEdit.Password)
107        Layout.addWidget(self.PasswordLineEdit,2,1,1,2)
108
109        self.OkPushButton = QPushButton(self)
110        Layout.addWidget(self.OkPushButton,3,2)
111
112        self.languageChange()
113
114        self.resize(QSize(420,163).expandedTo(self.minimumSizeHint()))
115
116        self.OkPushButton.clicked.connect(self.accept)
117        self.PasswordLineEdit.returnPressed.connect(self.accept)
118
119    def setDefaultUsername(self, defUser, allowUsernameEdit = True):
120        self.UsernameLineEdit.setText(defUser)
121        if not allowUsernameEdit:
122            self.UsernameLineEdit.setReadOnly(True)
123            self.UsernameLineEdit.setStyleSheet("QLineEdit {background-color: lightgray}")
124
125    def getUsername(self):
126        return to_unicode(self.UsernameLineEdit.text())
127
128
129    def getPassword(self):
130        return to_unicode(self.PasswordLineEdit.text())
131
132
133    def languageChange(self):
134        self.setWindowTitle(self.__tr("HP Device Manager - Enter Username/Password"))
135        self.PromptTextLabel.setText(self.__tr(self.prompt))
136        self.UsernameTextLabel.setText(self.__tr("Username:"))
137        self.PasswordTextLabel.setText(self.__tr("Password:"))
138        self.OkPushButton.setText(self.__tr("OK"))
139
140
141    def __tr(self,s,c = None):
142        return qApp.translate("SetupDialog",s,c)
143
144
145def FailureMessageUI(prompt):
146    try:
147        dlg = PasswordDialog(prompt, None)
148        FailureUI(dlg, prompt)
149    finally:
150        pass
151
152
153def showPasswordUI(prompt, userName=None, allowUsernameEdit=True):
154    try:
155        dlg = PasswordDialog(prompt, None)
156
157        if userName != None:
158            dlg.setDefaultUsername(userName, allowUsernameEdit)
159
160        if dlg.exec_() == QDialog.Accepted:
161            return (dlg.getUsername(), dlg.getPassword())
162
163    finally:
164        pass
165
166    return ("", "")
167
168
169
170class DeviceTableWidgetItem(QTableWidgetItem):
171    def __init__(self, text, device_uri):
172        QTableWidgetItem.__init__(self, text, QTableWidgetItem.UserType)
173        self.device_uri = device_uri
174
175
176
177class SetupDialog(QDialog, Ui_Dialog):
178    def __init__(self, parent, param, jd_port, device_uri=None, remove=False):
179        QDialog.__init__(self, parent)
180        self.setupUi(self)
181
182        self.param = param
183        self.jd_port = jd_port
184        self.device_uri = device_uri
185        self.remove = remove
186
187        if device_uri:
188            log.info("Using device: %s" % device_uri)
189
190        self.initUi()
191
192        if self.remove:
193            QTimer.singleShot(0, self.showRemovePage)
194        else:
195            if self.skip_discovery:
196                self.discovery_method = 0 # SLP
197                QTimer.singleShot(0, self.showDevicesPage)
198            else:
199                QTimer.singleShot(0, self.showDiscoveryPage)
200
201        cups.setPasswordCallback(showPasswordUI)
202
203
204    #
205    # INIT
206    #
207
208    def initUi(self):
209        self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128')))
210
211        # connect signals/slots
212        self.CancelButton.clicked.connect(self.CancelButton_clicked)
213        self.BackButton.clicked.connect(self.BackButton_clicked)
214        self.NextButton.clicked.connect(self.NextButton_clicked)
215        self.ManualGroupBox.clicked.connect(self.ManualGroupBox_clicked)
216        signal.signal(signal.SIGINT, signal.SIG_DFL)
217
218        if self.remove:
219            self.initRemovePage()
220            self.max_page = 1
221        else:
222            self.initDiscoveryPage()
223            self.initDevicesPage()
224            self.initAddPrinterPage()
225            self.max_page = PAGE_ADD_PRINTER
226
227    #
228    #  DISCOVERY PAGE
229    #
230
231    def initDiscoveryPage(self):
232        self.UsbRadioButton.setChecked(True)
233        self.setUsbRadioButton(True)
234        self.ManualGroupBox.setChecked(False)
235
236        self.advanced = False
237        self.manual = False
238        self.skip_discovery = False
239        self.discovery_method = 0
240        self.NetworkRadioButton.setEnabled(prop.net_build)
241        self.WirelessButton.setEnabled(prop.net_build)
242        self.ParallelRadioButton.setEnabled(prop.par_build)
243        self.devices = {}
244        self.bus = 'usb'
245        self.timeout = 5
246        self.ttl = 4
247        self.search = ''
248        self.print_test_page = False
249        self.device_desc = DEVICE_DESC_ALL
250
251        if self.param:
252            log.info("Searching for device...")
253            self.manual = True
254            self.advanced = True
255            self.ManualParamLineEdit.setText(self.param)
256            self.JetDirectSpinBox.setValue(self.jd_port)
257            self.ManualGroupBox.setChecked(True)
258            self.DiscoveryOptionsGroupBox.setEnabled(False)
259
260            if self.manualDiscovery():
261                self.skip_discovery = True
262            else:
263                FailureUI(self, self.__tr("<b>Device not found.</b> <p>Please make sure your printer is properly connected and powered-on."))
264
265                match = device.usb_pat.match(self.param)
266                if match is not None:
267                    self.UsbRadioButton.setChecked(True)
268                    self.setUsbRadioButton(True)
269
270                else:
271                    match = device.dev_pat.match(self.param)
272                    if match is not None and prop.par_build:
273                        self.ParallelRadioButton.setChecked(True)
274                        self.setParallelRadioButton(True)
275
276                    else:
277                        match = device.ip_pat.match(self.param)
278                        if match is not None and prop.net_build:
279                            self.NetworkRadioButton.setChecked(True)
280                            self.setNetworkRadioButton(True)
281
282                        else:
283                            FailureUI(self, self.__tr("<b>Invalid manual discovery parameter.</b>"))
284
285        elif self.device_uri: # If device URI specified on the command line, skip discovery
286                              # if the device URI is well-formed (but not necessarily valid)
287            try:
288                back_end, is_hp, self.bus, model, serial, dev_file, host, zc, port = \
289                device.parseDeviceURI(self.device_uri)
290
291            except Error:
292                log.error("Invalid device URI specified: %s" % self.device_uri)
293
294            else:
295                name = host
296                if self.bus == 'net':
297                    try:
298                        log.debug("Trying to get hostname for device...")
299                        name = socket.gethostbyaddr(host)[0]
300                    except socket.herror:
301                        log.debug("Failed.")
302                    else:
303                        log.debug("Host name=%s" % name)
304
305                self.devices = {self.device_uri : (model, model, name)}
306                self.skip_discovery = True
307
308        # If no network or parallel, usb is only option, skip initial page...
309        elif not prop.par_build and not prop.net_build:
310            self.skip_discovery = True
311            self.bus = 'usb'
312            self.UsbRadioButton.setChecked(True)
313            self.setUsbRadioButton(True)
314
315        if prop.fax_build and prop.scan_build:
316            self.DeviceTypeComboBox.addItem("All devices/printers", DEVICE_DESC_ALL)
317            self.DeviceTypeComboBox.addItem("Single function printers only", DEVICE_DESC_SINGLE_FUNC)
318            self.DeviceTypeComboBox.addItem("All-in-one/MFP devices only", DEVICE_DESC_MULTI_FUNC)
319        else:
320            self.DeviceTypeComboBox.setEnabled(False)
321
322        self.AdvancedButton.clicked.connect(self.AdvancedButton_clicked)
323        self.UsbRadioButton.toggled.connect(self.UsbRadioButton_toggled)
324        self.NetworkRadioButton.toggled.connect(self.NetworkRadioButton_toggled)
325        self.WirelessButton.toggled.connect(self.WirelessButton_toggled)
326        self.ParallelRadioButton.toggled.connect(self.ParallelRadioButton_toggled)
327        self.NetworkTTLSpinBox.valueChanged.connect(self.NetworkTTLSpinBox_valueChanged)
328        self.NetworkTimeoutSpinBox.valueChanged.connect(self.NetworkTimeoutSpinBox_valueChanged)
329        self.ManualGroupBox.toggled.connect(self.ManualGroupBox_toggled)
330
331        self.showAdvanced()
332
333
334    def ManualGroupBox_toggled(self, checked):
335        self.DiscoveryOptionsGroupBox.setEnabled(not checked)
336
337
338    def manualDiscovery(self):
339        # Validate param...
340        device_uri, sane_uri, fax_uri = device.makeURI(self.param, self.jd_port)
341
342        if device_uri:
343            log.info("Found device: %s" % device_uri)
344            back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
345                device.parseDeviceURI(device_uri)
346
347            name = host
348            if bus == 'net':
349                try:
350                    if device.ip_pat.search(name) is not None:
351                        log.debug("Getting host name from IP address (%s)" % name)
352                        name = socket.gethostbyaddr(host)[0]
353                except (socket.herror, socket.gaierror):
354                    pass
355
356            self.devices = {device_uri : (model, model, name)}
357
358            if bus == 'usb':
359                self.UsbRadioButton.setChecked(True)
360                self.setUsbRadioButton(True)
361
362            elif bus == 'net' and prop.net_build:
363                self.NetworkRadioButton.setChecked(True)
364                self.setNetworkRadioButton(True)
365
366            elif bus == 'par' and prop.par_build:
367                self.ParallelRadioButton.setChecked(True)
368                self.setParallelRadioButton(True)
369
370            return True
371
372
373        return False
374
375
376    def ManualGroupBox_clicked(self, checked):
377        self.manual = checked
378        network = self.NetworkRadioButton.isChecked()
379        self.setJetDirect(network)
380
381
382    def showDiscoveryPage(self):
383        self.BackButton.setEnabled(False)
384        self.NextButton.setEnabled(True)
385        self.setNextButton(BUTTON_NEXT)
386        self.displayPage(PAGE_DISCOVERY)
387
388
389    def AdvancedButton_clicked(self):
390        self.advanced = not self.advanced
391        self.showAdvanced()
392
393
394    def showAdvanced(self):
395        if self.advanced:
396            self.AdvancedStackedWidget.setCurrentIndex(ADVANCED_SHOW)
397            self.AdvancedButton.setText(self.__tr("Hide Advanced Options"))
398            self.AdvancedButton.setIcon(QIcon(load_pixmap("minus", "16x16")))
399        else:
400            self.AdvancedStackedWidget.setCurrentIndex(ADVANCED_HIDE)
401            self.AdvancedButton.setText(self.__tr("Show Advanced Options"))
402            self.AdvancedButton.setIcon(QIcon(load_pixmap("plus", "16x16")))
403
404
405    def setJetDirect(self, enabled):
406        self.JetDirectLabel.setEnabled(enabled and self.manual)
407        self.JetDirectSpinBox.setEnabled(enabled and self.manual)
408
409
410    def setNetworkOptions(self,  enabled):
411        self.NetworkTimeoutLabel.setEnabled(enabled)
412        self.NetworkTimeoutSpinBox.setEnabled(enabled)
413        self.NetworkTTLLabel.setEnabled(enabled)
414        self.NetworkTTLSpinBox.setEnabled(enabled)
415
416
417    def setSearchOptions(self, enabled):
418        self.SearchLineEdit.setEnabled(enabled)
419        self.DeviceTypeComboBox.setEnabled(enabled)
420        self.DeviceTypeLabel.setEnabled(enabled)
421
422
423    def setManualDiscovery(self, enabled):
424        self.ManualGroupBox.setEnabled(enabled)
425
426
427    def setNetworkDiscovery(self, enabled):
428        self.NetworkDiscoveryMethodLabel.setEnabled(enabled)
429        self.NetworkDiscoveryMethodComboBox.setEnabled(enabled)
430        self.NetworkDiscoveryMethodComboBox.setCurrentIndex(0)
431
432
433    def UsbRadioButton_toggled(self, radio_enabled):
434        self.setUsbRadioButton(radio_enabled)
435
436
437    def setUsbRadioButton(self, checked):
438        self.setNetworkDiscovery(not checked)
439        self.setJetDirect(not checked)
440        self.setNetworkOptions(not checked)
441        self.setSearchOptions(checked)
442        self.setManualDiscovery(checked)
443
444        if checked:
445            self.ManualParamLabel.setText(self.__tr("USB bus ID:device ID (bbb:ddd):"))
446            self.bus = 'usb'
447            # TODO: Set bbb:ddd validator
448
449
450    def NetworkRadioButton_toggled(self, radio_enabled):
451        self.setNetworkRadioButton(radio_enabled)
452
453
454    def setNetworkRadioButton(self, checked):
455        self.setNetworkDiscovery(checked)
456        self.setJetDirect(checked)
457        self.setNetworkOptions(checked)
458        self.setSearchOptions(checked)
459        self.setManualDiscovery(checked)
460
461
462        if checked:
463            self.ManualParamLabel.setText(self.__tr("IP Address or network name:"))
464            self.bus = 'net'
465            # TODO: Reset validator
466
467    def WirelessButton_toggled(self, radio_enabled):
468        self.setWirelessButton(radio_enabled)
469
470
471    def setWirelessButton(self, checked):
472        self.setNetworkDiscovery(not checked)
473        self.setJetDirect(not checked)
474        self.setNetworkOptions(not checked)
475        self.setSearchOptions(not checked)
476        self.setManualDiscovery(not checked)
477
478
479        if checked:
480            self.ManualParamLabel.setText(self.__tr("IP Address or network name:"))
481            self.bus = 'net'
482
483
484    def ParallelRadioButton_toggled(self, radio_enabled):
485        self.setParallelRadioButton(radio_enabled)
486
487
488    def setParallelRadioButton(self, checked):
489        self.setNetworkDiscovery(not checked)
490        self.setJetDirect(not checked)
491        self.setNetworkOptions(not checked)
492        self.setSearchOptions(not checked)
493        self.setManualDiscovery(not checked)
494
495
496        if checked:
497            self.ManualParamLabel.setText(self.__tr("Device node (/dev/...):"))
498            self.bus = 'par'
499            # TODO: Set /dev/... validator
500
501
502    def NetworkTTLSpinBox_valueChanged(self, ttl):
503        self.ttl = ttl
504
505
506    def NetworkTimeoutSpinBox_valueChanged(self, timeout):
507        self.timeout = timeout
508
509    #
510    # DEVICES PAGE
511    #
512
513    def initDevicesPage(self):
514        self.RefreshButton.clicked.connect(self.RefreshButton_clicked)
515
516
517    def showDevicesPage(self):
518        self.BackButton.setEnabled(True)
519        self.setNextButton(BUTTON_NEXT)
520        search = ""
521
522        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
523        try:
524            if not self.devices:
525                if self.manual and self.param: # manual, but not passed-in on command line
526                    self.manualDiscovery()
527
528                else: # probe
529                    net_search_type = ''
530
531                    if self.bus == 'net':
532                        if self.discovery_method == 0:
533                            net_search_type = "slp"
534                        elif self.discovery_method == 1:
535                            net_search_type = "mdns"
536                        else:
537                            net_search_type = "avahi"
538
539                        log.info("Searching... (bus=%s, timeout=%d, ttl=%d, search=%s desc=%d, method=%s)" %
540                                 (self.bus,  self.timeout, self.ttl, self.search or "(None)",
541                                  self.device_desc, net_search_type))
542                    else:
543                        log.info("Searching... (bus=%s, search=%s, desc=%d)" %
544                                 (self.bus,  self.search or "(None)", self.device_desc))
545
546                    if self.device_desc == DEVICE_DESC_SINGLE_FUNC:
547                        filter_dict = {'scan-type' : (operator.le, SCAN_TYPE_NONE)}
548
549                    elif self.device_desc == DEVICE_DESC_MULTI_FUNC:
550                        filter_dict = {'scan-type': (operator.gt, SCAN_TYPE_NONE)}
551
552                    else: # DEVICE_DESC_ALL
553                        filter_dict = {}
554
555                    if self.bus == 'usb':
556                        try:
557                            from base import smart_install
558                        except ImportError:
559                            log.error("Failed to Import smart_install.py from base")
560                        else:   #if no Smart Install device found, ignores.
561                            QApplication.restoreOverrideCursor()
562                            smart_install.disable(GUI_MODE, 'qt4')
563                            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
564
565                    self.devices = device.probeDevices([self.bus], self.timeout, self.ttl,
566                                                       filter_dict, self.search, net_search=net_search_type)
567
568        finally:
569            QApplication.restoreOverrideCursor()
570
571        self.clearDevicesTable()
572
573        if self.devices:
574            self.NextButton.setEnabled(True)
575            self.DevicesFoundIcon.setPixmap(load_pixmap('info', '16x16'))
576
577            if len(self.devices) == 1:
578                self.DevicesFoundLabel.setText(self.__tr("<b>1 device found.</b> Click <i>Next</i> to continue."))
579            else:
580                self.DevicesFoundLabel.setText(self.__tr("<b>%s devices found.</b> Select the device to install and click <i>Next</i> to continue."%(len(self.devices))))
581
582            self.loadDevicesTable()
583
584        else:
585            self.NextButton.setEnabled(False)
586            self.DevicesFoundIcon.setPixmap(load_pixmap('error', '16x16'))
587            log.error("No devices found on bus: %s" % self.bus)
588            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."))
589            if self.bus == 'net' and utils.check_lan():
590                FailureUI(self, self.__tr('''<b>HPLIP cannot detect printers in your network.</b><p>This may be due to existing firewall settings blocking the required ports.
591                When you are in a trusted network environment, you may open the ports for network services like mdns and slp in the firewall. For detailed steps follow the link.
592                <b>http://hplipopensource.com/node/374</b></p>'''),
593                        self.__tr("HP Device Manager"))
594
595
596        self.displayPage(PAGE_DEVICES)
597
598
599    def loadDevicesTable(self):
600        self.DevicesTableWidget.setRowCount(len(self.devices))
601
602        if self.bus == 'net':
603            if self.discovery_method == 0:
604                headers = [self.__tr('Model'), self.__tr('IP Address'), self.__tr('Host Name'), self.__tr('Device URI')]
605                device_uri_col = 3
606            else:
607                headers = [self.__tr('Model'), self.__tr('Host Name'), self.__tr('Device URI')]
608                device_uri_col = 2
609        else:
610            headers = [self.__tr('Model'), self.__tr('Device URI')]
611            device_uri_col = 1
612
613        self.DevicesTableWidget.setColumnCount(len(headers))
614        self.DevicesTableWidget.setHorizontalHeaderLabels(headers)
615        flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
616
617        for row, d in enumerate(self.devices):
618            back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(d)
619            model_ui = models.normalizeModelUIName(model)
620
621            i = DeviceTableWidgetItem(str(model_ui), d)
622            i.setFlags(flags)
623            self.DevicesTableWidget.setItem(row, 0, i)
624
625            i = QTableWidgetItem(str(d))
626            i.setFlags(flags)
627            self.DevicesTableWidget.setItem(row, device_uri_col, i)
628
629            if self.bus == 'net':
630                i = QTableWidgetItem(str(host))
631                i.setFlags(flags)
632                self.DevicesTableWidget.setItem(row, 1, i)
633
634                if self.discovery_method == 0:
635                    i = QTableWidgetItem(str(self.devices[d][2]))
636                    i.setFlags(flags)
637                    self.DevicesTableWidget.setItem(row, 2, i)
638
639        self.DevicesTableWidget.resizeColumnsToContents()
640        self.DevicesTableWidget.selectRow(0)
641        self.DevicesTableWidget.setSortingEnabled(True)
642        self.DevicesTableWidget.sortItems(0)
643
644
645    def clearDevicesTable(self):
646        self.DevicesTableWidget.clear()
647        self.DevicesTableWidget.setRowCount(0)
648        self.DevicesTableWidget.setColumnCount(0)
649
650
651    def RefreshButton_clicked(self):
652        self.clearDevicesTable()
653        self.devices = []
654        QTimer.singleShot(0, self.showDevicesPage)
655
656    #
657    # ADD PRINTER PAGE
658    #
659
660    def initAddPrinterPage(self):
661        self.mq = {}
662
663        self.PrinterNameLineEdit.textEdited.connect(self.PrinterNameLineEdit_textEdited)
664
665        self.FaxNameLineEdit.textEdited.connect(self.FaxNameLineEdit_textEdited)
666
667        self.SetupPrintGroupBox.clicked.connect(self.SetupPrintGroupBox_clicked)
668        self.SetupFaxGroupBox.clicked.connect(self.SetupFaxGroupBox_clicked)
669        self.PrinterNameLineEdit.setValidator(PrinterNameValidator(self.PrinterNameLineEdit))
670        self.FaxNameLineEdit.setValidator(PrinterNameValidator(self.FaxNameLineEdit))
671        self.FaxNumberLineEdit.setValidator(PhoneNumValidator(self.FaxNumberLineEdit))
672        self.OtherPPDButton.setIcon(QIcon(load_pixmap('folder_open', '16x16')))
673        self.OtherPPDButton.clicked.connect(self.OtherPPDButton_clicked)
674
675        self.OtherPPDButton.setToolTip(self.__tr("Browse for an alternative PPD file for this printer."))
676
677        self.printer_fax_names_same = False
678        self.printer_name = ''
679        self.fax_name = ''
680        self.fax_setup_ok = True
681        self.fax_setup = False
682        self.print_setup = False
683
684
685    def showAddPrinterPage(self):
686        # Install the plugin if needed...
687        pluginObj = pluginhandler.PluginHandle()
688        plugin = self.mq.get('plugin', PLUGIN_NONE)
689        plugin_reason = self.mq.get('plugin-reason', PLUGIN_REASON_NONE)
690        if plugin > PLUGIN_NONE:
691
692            if pluginObj.getStatus() != pluginhandler.PLUGIN_INSTALLED:
693                ok, sudo_ok = pkit.run_plugin_command(plugin == PLUGIN_REQUIRED, plugin_reason)
694                if not sudo_ok:
695                    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>"))
696                    return
697                if not ok or pluginObj.getStatus() != pluginhandler.PLUGIN_INSTALLED:
698                    if plugin == PLUGIN_REQUIRED:
699                        FailureUI(self, self.__tr("<b>The device you are trying to setup requires a binary plug-in. Some functionalities may not work as expected without plug-ins.<p> Please run 'hp-plugin' as normal user to install plug-ins.</b></p><p>Visit <u>http://hplipopensource.com</u> for more infomation.</p>"))
700                        return
701                    else:
702                        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."))
703
704        self.setNextButton(BUTTON_ADD_PRINTER)
705        self.print_setup = self.setDefaultPrinterName()
706        if self.print_setup:
707            self.SetupPrintGroupBox.setCheckable(True)
708            self.SetupPrintGroupBox.setEnabled(True)
709            self.SendTestPageCheckBox.setCheckable(True)
710            self.SendTestPageCheckBox.setEnabled(True)
711            self.findPrinterPPD()
712            self.updatePPD()
713        else:
714            self.print_ppd = None
715            self.SetupPrintGroupBox.setCheckable(False)
716            self.SetupPrintGroupBox.setEnabled(False)
717            self.SendTestPageCheckBox.setCheckable(False)
718            self.SendTestPageCheckBox.setEnabled(False)
719
720        if fax_import_ok and prop.fax_build and \
721            self.mq.get('fax-type', FAX_TYPE_NONE) not in (FAX_TYPE_NONE, FAX_TYPE_NOT_SUPPORTED):
722            self.fax_setup = True
723            self.SetupFaxGroupBox.setChecked(True)
724            self.SetupFaxGroupBox.setEnabled(True)
725
726            self.fax_setup = self.setDefaultFaxName()
727            if self.fax_setup:
728                self.findFaxPPD()
729                self.readwriteFaxInformation()
730            else:
731                self.fax_setup = False
732                self.SetupFaxGroupBox.setChecked(False)
733                self.SetupFaxGroupBox.setEnabled(False)
734
735        else:
736            self.SetupFaxGroupBox.setChecked(False)
737            self.SetupFaxGroupBox.setEnabled(False)
738            self.fax_name = ''
739            self.fax_name_ok = True
740            self.fax_setup = False
741            self.fax_setup_ok = True
742
743
744
745        if self.print_setup or self.fax_setup:
746            self.setAddPrinterButton()
747            self.displayPage(PAGE_ADD_PRINTER)
748        else:
749            log.info("Exiting the setup...")
750            self.close()
751
752
753
754
755    def updatePPD(self):
756        if self.print_ppd is None:
757            log.error("No appropriate print PPD file found for model %s" % self.model)
758            self.PPDFileLineEdit.setText(self.__tr('(Not found. Click browse button to select a PPD file.)'))
759            try:
760                self.PPDFileLineEdit.setStyleSheet("background-color: yellow")
761            except AttributeError:
762                pass
763            self.PrinterDescriptionLineEdit.setText(str(""))
764
765        else:
766            self.PPDFileLineEdit.setText(self.print_ppd[0])
767            self.PrinterDescriptionLineEdit.setText(self.print_ppd[1])
768            try:
769                self.PPDFileLineEdit.setStyleSheet("")
770            except AttributeError:
771                pass
772
773
774    def OtherPPDButton_clicked(self, b):
775        ppd_file = to_unicode(QFileDialog.getOpenFileName(self, self.__tr("Select PPD File"),
776                                                       sys_conf.get('dirs', 'ppd'),
777                                                       self.__tr("PPD Files (*.ppd *.ppd.gz);;All Files (*)")))
778
779        if ppd_file and os.path.exists(ppd_file):
780            self.print_ppd = (ppd_file, cups.getPPDDescription(ppd_file))
781            self.updatePPD()
782            self.setAddPrinterButton()
783
784
785    def findPrinterPPD(self):
786        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
787        try:
788            self.print_ppd = None
789            self.ppds = cups.getSystemPPDs()
790            self.print_ppd = cups.getPPDFile2(self.mq, self.model, self.ppds)
791            if "scanjet" in self.model or "digital_sender" in self.model:
792                self.print_ppd = None
793
794        finally:
795            QApplication.restoreOverrideCursor()
796
797
798    def findFaxPPD(self):
799        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
800        try:
801            self.fax_ppd, fax_ppd_name, nick = cups.getFaxPPDFile(self.mq, self.model)
802            if self.fax_ppd:
803                self.fax_setup_ok = True
804            else:
805                self.fax_setup_ok = False
806                FailureUI(self, self.__tr("<b>Unable to locate the HPLIP Fax PPD file:</b><p>%s.ppd.gz</p><p>Fax setup has been disabled."%fax_ppd_name))
807                self.fax_setup = False
808                self.SetupFaxGroupBox.setChecked(False)
809                self.SetupFaxGroupBox.setEnabled(False)
810        finally:
811            QApplication.restoreOverrideCursor()
812
813
814    def setDefaultPrinterName(self):
815        self.installed_print_devices = device.getSupportedCUPSDevices(['hp'])
816        log.debug(self.installed_print_devices)
817
818        self.installed_queues = [p.name for p in cups.getPrinters()]
819
820        back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(self.device_uri)
821        default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_')
822
823        printer_name = default_model
824        installed_printer_names = device.getSupportedCUPSPrinterNames(['hp'])
825        # Check for duplicate names
826        if (self.device_uri in self.installed_print_devices and printer_name in self.installed_print_devices[self.device_uri]) \
827           or (printer_name in installed_printer_names):
828            warn_text = self.__tr("<b>One or more print queues already exist for this device: %s</b>.<br> <b>Would you like to install another print queue for this device ?</b>" %
829                    ', '.join([printer for printer in installed_printer_names if printer_name in printer]))
830            if ( QMessageBox.warning(self,
831                                self.windowTitle(),
832                                warn_text,
833                                QMessageBox.Yes|\
834                                QMessageBox.No,
835                                QMessageBox.NoButton) == QMessageBox.Yes ):
836
837                i = 2
838                while True:
839                    t = printer_name + "_%d" % i
840                    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]):
841                        printer_name += "_%d" % i
842                        break
843                    i += 1
844            else:
845                self.printer_name_ok = False
846                return False
847
848        self.printer_name_ok = True
849        self.PrinterNameLineEdit.setText(printer_name)
850        log.debug(printer_name)
851        self.printer_name = printer_name
852        return True
853
854
855    def setDefaultFaxName(self):
856        self.installed_fax_devices = device.getSupportedCUPSDevices(['hpfax'])
857        log.debug(self.installed_fax_devices)
858
859        self.fax_uri = self.device_uri.replace('hp:', 'hpfax:')
860
861        back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(self.fax_uri)
862        default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_')
863
864        fax_name = default_model + "_fax"
865        installed_fax_names = device.getSupportedCUPSPrinterNames(['hpfax'])
866        # Check for duplicate names
867        if (self.fax_uri in self.installed_fax_devices and fax_name in self.installed_fax_devices[self.fax_uri]) \
868           or (fax_name in installed_fax_names):
869            warn_text = self.__tr(
870                "<b>One or more fax queues already exist for this device: %s</b>.<br> <b>Would you like to install another fax queue for this device ?</b>" %
871                ', '.join([fax_device for fax_device in installed_fax_names if fax_name in fax_device]))
872            if ( QMessageBox.warning(self,
873                                 self.windowTitle(),
874                                 warn_text,
875                                 QMessageBox.Yes|\
876                                 QMessageBox.No|\
877                                 QMessageBox.NoButton) == QMessageBox.Yes ):
878                i = 2
879                while True:
880                    t = fax_name + "_%d" % i
881                    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]):
882                        fax_name += "_%d" % i
883                        break
884                    i += 1
885            else:
886                self.fax_name_ok = False
887                return False
888
889        self.fax_name_ok = True
890        self.FaxNameLineEdit.setText(fax_name)
891        self.fax_name = fax_name
892        return True
893
894
895    def PrinterNameLineEdit_textEdited(self, t):
896        self.printer_name = to_unicode(t)
897        self.printer_name_ok = True
898
899        if not self.printer_name:
900            self.PrinterNameLineEdit.setToolTip(self.__tr('You must enter a name for the printer.'))
901            self.printer_name_ok = False
902
903        elif self.fax_name == self.printer_name:
904            s = self.__tr('The printer name and fax name must be different. Please choose different names.')
905            self.PrinterNameLineEdit.setToolTip(s)
906            self.FaxNameLineEdit.setToolTip(s)
907            self.fax_name_ok = False
908            self.printer_name_ok = False
909            self.printer_fax_names_same = True
910
911        elif self.printer_name in self.installed_queues:
912            self.PrinterNameLineEdit.setToolTip(self.__tr('A printer already exists with this name. Please choose a different name.'))
913            self.printer_name_ok = False
914
915        elif self.printer_fax_names_same:
916            if self.fax_name != self.printer_name:
917                self.printer_fax_names_same = False
918                self.printer_name_ok = True
919
920                self.FaxNameLineEdit.emit(SIGNAL("textEdited(const QString &)"),
921                            self.FaxNameLineEdit.text())
922
923        self.setIndicators()
924        self.setAddPrinterButton()
925
926
927    def FaxNameLineEdit_textEdited(self, t):
928        self.fax_name = to_unicode(t)
929        self.fax_name_ok = True
930
931        if not self.fax_name:
932            self.FaxNameLineEdit.setToolTip(self.__tr('You must enter a fax name.'))
933            self.fax_name_ok = False
934
935        elif self.fax_name == self.printer_name:
936            s = self.__tr('The printer name and fax name must be different. Please choose different names.')
937            self.PrinterNameLineEdit.setToolTip(s)
938            self.FaxNameLineEdit.setToolTip(s)
939            self.printer_name_ok = False
940            self.fax_name_ok = False
941            self.printer_fax_names_same = True
942
943        elif self.fax_name in self.installed_queues:
944            self.FaxNameLineEdit.setToolTip(self.__tr('A fax already exists with this name. Please choose a different name.'))
945            self.fax_name_ok = False
946
947        elif self.printer_fax_names_same:
948            if self.fax_name != self.printer_name:
949                self.printer_fax_names_same = False
950                self.fax_name_ok = True
951
952                self.PrinterNameLineEdit.emit(SIGNAL("textEdited(const QString&)"),
953                            self.PrinterNameLineEdit.text())
954
955        self.setIndicators()
956        self.setAddPrinterButton()
957
958    def SetupPrintGroupBox_clicked(self):
959        if not self.SetupPrintGroupBox.isChecked():
960            self.SendTestPageCheckBox.setCheckable(False)
961            self.SendTestPageCheckBox.setEnabled(False)
962        else:
963            self.SendTestPageCheckBox.setCheckable(True)
964            self.SendTestPageCheckBox.setEnabled(True)
965        self.setAddPrinterButton()
966
967    def SetupFaxGroupBox_clicked(self):
968        self.setAddPrinterButton()
969
970
971    def setIndicators(self):
972        if self.printer_name_ok:
973            self.PrinterNameLineEdit.setToolTip(str(""))
974            try:
975                self.PrinterNameLineEdit.setStyleSheet("")
976            except AttributeError:
977                pass
978        else:
979            try:
980                self.PrinterNameLineEdit.setStyleSheet("background-color: yellow")
981            except AttributeError:
982                pass
983
984        if self.fax_name_ok:
985            self.FaxNameLineEdit.setToolTip(str(""))
986            try:
987                self.PrinterNameLineEdit.setStyleSheet("")
988            except AttributeError:
989                pass
990        else:
991            try:
992                self.PrinterNameLineEdit.setStyleSheet("background-color: yellow")
993            except AttributeError:
994                pass
995
996
997    def setAddPrinterButton(self):
998        if self.SetupPrintGroupBox.isChecked() or self.SetupFaxGroupBox.isChecked():
999            self.NextButton.setEnabled((self.print_setup and self.printer_name_ok and self.print_ppd is not None) or
1000                                   (self.fax_setup and self.fax_name_ok))
1001        else:
1002            self.NextButton.setEnabled(False)
1003
1004
1005    #
1006    # ADD PRINTER
1007    #
1008
1009    def addPrinter(self):
1010        if self.print_setup:
1011            print_sts = self.setupPrinter()
1012            if print_sts == cups.IPP_FORBIDDEN or print_sts == cups.IPP_NOT_AUTHENTICATED or print_sts == cups.IPP_NOT_AUTHORIZED:
1013                pass  # User doesn't have sufficient permissions so ignored.
1014            if print_sts == cups.IPP_OK:
1015                self.flashFirmware()
1016            if self.print_test_page:
1017                self.printTestPage()
1018
1019        if self.fax_setup:
1020            if self.setupFax() == cups.IPP_OK:
1021                self.readwriteFaxInformation(False)
1022
1023        self.close()
1024
1025
1026    #
1027    # Updating firmware download for supported devices.
1028    #
1029    def flashFirmware(self):
1030        if self.mq.get('fw-download', False):
1031            try:
1032                d = device.Device(self.device_uri)
1033            except Error as e:
1034                FailureUI(self, self.__tr("<b>Error opening device. Firmware download is Failed.</b><p>%s (%s)." % (e.msg, e.opt)))
1035            else:
1036                if d.downloadFirmware():
1037                    log.info("Firmware download successful.\n")
1038                else:
1039                    FailureUI(self, self.__tr("<b>Firmware download is Failed.</b>"))
1040                d.close()
1041
1042    #
1043    # SETUP PRINTER/FAX
1044    #
1045
1046    def setupPrinter(self):
1047        status = cups.IPP_BAD_REQUEST
1048        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
1049        try:
1050            if not os.path.exists(self.print_ppd[0]): # assume foomatic: or some such
1051                add_prnt_args = (from_unicode_to_str(self.printer_name), self.device_uri, self.print_location, '', self.print_ppd[0], self.print_desc)
1052            else:
1053                add_prnt_args = (from_unicode_to_str(self.printer_name), self.device_uri, self.print_location, self.print_ppd[0], '', self.print_desc)
1054
1055            status, status_str = cups.cups_operation(cups.addPrinter, GUI_MODE, 'qt4', self, *add_prnt_args)
1056            log.debug(device.getSupportedCUPSDevices(['hp']))
1057
1058            if status != cups.IPP_OK:
1059                QApplication.restoreOverrideCursor()
1060                FailureUI(self, self.__tr("<b>Printer queue setup failed.</b> <p>Error : %s"%status_str))
1061            else:
1062                # sending Event to add this device in hp-systray
1063                utils.sendEvent(EVENT_CUPS_QUEUES_ADDED,self.device_uri, self.printer_name)
1064
1065        finally:
1066            QApplication.restoreOverrideCursor()
1067        return status
1068
1069
1070    def setupFax(self):
1071        status = cups.IPP_BAD_REQUEST
1072        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
1073        try:
1074            if not os.path.exists(self.fax_ppd):
1075                status, status_str = cups.addPrinter(self.fax_name,
1076                    self.fax_uri, self.fax_location, '', self.fax_ppd,  self.fax_desc)
1077            else:
1078                status, status_str = cups.addPrinter(self.fax_name,
1079                    self.fax_uri, self.fax_location, self.fax_ppd, '', self.fax_desc)
1080
1081            log.debug(device.getSupportedCUPSDevices(['hpfax']))
1082
1083            if status != cups.IPP_OK:
1084                QApplication.restoreOverrideCursor()
1085                FailureUI(self, self.__tr("<b>Fax queue setup failed.</b><p>Error : %s"%status_str))
1086            else:
1087                 # sending Event to add this device in hp-systray
1088                utils.sendEvent(EVENT_CUPS_QUEUES_ADDED,self.fax_uri, self.fax_name)
1089
1090        finally:
1091            QApplication.restoreOverrideCursor()
1092
1093        return status
1094
1095
1096    def readwriteFaxInformation(self, read=True):
1097        try:
1098            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
1099
1100            d = fax.getFaxDevice(self.fax_uri, disable_dbus=True)
1101
1102            while True:
1103                try:
1104                    d.open()
1105                except Error:
1106                    error_text = self.__tr("Unable to communicate with the device. Please check the device and try again.")
1107                    log.error(to_unicode(error_text))
1108                    if QMessageBox.critical(self,
1109                                           self.windowTitle(),
1110                                           error_text,
1111                                           QMessageBox.Retry | QMessageBox.Default,
1112                                           QMessageBox.Cancel | QMessageBox.Escape,
1113                                           QMessageBox.NoButton) == QMessageBox.Cancel:
1114                        break
1115
1116                else:
1117                    try:
1118                        tries = 0
1119                        ok = True
1120
1121                        while True:
1122                            tries += 1
1123
1124                            try:
1125                                if read:
1126                                    #self.fax_number = str(d.getPhoneNum())
1127                                    #self.fax_name_company = str(d.getStationName())
1128                                    self.fax_number = to_unicode(d.getPhoneNum())
1129                                    self.fax_name_company = to_unicode(d.getStationName())
1130                                else:
1131                                    d.setStationName(self.fax_name_company)
1132                                    d.setPhoneNum(self.fax_number)
1133
1134                            except Error:
1135                                error_text = self.__tr("<b>Device I/O Error</b><p>Could not communicate with device. Device may be busy.")
1136                                log.error(to_unicode(error_text))
1137
1138                                if QMessageBox.critical(self,
1139                                                       self.windowTitle(),
1140                                                       error_text,
1141                                                       QMessageBox.Retry | QMessageBox.Default,
1142                                                       QMessageBox.Cancel | QMessageBox.Escape,
1143                                                       QMessageBox.NoButton) == QMessageBox.Cancel:
1144                                    break
1145
1146
1147                                time.sleep(5)
1148                                ok = False
1149
1150                                if tries > 12:
1151                                    break
1152
1153                            else:
1154                                ok = True
1155                                break
1156
1157                    finally:
1158                        d.close()
1159
1160                    if ok and read:
1161                        self.FaxNumberLineEdit.setText(self.fax_number)
1162                        self.NameCompanyLineEdit.setText(self.fax_name_company)
1163
1164                    break
1165
1166        finally:
1167            QApplication.restoreOverrideCursor()
1168
1169
1170    def printTestPage(self):
1171        try:
1172            d = device.Device(self.device_uri)
1173        except Error as e:
1174            FailureUI(self, self.__tr("<b>Device error:</b><p>%s (%s)." % (e.msg, e.opt)))
1175
1176        else:
1177            try:
1178                d.open()
1179            except Error:
1180                FailureUI(self, self.__tr("<b>Unable to print to printer.</b><p>Please check device and try again."))
1181            else:
1182                if d.isIdleAndNoError():
1183                    d.close()
1184
1185                    try:
1186                        d.printTestPage(self.printer_name)
1187                    except Error as e:
1188                        if e.opt == ERROR_NO_CUPS_QUEUE_FOUND_FOR_DEVICE:
1189                            FailureUI(self, self.__tr("<b>No CUPS queue found for device.</b><p>Please install the printer in CUPS and try again."))
1190                        else:
1191                            FailureUI(self, self.__tr("<b>Printer Error</b><p>An error occured: %s (code=%d)." % (e.msg, e.opt)))
1192                else:
1193                    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."))
1194                    d.close()
1195
1196    #
1197    # Remove Page
1198    #
1199
1200    def initRemovePage(self):
1201        pass
1202
1203
1204    def showRemovePage(self):
1205        self.displayPage(PAGE_REMOVE)
1206        self.StepText.setText(self.__tr("Step 1 of 1"))
1207        self.setNextButton(BUTTON_REMOVE)
1208        self.BackButton.setEnabled(False)
1209        self.NextButton.setEnabled(False)
1210
1211        self.RemoveDevicesTableWidget.verticalHeader().hide()
1212
1213        self.installed_printers = device.getSupportedCUPSPrinters(['hp', 'hpfax'])
1214        log.debug(self.installed_printers)
1215
1216        if not self.installed_printers:
1217            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."))
1218            self.close()
1219            return
1220
1221        self.RemoveDevicesTableWidget.setRowCount(len(self.installed_printers))
1222
1223        headers = [self.__tr("Select"), self.__tr('Printer (Queue) Name'), self.__tr('Type'), self.__tr('Device URI')]
1224
1225        self.RemoveDevicesTableWidget.setColumnCount(len(headers))
1226        self.RemoveDevicesTableWidget.setHorizontalHeaderLabels(headers)
1227        flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled
1228
1229        row = 0
1230        for p in self.installed_printers:
1231            widget = QCheckBox(self.RemoveDevicesTableWidget)
1232            widget.stateChanged.connect(self.CheckBox_stateChanged)
1233            self.RemoveDevicesTableWidget.setCellWidget(row, 0, widget)
1234
1235            back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
1236                device.parseDeviceURI(p.device_uri)
1237
1238            if self.device_uri is not None and self.device_uri == p.device_uri:
1239                widget.setCheckState(Qt.Checked)
1240
1241            i = QTableWidgetItem(str(p.name))
1242            i.setFlags(flags)
1243            i.setData(Qt.UserRole, p.name)
1244            self.RemoveDevicesTableWidget.setItem(row, 1, i)
1245
1246            if back_end == 'hpfax':
1247                typ = self.__tr("Fax")
1248            else:
1249                typ = self.__tr("Printer")
1250
1251            i = QTableWidgetItem(typ)
1252            i.setFlags(flags)
1253            self.RemoveDevicesTableWidget.setItem(row, 2, i)
1254
1255            i = QTableWidgetItem(str(p.device_uri))
1256            i.setFlags(flags)
1257            self.RemoveDevicesTableWidget.setItem(row, 3, i)
1258
1259            row += 1
1260
1261        self.RemoveDevicesTableWidget.resizeColumnsToContents()
1262
1263
1264    def CheckBox_stateChanged(self, i):
1265        for row in range(self.RemoveDevicesTableWidget.rowCount()):
1266            widget = self.RemoveDevicesTableWidget.cellWidget(row, 0)
1267            if widget.checkState() == Qt.Checked:
1268                self.NextButton.setEnabled(True)
1269                break
1270        else:
1271            self.NextButton.setEnabled(False)
1272
1273
1274    #
1275    # Misc
1276    #
1277
1278    def NextButton_clicked(self):
1279        p = self.StackedWidget.currentIndex()
1280        if p == PAGE_DISCOVERY:
1281            self.manual = self.ManualGroupBox.isChecked()
1282            self.param = to_unicode(self.ManualParamLineEdit.text())
1283            self.jd_port = self.JetDirectSpinBox.value()
1284            self.search = to_unicode(self.SearchLineEdit.text())
1285            self.device_desc = value_int(self.DeviceTypeComboBox.itemData(self.DeviceTypeComboBox.currentIndex()))[0]
1286            self.discovery_method = self.NetworkDiscoveryMethodComboBox.currentIndex()
1287
1288            if self.WirelessButton.isChecked():
1289                dlg = WifiSetupDialog(self, device_uri=None, standalone=False)
1290                dlg.exec_()
1291
1292                if dlg.success == SUCCESS_CONNECTED:
1293                    self.manual = True
1294                    self.param = dlg.hn
1295                    self.bus = 'net'
1296            if not self.WirelessButton.isChecked():
1297                self.showDevicesPage()
1298
1299        elif p == PAGE_DEVICES:
1300            row = self.DevicesTableWidget.currentRow()
1301            self.device_uri = self.DevicesTableWidget.item(row, 0).device_uri
1302            self.mq = device.queryModelByURI(self.device_uri)
1303            back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(self.device_uri)
1304            self.model = models.normalizeModelName(model).lower()
1305            self.showAddPrinterPage()
1306
1307        elif p == PAGE_ADD_PRINTER:
1308            self.print_test_page = self.SendTestPageCheckBox.isChecked()
1309            self.print_setup = self.SetupPrintGroupBox.isChecked()
1310            self.fax_setup = self.SetupFaxGroupBox.isChecked()
1311            self.print_location = from_unicode_to_str(to_unicode(self.PrinterLocationLineEdit.text()))
1312            self.print_desc = from_unicode_to_str(to_unicode(self.PrinterDescriptionLineEdit.text()))
1313            self.fax_desc = from_unicode_to_str(to_unicode(self.FaxDescriptionLineEdit.text()))
1314            self.fax_location = from_unicode_to_str(to_unicode(self.FaxLocationLineEdit.text()))
1315            self.fax_name_company = to_unicode(self.NameCompanyLineEdit.text())
1316            self.fax_number = to_unicode(self.FaxNumberLineEdit.text())
1317            self.addPrinter()
1318
1319        elif p == PAGE_REMOVE:
1320            for row in range(self.RemoveDevicesTableWidget.rowCount()):
1321                widget = self.RemoveDevicesTableWidget.cellWidget(row, 0)
1322                if widget.checkState() == Qt.Checked:
1323                    item = self.RemoveDevicesTableWidget.item(row, 1)
1324                    printer = to_unicode(value_str(item.data(Qt.UserRole)))
1325                    uri = device.getDeviceURIByPrinterName(printer)
1326                    log.debug("Removing printer: %s" % printer)
1327                    status, status_str = cups.cups_operation(cups.delPrinter, GUI_MODE, 'qt4', self, printer)
1328
1329                    if  status != cups.IPP_OK:
1330                        FailureUI(self, self.__tr("<b>Unable to delete '%s' queue. </b><p>Error : %s"%(printer,status_str)))
1331                        if status == cups.IPP_FORBIDDEN or status == cups.IPP_NOT_AUTHENTICATED or status == cups.IPP_NOT_AUTHORIZED:
1332                            break
1333                    else:
1334                        # sending Event to add this device in hp-systray
1335                        utils.sendEvent(EVENT_CUPS_QUEUES_REMOVED, uri, printer)
1336
1337            self.close()
1338
1339        else:
1340            log.error("Invalid page!") # shouldn't happen!
1341
1342
1343    def BackButton_clicked(self):
1344        p = self.StackedWidget.currentIndex()
1345        if p == PAGE_DEVICES:
1346            self.devices = {}
1347            self.showDiscoveryPage()
1348
1349        elif p == PAGE_ADD_PRINTER:
1350            self.showDevicesPage()
1351
1352        else:
1353            log.error("Invalid page!") # shouldn't happen!
1354
1355
1356    def CancelButton_clicked(self):
1357        self.close()
1358
1359
1360    def displayPage(self, page):
1361        self.StackedWidget.setCurrentIndex(page)
1362        self.updateStepText(page)
1363
1364
1365    def setNextButton(self, typ=BUTTON_FINISH):
1366        if typ == BUTTON_ADD_PRINTER:
1367            self.NextButton.setText(self.__tr("Add Printer"))
1368        elif typ == BUTTON_NEXT:
1369            self.NextButton.setText(self.__tr("Next >"))
1370        elif typ == BUTTON_FINISH:
1371            self.NextButton.setText(self.__tr("Finish"))
1372        elif typ == BUTTON_REMOVE:
1373            self.NextButton.setText(self.__tr("Remove"))
1374
1375
1376    def updateStepText(self, p):
1377        self.StepText.setText(self.__tr("Step %s of %s"%(p+1, self.max_page+1)))  #Python 3.2
1378
1379
1380    def __tr(self,s,c = None):
1381        return qApp.translate("SetupDialog",s,c)
1382
1383
1384