Fixed build error by changing buildrequires from pkgconfig(turbo-jpeg) to libjpeg...
[platform/upstream/hplip.git] / ui / setupform.py
1 # -*- coding: utf-8 -*-
2 #
3 # (c) Copyright 2001-2009 Hewlett-Packard Development Company, L.P.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # Author: Don Welch, Goutam Korra, Naga Samrat Chowdary Narla,
20
21 # Std Lib
22 import sys
23 import socket
24 import re
25 import gzip
26 import time
27 import os.path, os
28 import operator
29
30 # Local
31 from base.g import *
32 from base import device, utils, models, pkit
33 from prnt import cups
34 from installer import core_install
35 from ui_utils import load_pixmap
36
37 try:
38     from fax import fax
39     #from fax import fax
40     fax_import_ok = True
41 except ImportError:
42     # This can fail on Python < 2.3 due to the datetime module
43     fax_import_ok = False
44     log.warning("Fax setup disabled - Python 2.3+ required.")
45
46 # Qt
47 from qt import *
48 from setupform_base import SetupForm_base
49 from setupsettings import SetupSettings
50 from setupmanualfind import SetupManualFind
51
52 def restart_cups():
53     if os.path.exists('/etc/init.d/cups'):
54         return '/etc/init.d/cups restart'
55
56     elif os.path.exists('/etc/init.d/cupsys'):
57         return '/etc/init.d/cupsys restart'
58
59     else:
60         return 'killall -HUP cupsd'
61
62
63 class DeviceListViewItem(QListViewItem):
64     def __init__(self, parent, device_uri, mq, c1='', c2='', c3='', c4=''):
65         QListViewItem.__init__(self, parent, c1, c2, c3, c4)
66         self.device_uri = device_uri
67         self.mq = mq
68
69
70 class PPDListViewItem(QListViewItem):
71     def __init__(self, parent, ppd_file, c1=''):
72         QListViewItem.__init__(self, parent, ppd_file, c1)
73         self.ppd_file = ppd_file
74
75
76 class PrinterNameValidator(QValidator):
77     def __init__(self, parent=None, name=None):
78         QValidator.__init__(self, parent, name)
79
80     def validate(self, input, pos):
81         input = unicode(input)
82
83         if not input:
84             return QValidator.Acceptable, pos
85
86         elif input[pos-1] in u"""~`!@#$%^&*()-=+[]{}()\\/,.<>?'\";:| """:
87             return QValidator.Invalid, pos
88
89         # TODO: How to determine if unicode char is "printable" and acceptable
90         # to CUPS?
91         #elif input != utils.printable(input):
92         #    return QValidator.Invalid, pos
93
94         else:
95             return QValidator.Acceptable, pos
96
97
98
99 class PhoneNumValidator(QValidator):
100     def __init__(self, parent=None, name=None):
101         QValidator.__init__(self, parent, name)
102
103     def validate(self, input, pos):
104         input = unicode(input)
105
106         if not input:
107             return QValidator.Acceptable, pos
108
109         elif input[pos-1] not in u'0123456789-(+) ':
110             return QValidator.Invalid, pos
111
112         else:
113             return QValidator.Acceptable, pos
114
115
116
117 class SetupForm(SetupForm_base):
118     def __init__(self, bus, param, jd_port=1, parent=None, name=None, modal=0, fl=0):
119         SetupForm_base.__init__(self, parent, name, modal, fl)
120
121         self.start_page = self.ConnectionPage
122         self.first_page = True
123
124         if bus is None:
125             self.bus = 'usb'
126         else:
127             self.bus = bus[0]
128             self.start_page = self.ProbedDevicesPage
129
130         if not prop.par_build:
131             self.parRadioButton.setEnabled(False)
132
133         if not prop.net_build:
134             self.netRadioButton.setEnabled(False)
135
136         if not prop.par_build and not prop.net_build:
137             self.bus = 'usb'
138             self.start_page = self.ProbedDevicesPage
139
140         self.param = param
141         self.jd_port = jd_port
142
143         if self.param:
144             # Validate param...
145             device_uri, sane_uri, fax_uri = device.makeURI(self.param, self.jd_port)
146
147             if device_uri:
148                 self.device_uri = device_uri
149                 self.start_page = self.PPDPage
150
151             else:
152                 self.FailureUI(self.__tr("<b>Device not found.</b> <p>Please make sure your printer is properly connected and powered-on."))
153
154         self.setIcon(load_pixmap('hp_logo', '128x128'))
155
156         self.connectionTypeButtonGroup.setButton(0)
157         self.device_uri = ''
158         self.mq = {}
159         self.prev_page = None
160         self.probe_pat = re.compile(r'(.*?)\s"(.*?)"\s"(.*?)"\s"(.*?)"', re.IGNORECASE)
161         self.printer_name = ''
162         self.ppd_list = []
163         self.location = ''
164         self.desc = ''
165         self.filter = []
166         self.search = ''
167         self.ttl = 4
168         self.timeout = 5
169         self.printer_name_ok = True
170         self.fax_name_ok = True
171         self.fax_number = ''
172         self.fax_name = ''
173         self.printer_fax_names_same = False
174         self.fax_name_company = ''
175         self.fax_location = ''
176         self.fax_desc = ''
177         self.print_test_page = True
178         self.printerNameLineEdit.setValidator(PrinterNameValidator(self.printerNameLineEdit))
179         self.faxNameLineEdit.setValidator(PrinterNameValidator(self.faxNameLineEdit))
180         self.faxNumberLineEdit.setValidator(PhoneNumValidator(self.faxNumberLineEdit))
181         self.setTitleFont(QFont("Helvetica", 16))
182         self.setBackEnabled(self.FinishedPage, False)
183         self.bg = self.printerNameLineEdit.paletteBackgroundColor()
184         self.setHelpEnabled(self.ConnectionPage, False)
185         self.setHelpEnabled(self.ProbedDevicesPage, False)
186         self.setHelpEnabled(self.PPDPage, False)
187         self.setHelpEnabled(self.PrinterNamePage, False)
188         self.setHelpEnabled(self.FinishedPage, False)
189
190         self.faxNameLineEdit.setMaxLength(50)
191         self.printerNameLineEdit.setMaxLength(50)
192
193         QToolTip.add(self.searchFiltersPushButton2,
194             self.__tr('Current: Filter: [%2]  Search: "%3"  TTL: %4  Timeout: %5s').arg(','.join(self.filter)).arg(self.search or '').arg(self.ttl).arg(self.timeout))
195
196         cups.setPasswordCallback(showPasswordUI)
197
198
199     def showPage(self, page):
200         orig_page = page
201
202         if self.first_page:
203             page = self.start_page
204             self.first_page = False
205
206         log.debug("%s %s %s" % ("*"*20, "showPage(%s)" % page.name(), "*"*20))
207
208         try:
209             log.debug("%s --> %s" % (self.prev_page.name(), page.name()))
210         except AttributeError:
211             log.debug("--> %s" % page.name())
212
213         if page is self.ConnectionPage: # start --> ConnectionPage
214             pass
215
216         elif page is self.ProbedDevicesPage:
217             # ConnectionPage --> ProbedDevicesPage/EnterIPPage/DeviceNotFoundPage
218             devices_found = self.updateProbedDevicesPage()
219
220
221         elif page is self.PPDPage: # ProbedDevicesPage --> PPDPage
222             if self.param:
223                 device_uri, sane_uri, fax_uri = device.makeURI(self.param, self.jd_port)
224
225                 if device_uri:
226                     self.device_uri = device_uri
227
228             back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
229                 device.parseDeviceURI(self.device_uri)
230
231             self.bus = bus
232             self.mq = device.queryModelByURI(self.device_uri)
233
234             norm_model = models.normalizeModelName(model).lower()
235
236             core = core_install.CoreInstall()
237             core.set_plugin_version()
238             plugin = self.mq.get('plugin', PLUGIN_NONE)
239             plugin_reason = self.mq.get('plugin-reason', PLUGIN_REASON_NONE)
240             if plugin > PLUGIN_NONE and core.check_for_plugin() != PLUGIN_INSTALLED:
241                 ok, sudo_ok = pkit.run_plugin_command(plugin == PLUGIN_REQUIRED, plugin_reason)
242                 if not sudo_ok:
243                     self.FailureUI(self.__tr("<b>Unable to find an appropriate su/sudo utility to run hp-plugin.</b><p>Install kdesu, gnomesu, or gksu.</p>"))
244                     return
245                 if not ok or core.check_for_plugin() != PLUGIN_INSTALLED:
246                     if plugin == PLUGIN_REQUIRED:
247                         self.FailureUI(self.__tr("<b>The printer you are trying to setup requires a binary driver plug-in and it failed to install.</b><p>Please check your internet connection and try again.</p><p>Visit <u>http://hplipopensource.com</u> for more information.</p>"))
248                         return
249                     else:
250                         self.WarningUI(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."))
251
252             self.updatePPDPage()
253
254         elif page is self.PrinterNamePage:
255             self.setDefaultPrinterName()
256
257             if fax_import_ok and prop.fax_build and \
258                 self.mq.get('fax-type', FAX_TYPE_NONE) not in (FAX_TYPE_NONE, FAX_TYPE_NOT_SUPPORTED):
259
260                 self.faxCheckBox.setEnabled(True)
261                 self.faxCheckBox.setEnabled(True)
262                 self.faxNameLineEdit.setEnabled(True)
263                 self.faxNumberLineEdit.setEnabled(True)
264                 self.faxNameCoLineEdit.setEnabled(True)
265                 self.faxLocationLineEdit.setEnabled(True)
266                 self.faxDescriptionLineEdit.setEnabled(True)
267                 self.faxInfoGroupBox.setEnabled(True)
268                 self.setup_fax = True
269                 self.setDefaultFaxName()
270                 self.readwriteFaxInformation(True)
271
272             else:
273                 self.setup_fax = False
274                 self.fax_name_ok = True
275                 self.defaultFaxNamePushButton.setEnabled(False)
276                 self.faxCheckBox.setEnabled(False)
277                 self.faxNameLineEdit.setEnabled(False)
278                 self.faxNumberLineEdit.setEnabled(False)
279                 self.faxNameCoLineEdit.setEnabled(False)
280                 self.faxLocationLineEdit.setEnabled(False)
281                 self.faxDescriptionLineEdit.setEnabled(False)
282                 self.faxInfoGroupBox.setEnabled(False)
283
284         elif page is self.FinishedPage:
285             self.lineEdit1.setText(self.printer_name)
286             self.lineEdit2.setText(self.location)
287             self.lineEdit3.setText(self.desc)
288             self.lineEdit4.setText(self.ppd_file)
289
290             #log.debug("Restarting CUPS...")
291             #status, output = utils.run(restart_cups())
292             #log.debug("Restart CUPS returned: exit=%d output=%s" % (status, output))
293
294             self.setupPrinter()
295
296             if self.setup_fax:
297                 self.setupFax()
298                 self.readwriteFaxInformation(False)
299
300                 self.lineEdit5.setText(self.fax_number)
301                 self.lineEdit6.setText(self.fax_name)
302                 self.lineEdit7.setText(self.fax_name_company)
303                 self.lineEdit8.setText(self.fax_location)
304                 self.lineEdit9.setText(self.fax_desc)
305
306                 self.faxGroupBox.setEnabled(True)
307
308             else:
309                 self.faxGroupBox.setEnabled(False)
310
311             self.setFinishEnabled(self.FinishedPage, True)
312
313         if orig_page != page:
314             try:
315                 log.debug("%s --> %s" % (self.prev_page.name(), page.name()))
316             except AttributeError:
317                 log.debug("--> %s" % page.name())
318
319         self.prev_page = page
320         QWizard.showPage(self, page)
321
322         if page is self.ProbedDevicesPage: # ConnectionPage --> ProbedDevicesPage/EnterIPPage/DeviceNotFoundPage
323             if not devices_found:
324                 self.FailureUI(self.__tr("<b>No devices found.</b><p>Please make sure your printer is properly connected and powered-on."))
325
326
327     #
328     # CONNECTION TYPE PAGE
329     #
330
331     def connectionTypeButtonGroup_clicked(self,a0):
332         if a0 == 0:
333             self.bus = 'usb'
334
335         elif a0 == 1:
336             self.bus = 'net'
337
338         elif a0 == 2:
339             self.bus = 'par'
340
341         log.debug(self.bus)
342
343
344     def searchFiltersPushButton2_clicked(self):
345         self.settingsDlg()
346
347     #
348     # FILTERS SEARCH SETTINGS
349     #
350
351     def settingsDlg(self):
352         dlg = SetupSettings(self.bus, self.filter, self.search, self.ttl, self.timeout, self)
353         if dlg.exec_loop() == QDialog.Accepted:
354             #self.filter = [x.lower().strip() for x in dlg.filter.split(',')]
355             self.filter = dlg.filter
356             self.search = dlg.search
357             self.ttl = dlg.ttl
358             self.timeout = dlg.timeout
359
360             t = self.__tr('Current Settings: Filter: [%2]  Search: "%3"  TTL: %4  Timeout: %5s').arg(','.join(self.filter)).arg(self.search or '').arg(self.ttl).arg(self.timeout)
361
362             QToolTip.add(self.searchFiltersPushButton2, t)
363             QToolTip.add(self.searchFiltersPushButton, t)
364             return True
365
366         return False
367
368     #
369     # PROBED DEVICES PAGE
370     #
371
372     def updateProbedDevicesPage(self, devices=None, param=''):
373         QApplication.setOverrideCursor(QApplication.waitCursor)
374
375         if self.bus == 'net':
376             io_str = self.__tr("network")
377
378         elif self.bus == 'usb':
379             io_str = self.__tr("USB bus")
380
381         elif self.bus == 'par':
382             io_str = self.__tr("parallel port")
383
384         QToolTip.add(self.searchFiltersPushButton, self.__tr('Current Settings: Filter: [%2]  Search: "%3"  TTL: %4  Timeout: %5s').arg(','.join(self.filter)).arg(self.search or '').arg(self.ttl).arg(self.timeout))
385
386         log.debug("Updating probed devices list...")
387         log.debug(self.bus)
388
389         self.probedDevicesListView.clear()
390
391         while self.probedDevicesListView.columns():
392             self.probedDevicesListView.removeColumn(0)
393
394         self.probedDevicesListView.addColumn(self.__tr("Model"))
395
396         if self.bus == 'usb':
397             self.probedDevicesListView.addColumn(self.__tr("Serial No."))
398
399         elif self.bus == 'net':
400             self.probedDevicesListView.addColumn(self.__tr("IP Address"))
401             self.probedDevicesListView.addColumn(self.__tr("Host Name"))
402
403         elif self.bus == 'par':
404             self.probedDevicesListView.addColumn(self.__tr("Device"))
405
406         self.probedDevicesListView.addColumn(self.__tr("Device URI"))
407
408         if devices is None:
409             FILTER_MAP = {'print' : None,
410                           'none' : None,
411                           'scan': 'scan-type',
412                           'copy': 'copy-type',
413                           'pcard': 'pcard-type',
414                           'fax': 'fax-type',
415                           }
416
417             filter_dict = {}
418
419             if prop.fax_build and prop.scan_build:
420                 for f in self.filter:
421                     if f in FILTER_MAP:
422                         filter_dict[FILTER_MAP[f]] = (operator.gt, 0)
423                     else:
424                         filter_dict[f] = (operator.gt, 0)
425             else:
426                 filter_dict['scan-type'] = (operator.ge, SCAN_TYPE_NONE)
427
428             devices = device.probeDevices([self.bus], self.timeout, self.ttl, filter_dict, self.search, net_search='slp')
429
430             self.probeHeadingTextLabel.setText(self.__tr("%1 device(s) found on the %1:").arg(len(devices)).arg(io_str))
431
432         else:
433             if self.bus == 'net':
434                 self.probeHeadingTextLabel.setText(self.__tr("%1 device(s) found on the %1 at address %2:").arg(len(devices)).arg(io_str).arg(param))
435
436             elif self.bus == 'usb':
437                 self.probeHeadingTextLabel.setText(self.__tr("%1 device(s) found on the %1 at ID %2:").arg(len(devices)).arg(io_str).arg(param))
438
439             elif self.bus == 'par':
440                 self.probeHeadingTextLabel.setText(self.__tr("%1 device(s) found on the %1 device node ID %2:").arg(len(devices)).arg(io_str).arg(param))
441
442         log.debug(devices)
443
444         if devices:
445             row = 0
446             for d in devices:
447                 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(d)
448
449                 mq = {}
450                 model_ui = models.normalizeModelUIName(model)
451
452                 if self.bus == 'usb':
453                     i = DeviceListViewItem(self.probedDevicesListView, d, mq, model_ui, serial, d)
454
455                 elif self.bus == 'net':
456                     i = DeviceListViewItem(self.probedDevicesListView, d, mq, model_ui, host, devices[d][2], d)
457
458                 elif self.bus == 'par':
459                     i = DeviceListViewItem(self.probedDevicesListView, d, mq, model_ui, dev_file, d)
460
461                 row += 1
462
463             i = self.probedDevicesListView.firstChild()
464             self.probedDevicesListView.setCurrentItem(i)
465             self.probedDevicesListView.setSelected(i, True)
466             item = self.probedDevicesListView.currentItem()
467             self.device_uri = item.device_uri
468             self.updateModelQuery(item)
469             self.setNextEnabled(self.ProbedDevicesPage, True)
470             log.debug(self.device_uri)
471
472         else:
473             self.setNextEnabled(self.ProbedDevicesPage, False)
474             QApplication.restoreOverrideCursor()
475             return False
476
477         QApplication.restoreOverrideCursor()
478         return True
479
480     def updateModelQuery(self, item):
481         if not item.mq:
482             item.mq = device.queryModelByURI(self.device_uri)
483             self.mq = item.mq
484         else:
485             self.mq = item.mq
486
487         log.debug(self.mq)
488
489     def probedDevicesListView_currentChanged(self, item):
490         self.device_uri = item.device_uri
491         self.updateModelQuery(item)
492         log.debug(self.device_uri)
493
494     def probeUpdatePushButton_clicked(self):
495         self.updateProbedDevicesPage()
496
497     def searchFiltersPushButton_clicked(self):
498         if self.settingsDlg():
499             self.updateProbedDevicesPage()
500
501     def manualFindPushButton_clicked(self):
502         dlg = SetupManualFind(self.bus, self)
503         if dlg.exec_loop() == QDialog.Accepted:
504             QApplication.setOverrideCursor(QApplication.waitCursor)
505
506             cups_uri, sane_uri, fax_uri = device.makeURI(dlg.param)
507
508             if cups_uri:
509                 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(cups_uri)
510                 name = ''
511                 if self.bus == 'net':
512                     try:
513                         name = socket.gethostbyaddr(host)[0]
514                     except socket.herror:
515                         name = ''
516
517                 QApplication.restoreOverrideCursor()
518                 self.updateProbedDevicesPage({cups_uri: (model, model, name)}, dlg.param)
519             else:
520                 QApplication.restoreOverrideCursor()
521                 self.updateProbedDevicesPage([], dlg.param)
522
523     #
524     # PPD
525     #
526
527     def updatePPDPage(self, ppds=None):
528         QApplication.setOverrideCursor(QApplication.waitCursor)
529         try:
530             back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(self.device_uri)
531         except Error:
532             self.FailureUI(self.__tr("<b>Device not found or invalid HPLIP device.</b><p>If you specified a USB ID, IP address, or other parameter, please re-check it and try again."))
533             self.close()
534             sys.exit()
535
536         if ppds is None or not ppds:
537             ppds = cups.getSystemPPDs()
538
539         #print ppds
540
541         default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_')
542         stripped_model = cups.stripModel2(models.normalizeModelName(model).lower())
543         
544         
545         #Check if common ppd name is already given in models.dat(This is needed because in case of devices having more than one derivatives
546         #will have diffrent model name strings in device ID, because of which we don't get the common ppd name for search)
547        
548         ppd_name = self.mq.get('ppd-name',0)
549         
550         if ppd_name == 0:
551                 self.ppd = cups.getPPDFile2(stripped_model, ppds)
552         else:
553             self.ppd = cups.getPPDFile2(ppd_name, ppds)
554         
555         log.debug(self.ppd)
556         self.ppdListView.clear()
557
558         if self.ppd is not None:
559             #for ppd in self.ppd_dict:
560             PPDListViewItem(self.ppdListView, self.ppd[0], self.ppd[1])
561
562 #            i = self.ppdListView.firstChild()
563 #            self.ppdListView.setCurrentItem(i)
564 #            self.ppdListView.setSelected(i, True)
565 #            self.ppd_file = self.ppdListView.currentItem().ppd_file
566             self.ppd_file = self.ppd[0]
567             log.debug(self.ppd_file)
568
569         else:
570             self.FailureUI(self.__tr('<b>PPD not file found.</b><p>An appropriate PPD file could not be found. Please check your HPLIP install, use <i>Select Other...</i>, or download one from linuxprinting.org.'))
571
572         QApplication.restoreOverrideCursor()
573
574
575     def ppdListView_currentChanged(self,a0):
576         self.ppd_file = a0.ppd_file
577         log.debug(self.ppd_file)
578
579
580     def otherPPDPushButton_clicked(self):
581         ppd_dir = sys_conf.get('dirs', 'ppd')
582         ppd_file = unicode(QFileDialog.getOpenFileName(ppd_dir, "PPD Files (*.ppd *.ppd.gz);;All Files (*)", self, "open file dialog", "Choose a PPD file"))
583
584         if ppd_file and os.path.exists(ppd_file):
585             self.updatePPDPage({ppd_file: cups.getPPDDescription(ppd_file)})
586         else:
587             self.updatePPDPage()
588
589     def ppdDefaultsPushButton_clicked(self):
590         self.updatePPDPage()
591
592
593     #
594     # PRINTER/FAX INFORMATION PAGE
595     #
596
597     def setDefaultPrinterName(self):
598         self.installed_print_devices = device.getSupportedCUPSDevices(['hp'])
599         #self.installed_print_devices = device.getSupportedCUPSDevices('*')
600         log.debug(self.installed_print_devices)
601
602         self.installed_queues = [p.name for p in cups.getPrinters()]
603
604         back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(self.device_uri)
605         default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_')
606
607         printer_name = default_model
608
609         installed_printer_names = device.getSupportedCUPSPrinterNames(['hp'])
610         # Check for duplicate names
611         if (self.device_uri in self.installed_print_devices and printer_name in self.installed_print_devices[self.device_uri]) \
612            or (printer_name in installed_printer_names):
613                 i = 2
614                 while True:
615                     t = printer_name + "_%d" % i
616                     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]):
617                         printer_name += "_%d" % i
618                         break
619                     i += 1
620
621         self.printer_name_ok = True
622         self.printerNameLineEdit.setText(printer_name)
623         log.debug(printer_name)
624         self.printerNameLineEdit.setPaletteBackgroundColor(self.bg)
625         self.defaultPrinterNamePushButton.setEnabled(False)
626         self.printer_name = printer_name
627
628
629     def setEditErrors(self):
630         if self.printer_name_ok:
631             self.printerNameLineEdit.setPaletteBackgroundColor(self.bg)
632             self.printer_name_ok = True
633
634             if self.fax_name_ok:
635                 self.setNextEnabled(self.PrinterNamePage, True)
636
637             QToolTip.remove(self.printerNameLineEdit)
638
639         else:
640             self.printerNameLineEdit.setPaletteBackgroundColor(QColor(0xff, 0x99, 0x99))
641             self.setNextEnabled(self.PrinterNamePage, False)
642
643         if self.fax_name_ok:
644             self.fax_name_ok = True
645             self.faxNameLineEdit.setPaletteBackgroundColor(self.bg)
646
647             if self.printer_name_ok:
648                 self.setNextEnabled(self.PrinterNamePage, True)
649
650             QToolTip.remove(self.faxNameLineEdit)
651
652         else:
653             self.faxNameLineEdit.setPaletteBackgroundColor(QColor(0xff, 0x99, 0x99))
654             self.setNextEnabled(self.PrinterNamePage, False)
655
656
657     def printerNameLineEdit_textChanged(self,a0):
658         self.printer_name = unicode(a0)
659         self.defaultPrinterNamePushButton.setEnabled(True)
660
661         self.printer_name_ok = True
662
663         if not self.printer_name:
664             QToolTip.add(self.printerNameLineEdit, self.__tr('You must enter a name for the printer.'))
665             self.printer_name_ok = False
666
667         elif self.fax_name == self.printer_name:
668             s = self.__tr('The printer name and fax name must be different. Please choose different names.')
669             QToolTip.add(self.faxNameLineEdit, s)
670             QToolTip.add(self.printerNameLineEdit, s)
671             self.fax_name_ok = False
672             self.printer_name_ok = False
673             self.printer_fax_names_same = True
674
675         elif self.printer_name in self.installed_queues:
676             QToolTip.add(self.printerNameLineEdit,
677                 self.__tr('A printer already exists with this name. Please choose a different name.'))
678             self.printer_name_ok = False
679
680         elif self.printer_fax_names_same:
681             if self.fax_name != self.printer_name:
682                 self.printer_fax_names_same = False
683                 self.printer_name_ok = True
684
685                 self.faxNameLineEdit.emit(SIGNAL("textChanged(const QString&)"),
686                             (self.faxNameLineEdit.text(),))
687
688         self.setEditErrors()
689
690
691     def printerLocationLineEdit_textChanged(self, a0):
692         self.location = unicode(a0)
693
694     def printerDescriptionLineEdit_textChanged(self,a0):
695         self.desc = unicode(a0)
696
697     def faxLocationLineEdit_textChanged(self,a0):
698         self.fax_location = unicode(a0)
699
700     def faxDescriptionLineEdit_textChanged(self,a0):
701         self.fax_desc = unicode(a0)
702
703     def defaultPrinterNamePushButton_clicked(self):
704         self.setDefaultPrinterName()
705         self.defaultPrinterNamePushButton.setEnabled(False)
706
707     def setDefaultFaxName(self):
708         self.installed_fax_devices = device.getSupportedCUPSDevices(['hpfax'])
709         log.debug(self.installed_fax_devices)
710
711         self.fax_uri = self.device_uri.replace('hp:', 'hpfax:')
712
713         back_end, is_hp, bus, model, serial, dev_file, host, zc, port = device.parseDeviceURI(self.fax_uri)
714         default_model = utils.xstrip(model.replace('series', '').replace('Series', ''), '_')
715
716         fax_name = default_model + "_fax"
717         installed_fax_names = device.getSupportedCUPSPrinterNames(['hpfax'])
718
719         # Check for duplicate names
720         if (self.fax_uri in self.installed_fax_devices and fax_name in self.installed_fax_devices[self.fax_uri]) \
721            or (fax_name in installed_fax_names):
722         #if fax_name in self.installed_queues or fax_name == self.printer_name:
723                 i = 2
724                 while True:
725                     t = fax_name + "_%d" % i
726                     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]):
727                         fax_name += "_%d" % i
728                         break
729                     i += 1
730
731         self.fax_name_ok = True
732         self.faxNameLineEdit.setText(fax_name)
733         self.faxNameLineEdit.setPaletteBackgroundColor(self.bg)
734         self.defaultFaxNamePushButton.setEnabled(False)
735         self.fax_name = fax_name
736         #self.fax_name_error = False
737
738     def faxNameLineEdit_textChanged(self, a0):
739         self.fax_name = unicode(a0)
740         self.defaultFaxNamePushButton.setEnabled(True)
741
742         self.fax_name_ok = True
743
744         if not self.fax_name:
745             QToolTip.add(self.faxNameLineEdit, self.__tr('You must enter a fax name.'))
746             self.fax_name_ok = False
747
748         elif self.fax_name == self.printer_name:
749             s = self.__tr('The printer name and fax name must be different. Please choose different names.')
750             QToolTip.add(self.faxNameLineEdit, s)
751             QToolTip.add(self.printerNameLineEdit, s)
752             self.printer_name_ok = False
753             self.fax_name_ok = False
754             self.printer_fax_names_same = True
755
756         elif self.fax_name in self.installed_queues:
757             QToolTip.add(self.faxNameLineEdit,
758                 self.__tr('A fax already exists with this name. Please choose a different name.'))
759             self.fax_name_ok = False
760
761         elif self.printer_fax_names_same:
762             if self.fax_name != self.printer_name:
763                 self.printer_fax_names_same = False
764                 self.fax_name_ok = True
765
766                 self.printerNameLineEdit.emit(SIGNAL("textChanged(const QString&)"),
767                             (self.printerNameLineEdit.text(),))
768
769         self.setEditErrors()
770
771
772     def faxNumberLineEdit_textChanged(self, a0):
773         self.fax_number = unicode(a0)
774
775     def faxNameCoLineEdit_textChanged(self, a0):
776         self.fax_name_company = unicode(a0)
777
778     def faxCheckBox_clicked(self):
779         pass
780
781     def faxCheckBox_toggled(self, a0):
782         self.setup_fax = bool(a0)
783
784         if not self.setup_fax and not self.fax_name_ok:
785             self.setDefaultFaxName()
786
787     def printTestPageCheckBox_toggled(self, a0):
788         self.print_test_page = bool(a0)
789
790     def defaultFaxNamePushButton_clicked(self):
791         self.setDefaultFaxName()
792         self.defaultFaxNamePushButton.setEnabled(False)
793
794     def readwriteFaxInformation(self, read=True):
795         try:
796             QApplication.setOverrideCursor(QApplication.waitCursor)
797
798             d = fax.getFaxDevice(self.fax_uri, disable_dbus=True)
799
800             while True:
801                 try:
802                     d.open()
803                 except Error:
804                     error_text = self.__tr("Unable to communicate with the device. Please check the device and try again.")
805                     log.error(unicode(error_text))
806                     if QMessageBox.critical(self,
807                                            self.caption(),
808                                            error_text,
809                                            QMessageBox.Retry | QMessageBox.Default,
810                                            QMessageBox.Cancel | QMessageBox.Escape,
811                                            QMessageBox.NoButton) == QMessageBox.Cancel:
812                         break
813
814                 else:
815                     try:
816                         tries = 0
817                         ok = True
818
819                         while True:
820                             tries += 1
821
822                             try:
823                                 if read:
824                                     self.fax_number = unicode(d.getPhoneNum())
825                                     self.fax_name_company = unicode(d.getStationName())
826                                 else:
827                                     d.setStationName(self.fax_name_company)
828                                     d.setPhoneNum(self.fax_number)
829
830                             except Error:
831                                 error_text = self.__tr("<b>Device I/O Error</b><p>Could not communicate with device. Device may be busy.")
832                                 log.error(unicode(error_text))
833
834                                 if QMessageBox.critical(self,
835                                                        self.caption(),
836                                                        error_text,
837                                                        QMessageBox.Retry | QMessageBox.Default,
838                                                        QMessageBox.Cancel | QMessageBox.Escape,
839                                                        QMessageBox.NoButton) == QMessageBox.Cancel:
840                                     break
841
842
843                                 time.sleep(5)
844                                 ok = False
845
846                                 if tries > 12:
847                                     break
848
849                             else:
850                                 ok = True
851                                 break
852
853                     finally:
854                         d.close()
855
856                     if ok and read:
857                         self.faxNumberLineEdit.setText(self.fax_number)
858                         self.faxNameCoLineEdit.setText(self.fax_name_company)
859
860                     break
861
862         finally:
863             QApplication.restoreOverrideCursor()
864
865     #
866     # SETUP PRINTER/FAX
867     #
868
869     def setupPrinter(self):
870         QApplication.setOverrideCursor(QApplication.waitCursor)
871
872         cups.setPasswordPrompt("You do not have permission to add a printer.")
873         #if self.ppd_file.startswith("foomatic:"):
874         if not os.path.exists(self.ppd_file): # assume foomatic: or some such
875             status, status_str = cups.addPrinter(self.printer_name.encode('utf8'), self.device_uri,
876                 self.location, '', self.ppd_file, self.desc)
877         else:
878             status, status_str = cups.addPrinter(self.printer_name.encode('utf8'), self.device_uri,
879                 self.location, self.ppd_file, '', self.desc)
880
881         log.debug("addPrinter() returned (%d, %s)" % (status, status_str))
882         self.installed_print_devices = device.getSupportedCUPSDevices(['hp'])
883
884         log.debug(self.installed_print_devices)
885
886         if self.device_uri not in self.installed_print_devices or \
887             self.printer_name not in self.installed_print_devices[self.device_uri]:
888
889             self.FailureUI(self.__tr("<b>Printer queue setup failed.</b><p>Please restart CUPS and try again."))
890         else:
891             # TODO:
892             #service.sendEvent(self.hpssd_sock, EVENT_CUPS_QUEUES_CHANGED, device_uri=self.device_uri)
893             pass
894
895         QApplication.restoreOverrideCursor()
896
897     def setupFax(self):
898         QApplication.setOverrideCursor(QApplication.waitCursor)
899
900         if self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_MARVELL:
901             fax_ppd_name = "HP-Fax3-hplip" # Fixed width (2528 pixels) and 300dpi rendering
902             nick = "HP Fax 3"
903         if self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_SOAP or self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_LEDMSOAP:
904             fax_ppd_name = "HP-Fax2-hplip" # Fixed width (2528 pixels) and 300dpi rendering
905             nick = "HP Fax 2"
906         if self.mq.get('fax-type', FAX_TYPE_NONE) == FAX_TYPE_LEDM:
907             fax_ppd_name = "HP-Fax4-hplip" # Fixed width (1728 pixels) and 200dpi rendering
908             nick = "HP Fax 4"
909         else:
910             fax_ppd_name = "HP-Fax-hplip" # Standard
911             nick = "HP Fax"
912
913         ppds = []
914
915         log.debug("Searching for fax file %s..." % fax_ppd_name)
916
917         ppd_dir = sys_conf.get('dirs', 'ppd')
918         for f in utils.walkFiles(ppd_dir, pattern="HP-Fax*.ppd*", abs_paths=True):
919             ppds.append(f)
920
921         for f in ppds:
922             if f.find(fax_ppd_name) >= 0:
923                 fax_ppd = f
924                 log.debug("Found PDD file: %s" % fax_ppd)
925                 log.debug("Nickname: %s" % cups.getPPDDescription(fax_ppd))
926                 break
927         else:
928             QApplication.restoreOverrideCursor()
929             log.error("Fax PPD file not found.")
930
931             if QMessageBox.warning(self, self.__tr("Unable to find HP fax PPD file."),
932                 self.__tr("The PPD file (%1.ppd) needed to setup the fax queue was not found.").arg(fax_ppd_name),
933                 self.__tr("Browse to file..."), # button 0
934                 self.__tr("Quit") # button 1
935                 ) == 0: # Browse
936
937                 while True:
938                     ppd_dir = sys_conf.get('dirs', 'ppd')
939                     fax_ppd = unicode(QFileDialog.getOpenFileName(ppd_dir,
940                         "HP Fax PPD Files (*.ppd *.ppd.gz);;All Files (*)", self,
941                         "open file dialog", "Choose the fax PPD file"))
942
943                     if not fax_ppd: # user hit cancel
944                         return
945
946                     if os.path.exists(fax_ppd):
947                         n = cups.getPPDDescription(fax_ppd)
948                         if n == nick:
949                             break
950                         else:
951                             self.FailureUI(self.__tr("<b>Incorrect fax PPD file.</b><p>The fax PPD file must have a nickname of '%1', not '%1'.").arg(nick).arg(n))
952                     else:
953                         self.FailureUI(self.__tr("<b>File not found.</b><p>hp-setup cannot find the file %1").arg(fax_ppd))
954
955             else: # Quit
956                 return
957
958         cups.setPasswordPrompt("You do not have permission to add a fax device.")
959         if not os.path.exists(fax_ppd):
960             status, status_str = cups.addPrinter(self.fax_name.encode('utf8'),
961                 self.fax_uri, self.fax_location, '', fax_ppd,  self.fax_desc)
962         else:
963             status, status_str = cups.addPrinter(self.fax_name.encode('utf8'),
964                 self.fax_uri, self.fax_location, fax_ppd, '', self.fax_desc)
965
966         log.debug("addPrinter() returned (%d, %s)" % (status, status_str))
967         self.installed_fax_devices = device.getSupportedCUPSDevices(['hpfax'])
968
969         log.debug(self.installed_fax_devices)
970
971         if self.fax_uri not in self.installed_fax_devices or \
972             self.fax_name not in self.installed_fax_devices[self.fax_uri]:
973
974             self.FailureUI(self.__tr("<b>Fax queue setup failed.</b><p>Please restart CUPS and try again."))
975         else:
976             pass
977             # TODO:
978             #service.sendEvent(self.hpssd_sock, EVENT_CUPS_QUEUES_CHANGED, device_uri=self.fax_uri)
979
980         QApplication.restoreOverrideCursor()
981
982     def accept(self):
983         if self.print_test_page:
984             try:
985                 d = device.Device(self.device_uri)
986             except Error, e:
987                 self.FailureUI(self.__tr("<b>Device error:</b><p>%s (%s)." % (e.msg, e.opt)))
988
989             else:
990                 try:
991                     d.open()
992                 except Error:
993                     self.FailureUI(self.__tr("<b>Unable to print to printer.</b><p>Please check device and try again."))
994                 else:
995                     if d.isIdleAndNoError():
996                         d.close()
997
998                         try:
999                             d.printTestPage(self.printer_name)
1000                         except Error, e:
1001                             if e.opt == ERROR_NO_CUPS_QUEUE_FOUND_FOR_DEVICE:
1002                                 self.FailureUI(self.__tr("<b>No CUPS queue found for device.</b><p>Please install the printer in CUPS and try again."))
1003                             else:
1004                                 self.FailureUI(self.__tr("<b>Printer Error</b><p>An error occured: %s (code=%d)." % (e.msg, e.opt)))
1005                     else:
1006                         self.FailureUI(self.__tr("<b>Printer Error.</b><p>Printer is busy, offline, or in an error state. Please check the device and try again."))
1007                         d.close()
1008
1009
1010         QWizard.accept(self)
1011
1012
1013     def reject(self):
1014         QWizard.reject(self)
1015
1016     def FailureUI(self, error_text):
1017         log.error(unicode(error_text).replace("<b>", "").replace("</b>", "").replace("<p>", " "))
1018         QMessageBox.critical(self,
1019                              self.caption(),
1020                              error_text,
1021                               QMessageBox.Ok,
1022                               QMessageBox.NoButton,
1023                               QMessageBox.NoButton)
1024
1025     def WarningUI(self, error_text):
1026         QMessageBox.warning(self,
1027                              self.caption(),
1028                              error_text,
1029                               QMessageBox.Ok,
1030                               QMessageBox.NoButton,
1031                               QMessageBox.NoButton)
1032
1033     def __tr(self, s, c=None):
1034         return qApp.translate("SetupForm", s, c)
1035
1036
1037
1038 class PasswordDialog(QDialog):
1039     def __init__(self,prompt, parent=None, name=None, modal=0, fl=0):
1040         QDialog.__init__(self,parent,name,modal,fl)
1041         self.prompt = prompt
1042
1043         if not name:
1044             self.setName("PasswordDialog")
1045
1046         passwordDlg_baseLayout = QGridLayout(self,1,1,11,6,"passwordDlg_baseLayout")
1047
1048         self.promptTextLabel = QLabel(self,"promptTextLabel")
1049         passwordDlg_baseLayout.addMultiCellWidget(self.promptTextLabel,0,0,0,1)
1050
1051         self.usernameTextLabel = QLabel(self,"usernameTextLabel")
1052         passwordDlg_baseLayout.addMultiCellWidget(self.usernameTextLabel,1,1,0,1)
1053
1054         self.usernameLineEdit = QLineEdit(self,"usernameLineEdit")
1055         self.usernameLineEdit.setEchoMode(QLineEdit.Normal)
1056         passwordDlg_baseLayout.addMultiCellWidget(self.usernameLineEdit,1,1,1,2)
1057
1058         self.passwordTextLabel = QLabel(self,"passwordTextLabel")
1059         passwordDlg_baseLayout.addMultiCellWidget(self.passwordTextLabel,2,2,0,1)
1060
1061         self.passwordLineEdit = QLineEdit(self,"passwordLineEdit")
1062         self.passwordLineEdit.setEchoMode(QLineEdit.Password)
1063         passwordDlg_baseLayout.addMultiCellWidget(self.passwordLineEdit,2,2,1,2)
1064
1065         self.okPushButton = QPushButton(self,"okPushButton")
1066         passwordDlg_baseLayout.addWidget(self.okPushButton,3,2)
1067
1068         self.languageChange()
1069
1070         self.resize(QSize(420,163).expandedTo(self.minimumSizeHint()))
1071         self.clearWState(Qt.WState_Polished)
1072
1073         self.connect(self.okPushButton,SIGNAL("clicked()"),self.accept)
1074         self.connect(self.passwordLineEdit,SIGNAL("returnPressed()"),self.accept)
1075
1076     def setDefaultUsername(self, defUser, allowUsernameEdit = True):
1077         self.usernameLineEdit.setText(defUser)
1078         if not allowUsernameEdit:
1079             self.usernameLineEdit.setReadOnly(True)
1080             self.usernameLineEdit.setPaletteBackgroundColor(QColor("lightgray"))
1081
1082     def getUsername(self):
1083         return unicode(self.usernameLineEdit.text())
1084
1085     def getPassword(self):
1086         return unicode(self.passwordLineEdit.text())
1087
1088     def languageChange(self):
1089         self.setCaption(self.__tr("HP Device Manager - Enter Username/Password"))
1090         self.promptTextLabel.setText(self.__tr(self.prompt))
1091         self.usernameTextLabel.setText(self.__tr("Username"))
1092         self.passwordTextLabel.setText(self.__tr("Password"))
1093         self.okPushButton.setText(self.__tr("OK"))
1094
1095     def __tr(self,s,c = None):
1096         return qApp.translate("PasswordDialog",s,c)
1097
1098
1099 def showPasswordUI(prompt, userName=None, allowUsernameEdit=True):
1100     try:
1101         dlg = PasswordDialog(prompt, None)
1102
1103         if userName != None:
1104             dlg.setDefaultUsername(userName, allowUsernameEdit)
1105
1106         if dlg.exec_loop() == QDialog.Accepted:
1107             return (dlg.getUsername(), dlg.getPassword())
1108
1109     finally:
1110         pass
1111
1112     return ("", "")