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