1# -*- coding: utf-8 -*-
2#
3# (c) Copyright 2001-2015 HP 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# Authors: Don Welch, Yashwant Kumar Sahu, Sanjay Kumar Sharma
20#
21
22# Std Lib
23import sys
24
25# Local
26from base.g import *
27from base import utils
28from prnt import cups
29from base.codes import *
30from .ui_utils import *
31from base.sixext import PY3
32from base.sixext import  to_unicode
33
34# Qt
35from PyQt4.QtCore import *
36from PyQt4.QtGui import *
37
38
39
40class RangeValidator(QValidator):
41    def __init__(self, parent=None, name=None):
42        QValidator.__init__(self, parent) #, name)
43
44
45    def validate(self, input, pos):
46        for x in to_unicode(input)[pos-1:]:
47            if x not in to_unicode('0123456789,- '):
48                if PY3:
49                    return QValidator.Invalid, input, pos
50                else:
51                    return QValidator.Invalid, pos
52        if PY3:
53            return QValidator.Acceptable, input, pos
54        else:
55            return QValidator.Acceptable, pos
56
57
58
59class PinValidator(QValidator):
60    def __init__(self, parent=None, name=None):
61        QValidator.__init__(self, parent) #, name)
62
63
64    def validate(self, input, pos):
65        for x in to_unicode(input)[pos-1:]:
66            if x not in to_unicode('0123456789'):
67                if PY3:
68                    return QValidator.Invalid, input, pos
69                else:
70                    return QValidator.Invalid, pos
71        if PY3:
72            return QValidator.Acceptable, input, pos
73        else:
74            return QValidator.Acceptable, pos
75
76
77
78class UsernameAndJobnameValidator(QValidator):
79    def __init__(self, parent=None, name=None):
80        QValidator.__init__(self, parent) #, name)
81
82
83    def validate(self, input, pos):
84        for x in to_unicode(input)[pos-1:]:
85            if x in to_unicode(' /=,.:;\'"[]{}-+!@#$%^&*()'):
86                if PY3:
87                    return QValidator.Invalid, input, pos
88                else:
89                    return QValidator.Invalid, pos
90        if PY3:
91            return QValidator.Acceptable, input, pos
92        else:
93            return QValidator.Acceptable, pos
94
95
96
97class OptionComboBox(QComboBox):
98    def __init__(self, rw, parent, name, group, option, choices, default,
99                 typ=cups.PPD_UI_PICKONE, other=None, job_option=False):
100        QComboBox.__init__(self, parent)
101        # rw?
102        self.group = group
103        self.option = option
104        self.choices = choices
105        self.default = default
106        self.typ = typ
107        self.other = other
108        self.job_option = job_option
109        self.setObjectName(name)
110
111
112    def setDefaultPushbutton(self, pushbutton):
113        self.pushbutton = pushbutton
114
115
116    def setOther(self, other):
117        self.other = other
118
119
120
121class OptionSpinBox(QSpinBox):
122    def __init__(self,  parent, name, group, option, default, job_option=False):
123        QSpinBox.__init__(self, parent)
124        self.group = group
125        self.option = option
126        self.default = default
127        self.job_option = job_option
128        self.setObjectName(name)
129
130
131    def setDefaultPushbutton(self, pushbutton):
132        self.pushbutton = pushbutton
133
134
135
136class OptionRadioButton(QRadioButton):
137    def __init__(self, parent, name, group, option, default, job_option=False):
138        QRadioButton.__init__(self, parent)
139        self.group = group
140        self.option = option
141        self.default = default
142        self.job_option = job_option
143        self.setObjectName(name)
144
145
146    def setDefaultPushbutton(self, pushbutton):
147        self.pushbutton = pushbutton
148
149
150
151class DefaultPushButton(QPushButton):
152    def __init__(self,  parent, name, group, option, choices,
153                 default, control, typ, job_option=False):
154        QPushButton.__init__(self, parent)
155        self.group = group
156        self.option = option
157        self.default = default
158        self.control = control
159        self.typ = typ
160        self.choices = choices
161        self.job_option = job_option
162        self.setObjectName(name)
163
164
165#class PageRangeRadioButton(QRadioButton):
166#    def __init__(self, parent, page_range_edit):
167#        QRadioButton.__init__(self, parent):
168#            self.page_range_edit = page_range_edit
169
170
171class PageRangeRadioButton(QRadioButton):
172    def __init__(self, parent, name, group, option, default): #, edit_control=None ):
173        QRadioButton.__init__(self, parent)
174        self.group = group
175        self.option = option
176        self.default = default
177        self.job_option = True
178        self.setObjectName(name)
179
180
181    def setRangeEdit(self, edit_control):
182        self.edit_control = edit_control
183
184
185    def setDefaultPushbutton(self, pushbutton):
186        self.pushbutton = pushbutton
187
188
189
190class PrintSettingsToolbox(QToolBox):
191    def __init__(self, parent, include_job_options=False):
192        QToolBox.__init__(self, parent)
193        self.include_job_options = include_job_options
194        self.plus_icon = QIcon(load_pixmap('plus', '16x16'))
195        self.minus_icon = QIcon(load_pixmap('minus', '16x16'))
196        self.last_item = 0
197        self.job_options = {}
198        self.job_storage_enable = False
199        self.ppd_type = 0
200        self.pin_count = 0
201
202        self.connect(self, SIGNAL("currentChanged(int)"), self.PrintSettingsToolbox_currentChanged)
203
204
205    def getPrintCommands(self, file_list=None):
206        # File list: [(path, mime_type, mime_desc, title, num_pages), ...]
207        if file_list is None or not file_list:
208            return []
209
210        print_commands = []
211
212        try:
213            copies = int(self.job_options['copies'])
214        except ValueError:
215            copies = 1
216
217        if copies < 1:
218            copies = 1
219            log.warning("Copies < 1, setting to 1.")
220        elif copies > 99:
221            copies = 99
222            log.warning("Copies > 99, setting to 99.")
223
224        #page_range = unicode(self.pageRangeEdit.text())
225        page_range = self.job_options['pagerange']
226
227        try:
228            x = utils.expand_range(page_range)
229        except ValueError:
230            log.error("Invalid page range: %s" % page_range)
231            return []
232
233        all_pages = not page_range
234        #page_set = int(self.pageSetComboBox.currentItem())
235        page_set = self.job_options['pageset']
236
237        cups.resetOptions()
238        cups.openPPD(self.cur_printer)
239        current_options = dict(cups.getOptions())
240        # Handling booklet options
241        if 'HPBookletFilter' in current_options:
242            if 'HPBookletPageSize' in current_options:
243                booklet_pagesize = current_options.get('HPBookletPageSize')
244            else:
245                booklet_pagesize = 'letter'
246            # NEED TO sET THE OPTIONS DICTIONARY
247            self.setPrinterOption('fitplot', 'true')
248            self.setPrinterOption('Duplex', 'DuplexTumble')
249            self.setPrinterOption('PageSize', booklet_pagesize)
250            self.setPrinterOption('number-up', '1')
251        cups.closePPD()
252
253        cups.openPPD(self.cur_printer)
254        if self.ppd_type == 1 and self.pin_count == 0:
255           self.setPrinterOption("HPDigit", "1111")
256        current_options = dict(cups.getOptions())
257        cups.closePPD()
258
259        nup = int(current_options.get("number-up", 1))
260        psnup = utils.which('psnup')
261
262        for p, t, d, title, num_pages in file_list:
263            alt_nup = (nup > 1 and t == 'application/postscript' and psnup)
264
265            if utils.which('lpr'):
266                if alt_nup:
267                    cmd = ' '.join(['psnup', '-%d' % nup, ''.join(['"', p, '"']), '| lpr -P', self.cur_printer])
268                else:
269                    cmd = ' '.join(['lpr -P', self.cur_printer])
270
271                if copies > 1:
272                    cmd = ' '.join([cmd, '-#%d' % copies])
273
274            else: # lp
275                if alt_nup:
276                    cmd = ' '.join(['psnup', '-%d' % nup, ''.join(['"', p, '"']), '| lp -c -d', self.cur_printer])
277                else:
278                    cmd = ' '.join(['lp -c -d', self.cur_printer])
279
280                if copies > 1:
281                    cmd = ' '.join([cmd, '-n%d' % copies])
282
283
284            if not all_pages and page_range:
285                cmd = ' '.join([cmd, '-o page-ranges=%s' % page_range])
286
287            #fit_to_page = "fit-to-page"
288            # code added for ps orientation issue but its on cups
289            #cmd = ' '.join([cmd, '-o %s' % fit_to_page])
290
291            if page_set:
292                cmd = ' '.join([cmd, '-o page-set=%s' % page_set])
293
294            # Job Storage
295            # self.job_storage_mode = (0=Off, 1=P&H, 2=PJ, 3=QC, 4=SJ)
296            # self.job_storage_pin = u"" (dddd)
297            # self.job_storage_use_pin = True|False
298            # self.job_storage_username = u""
299            # self.job_storage_auto_username = True|False
300            # self.job_storage_jobname = u""
301            # self.job_storage_auto_jobname = True|False
302            # self.job_storage_job_exist = (0=replace, 1=job name+(1-99))
303
304            if self.job_storage_enable:
305                if self.job_storage_mode != JOB_STORAGE_TYPE_OFF:
306                    if self.job_storage_mode == JOB_STORAGE_TYPE_PROOF_AND_HOLD:
307                        cmd = ' '.join([cmd, '-o HOLD=PROOF'])
308
309                    elif self.job_storage_mode == JOB_STORAGE_TYPE_PERSONAL:
310                        if self.job_storage_use_pin:
311                            cmd = ' '.join([cmd, '-o HOLD=ON'])
312                            cmd = ' '.join([cmd, '-o HOLDTYPE=PRIVATE'])
313                            cmd = ' '.join([cmd, '-o HOLDKEY=%s' % self.job_storage_pin.encode('ascii')])
314                        else:
315                            cmd = ' '.join([cmd, '-o HOLD=PROOF'])
316                            cmd = ' '.join([cmd, '-o HOLDTYPE=PRIVATE'])
317
318                    elif self.job_storage_mode == JOB_STORAGE_TYPE_QUICK_COPY:
319                        cmd = ' '.join([cmd, '-o HOLD=ON'])
320                        cmd = ' '.join([cmd, '-o HOLDTYPE=PUBLIC'])
321
322                    elif self.job_storage_mode == JOB_STORAGE_TYPE_STORE:
323                        if self.job_storage_use_pin:
324                            cmd = ' '.join([cmd, '-o HOLD=STORE'])
325                            cmd = ' '.join([cmd, '-o HOLDTYPE=PRIVATE'])
326                            cmd = ' '.join([cmd, '-o HOLDKEY=%s' % self.job_storage_pin.encode('ascii')])
327                        else:
328                            cmd = ' '.join([cmd, '-o HOLD=STORE'])
329
330                    cmd = ' '.join([cmd, '-o USERNAME=%s' % self.job_storage_username.encode('ascii')\
331                        .replace(" ", "_")])
332
333                    cmd = ' '.join([cmd, '-o JOBNAME=%s' % self.job_storage_jobname.encode('ascii')\
334                        .replace(" ", "_")])
335
336                    if self.job_storage_job_exist == 1:
337                        cmd = ' '.join([cmd, '-o DUPLICATEJOB=APPEND'])
338                    else:
339                        cmd = ' '.join([cmd, '-o DUPLICATEJOB=REPLACE'])
340
341                else: # Off
342                    cmd = ' '.join([cmd, '-o HOLD=OFF'])
343
344            if not alt_nup:
345                cmd = ''.join([cmd, ' "', p, '"'])
346
347            print_commands.append(cmd)
348
349        return print_commands
350
351
352    def PrintSettingsToolbox_currentChanged(self, i):
353        if i != -1:
354            self.setItemIcon(self.last_item, self.plus_icon)
355            self.setItemIcon(i, self.minus_icon)
356            self.last_item = i
357
358
359    def updateUi(self, cur_device, cur_printer):
360        #print "updateUi(%s, %s)" % (cur_device, cur_printer)
361        self.cur_device = cur_device
362        self.cur_printer = cur_printer
363
364        while self.count():
365            self.removeItem(0)
366
367        self.loading = True
368        cups.resetOptions()
369        cups.openPPD(self.cur_printer)
370        cur_outputmode = ""
371
372        try:
373            if 1:
374            #try:
375                current_options = dict(cups.getOptions())
376
377                if self.include_job_options:
378                    self.beginControlGroup("job_options", self.__tr("Job Options"))
379
380                    # Num. copies (SPINNER)
381                    try:
382                        current = int(current_options.get('copies', '1'))
383                    except ValueError:
384                        current = 1
385
386                    self.addControlRow("copies", self.__tr("Number of copies"),
387                        cups.UI_SPINNER, current, (1, 99), 1, job_option=True)
388                    self.job_options['copies'] = current
389
390                    # page range RADIO + RANGE (custom)
391                    current = current_options.get('pagerange', '')
392
393                    self.addControlRow("pagerange", self.__tr("Page Range"),
394                        cups.UI_PAGE_RANGE, current, None, None, job_option=True)
395
396                    self.job_options['pagerange'] = current
397
398                    # page set (COMBO/PICKONE)
399                    current = current_options.get('pageset', 'all')
400                    self.addControlRow("pageset", self.__tr("Page Set"),
401                        cups.PPD_UI_PICKONE, current,
402                        [('all', self.__tr("AllPages")),
403                         ('even', self.__tr("Even")),
404                         ('odd', self.__tr("Odd"))], 'all', job_option=True)
405
406                    self.job_options['pageset'] = current
407#                    if current == u'even':
408#                        self.job_options["pageset"] = PAGE_SET_EVEN
409#                    elif current == u'odd':
410#                        self.job_options["pageset"] = PAGE_SET_ODD
411#                    else:
412#                        self.job_options["pageset"] = PAGE_SET_ALL
413
414                    self.endControlGroup() # job_options
415
416                if not self.cur_device.device_type == DEVICE_TYPE_FAX:
417                    self.beginControlGroup("basic", self.__tr("Basic"))
418
419                    # Basic
420                        # PageSize (in PPD section)
421                        # orientation-requested
422                        # sides
423                        # outputorder
424                        # Collate
425
426                    current = current_options.get('orientation-requested', '3')
427
428                    self.addControlRow("orientation-requested", self.__tr("Page Orientation"),
429                        cups.PPD_UI_PICKONE, current,
430                        [('3', self.__tr('Portrait')),
431                         ('4', self.__tr('Landscape')),
432                         ('5', self.__tr('Reverse landscape')),
433                         ('6', self.__tr('Reverse portrait'))], '3')
434
435                    log.debug("Option: orientation-requested")
436                    log.debug("Current value: %s" % current)
437
438                    duplexer = self.cur_device.dq.get('duplexer', 0)
439                    log.debug("Duplexer = %d" % duplexer)
440
441                    if duplexer:
442                        current = current_options.get('sides', 'one-sided')
443                        self.addControlRow("sides",
444                            self.__tr("Duplex (Print on both sides of the page)"),
445                            cups.PPD_UI_PICKONE, current,
446                            [('one-sided',self.__tr('Single sided')),
447                             ('two-sided-long-edge', self.__tr('Two sided (long edge)')),
448                             ('two-sided-short-edge', self.__tr('Two sided (short edge)'))], 'one-sided')
449
450                        log.debug("Option: sides")
451                        log.debug("Current value: %s" % current)
452
453                    current = current_options.get('outputorder', 'normal')
454
455                    self.addControlRow("outputorder",
456                        self.__tr("Output Order"),
457                        cups.PPD_UI_PICKONE, current,
458                        [('normal', self.__tr('Normal (Print first page first)')),
459                         ('reverse', self.__tr('Reversed (Print last page first)'))], 'normal')
460
461                    log.debug("Option: outputorder")
462                    log.debug("Current value: %s" % current)
463
464                    #If collate section is not in the PPD, only then add a collate section.
465                    to_add = cups.duplicateSection("collate")
466                    if to_add == 0:
467                        current = utils.to_bool(current_options.get('Collate', '0'))
468
469                        self.addControlRow("Collate",
470                            self.__tr("Collate (Group together multiple copies)"),
471                            cups.PPD_UI_BOOLEAN, current,
472                            [], 0)
473
474                        log.debug("Option: Collate")
475                        log.debug("Current value: %s" % current)
476
477                    self.endControlGroup()
478
479                groups = cups.getGroupList()
480
481                #print groups
482
483                for g in groups:
484                    if 'jobretention' in g.lower():
485                        log.debug("HPJobRetention skipped.")
486                        continue
487
488                    try:
489                        text, num_subgroups = cups.getGroup(g)
490                        if text == "JCL":
491                           text = "Secure Printing"
492                           self.ppd_type = 1
493                    except TypeError:
494                        log.warn("Group %s returned None" % g)
495                        continue
496
497                    read_only = 'install' in g.lower()
498
499
500                    if g.lower() == 'printoutmode':
501                        text = self.__tr("Quality (also see 'Printout Mode' under 'General')")
502
503                    self.beginControlGroup(g, QString(text))
504
505                    log.debug("  Text: %s" % str(text))
506                    log.debug("Num subgroups: %d" % num_subgroups)
507
508                    options = cups.getOptionList(g)
509
510                    #print options
511
512                    for o in options:
513                        log.debug("  Option: %s" % repr(o))
514
515                        if 'pageregion' in o.lower():
516                            log.debug("Page Region skipped.")
517                            continue
518
519                        try:
520                            option_text, defchoice, conflicted, ui  = cups.getOption(g, o)
521                        except TypeError:
522                            log.warn("Option %s in group %s returned None" % (o, g))
523                            continue
524
525
526                        if o.lower() == 'quality':
527                            option_text = self.__tr("Quality")
528
529                        log.debug("    Text: %s" % repr(option_text))
530                        log.debug("    Defchoice: %s" % repr(defchoice))
531
532                        choices = cups.getChoiceList(g, o)
533
534                        value = None
535                        choice_data = []
536                        for c in choices:
537                            log.debug("    Choice: %s" % repr(c))
538
539                            # TODO: Add custom paper size controls
540                            if 'pagesize' in o.lower() and 'custom' in c.lower():
541                                log.debug("Skipped.")
542                                continue
543
544                            choice_text, marked = cups.getChoice(g, o, c)
545
546
547                            log.debug("      Text: %s" % repr(choice_text))
548
549                            if marked:
550                                value = c
551
552                            choice_data.append((c, choice_text))
553
554                        if o.lower() == 'outputmode':
555                            if value is not None:
556                                cur_outputmode = value
557                            else:
558                                cur_outputmode = defchoice
559                        if option_text == "[Pin-4 Digits]":
560                           self.addControlRow(o, option_text, cups.UI_SPINNER, 1111, (1000, 9999), 1111)
561                        else:
562                           self.addControlRow(o, option_text, ui, value, choice_data, defchoice, read_only)
563
564                    self.endControlGroup()
565
566##                        if 'pagesize' in o.lower(): # and 'custom' in c.lower():
567##                            current = 0.0
568##                            width_widget = self.addControlRow(widget, "custom", "custom-width", self.__tr("Custom Paper Width"), cups.UI_UNITS_SPINNER,
569##                                current, (0.0, 0.0), 0.0)
570##
571##                            current = 0.0
572##                            height_widget = self.addControlRow("custom", "custom-height", self.__tr("Custom Paper Height"), cups.UI_UNITS_SPINNER,
573##                                current, (0.0, 0.0), 0.0)
574##
575##                            if value.lower() == 'custom':
576##                                pass
577
578                # N-Up
579                    # number-up
580                    # number-up-layout
581                    # page-border
582
583                self.beginControlGroup("nup", self.__tr("N-Up (Multiple document pages per printed page)"))
584                current = current_options.get('number-up', '1')
585
586                self.addControlRow("number-up", self.__tr("Pages per Sheet"),
587                    cups.PPD_UI_PICKONE, current,
588                    [('1', self.__tr('1 page per sheet')),
589                     ('2', self.__tr('2 pages per sheet')),
590                     ('4', self.__tr('4 pages per sheet'))], '1')
591
592                log.debug("  Option: number-up")
593                log.debug("  Current value: %s" % current)
594
595                current = current_options.get('number-up-layout', 'lrtb')
596
597                self.addControlRow("number-up-layout", self.__tr("Layout"),
598                    cups.PPD_UI_PICKONE, current,
599                    [('btlr', self.__tr('Bottom to top, left to right')),
600                     ('btrl', self.__tr('Bottom to top, right to left')),
601                     ('lrbt', self.__tr('Left to right, bottom to top')),
602                     ('lrtb', self.__tr('Left to right, top to bottom')),
603                     ('rlbt', self.__tr('Right to left, bottom to top')),
604                     ('rltb', self.__tr('Right to left, top to bottom')),
605                     ('tblr', self.__tr('Top to bottom, left to right')),
606                     ('tbrl', self.__tr('Top to bottom, right to left')) ], 'lrtb')
607
608                log.debug("  Option: number-up-layout")
609                log.debug("  Current value: %s" % current)
610
611                current = current_options.get('page-border', 'none')
612
613                self.addControlRow("page-border",
614                    self.__tr("Printed Border Around Each Page"),
615                    cups.PPD_UI_PICKONE, current,
616                    [('double', self.__tr("Two thin borders")),
617                     ("double-thick", self.__tr("Two thick borders")),
618                     ("none", self.__tr("No border")),
619                     ("single", self.__tr("One thin border")),
620                     ("single-thick", self.__tr("One thick border"))], 'none')
621
622                log.debug("  Option: page-border")
623                log.debug("  Current value: %s" % current)
624
625                self.endControlGroup()
626
627                # Adjustment
628                    # brightness
629                    # gamma
630
631                if not self.cur_device.device_type == DEVICE_TYPE_FAX:
632                    self.beginControlGroup("adjustment", self.__tr("Printout Appearance"))
633
634                    current = int(current_options.get('brightness', 100))
635
636                    log.debug("  Option: brightness")
637                    log.debug("  Current value: %s" % current)
638
639                    self.addControlRow("brightness", self.__tr("Brightness"),
640                        cups.UI_SPINNER, current, (0, 200), 100, suffix=" %")
641
642                    current = int(current_options.get('gamma', 1000))
643
644                    log.debug("  Option: gamma")
645                    log.debug("  Current value: %s" % current)
646
647                    self.addControlRow("gamma", self.__tr("Gamma"), cups.UI_SPINNER, current,
648                        (1, 10000), 1000)
649
650                    self.endControlGroup()
651
652                # Margins (pts)
653                    # page-left
654                    # page-right
655                    # page-top
656                    # page-bottom
657
658##                if 0:
659##                    # TODO: cupsPPDPageSize() fails on LaserJets. How do we get margins in this case? Defaults?
660##                    # PPD file for LJs has a HWMargin entry...
661##                    page, page_width, page_len, left, bottom, right, top = cups.getPPDPageSize()
662##
663##                    right = page_width - right
664##                    top = page_len - top
665##
666##                    self.addGroupHeading("margins", self.__tr("Margins"))
667##                    current_top = current_options.get('page-top', 0) # pts
668##                    current_bottom = current_options.get('page-bottom', 0) # pts
669##                    current_left = current_options.get('page-left', 0) # pts
670##                    current_right = current_options.get('page-right', 0) # pts
671##
672##                    log.debug("  Option: page-top")
673##                    log.debug("  Current value: %s" % current_top)
674##
675##                    self.addControlRow("margins", "page-top", self.__tr("Top margin"),
676##                        cups.UI_UNITS_SPINNER, current_top,
677##                        (0, page_len), top)
678##
679##                    self.addControlRow("margins", "page-bottom", self.__tr("Bottom margin"),
680##                        cups.UI_UNITS_SPINNER, current_bottom,
681##                        (0, page_len), bottom)
682##
683##                    self.addControlRow("margins", "page-left", self.__tr("Right margin"),
684##                        cups.UI_UNITS_SPINNER, current_left,
685##                        (0, page_width), left)
686##
687##                    self.addControlRow("margins", "page-right", self.__tr("Left margin"),
688##                        cups.UI_UNITS_SPINNER, current_right,
689##                        (0, page_width), right)
690
691                # Image Printing
692                    # position
693                    # natural-scaling
694                    # saturation
695                    # hue
696
697                self.beginControlGroup("image", self.__tr("Image Printing"))
698
699                current = utils.to_bool(current_options.get('fitplot', 'false'))
700
701                self.addControlRow("fitplot",
702                    self.__tr("Fit to Page"),
703                    cups.PPD_UI_BOOLEAN, current,
704                    [], 0)
705
706                current = current_options.get('position', 'center')
707
708                self.addControlRow("position", self.__tr("Position on Page"),
709                    cups.PPD_UI_PICKONE, current,
710                    [('center', self.__tr('Centered')),
711                     ('top', self.__tr('Top')),
712                     ('left', self.__tr('Left')),
713                     ('right', self.__tr('Right')),
714                     ('top-left', self.__tr('Top left')),
715                     ('top-right', self.__tr('Top right')),
716                     ('bottom', self.__tr('Bottom')),
717                     ('bottom-left', self.__tr('Bottom left')),
718                     ('bottom-right', self.__tr('Bottom right'))], 'center')
719
720                log.debug("  Option: position")
721                log.debug("  Current value: %s" % current)
722
723                if not self.cur_device.device_type == DEVICE_TYPE_FAX:
724                    current = int(current_options.get('saturation', 100))
725
726                    log.debug("  Option: saturation")
727                    log.debug("  Current value: %s" % current)
728
729                    self.addControlRow("saturation", self.__tr("Saturation"),
730                        cups.UI_SPINNER, current, (0, 200), 100, suffix=" %")
731
732                    current = int(current_options.get('hue', 0))
733
734                    log.debug("  Option: hue")
735                    log.debug("  Current value: %s" % current)
736
737                    self.addControlRow("hue", self.__tr("Hue (color shift/rotation)"),
738                        cups.UI_SPINNER, current,
739                        (-100, 100), 0)
740
741                current = int(current_options.get('natural-scaling', 100))
742
743                log.debug("  Option: natural-scaling")
744                log.debug("  Current value: %s" % current)
745
746                self.addControlRow("natural-scaling",
747                    self.__tr('"Natural" Scaling (relative to image)'),
748                    cups.UI_SPINNER, current, (1, 800), 100, suffix=" %")
749
750                current = int(current_options.get('scaling', 100))
751
752                log.debug("  Option: scaling")
753                log.debug("  Current value: %s" % current)
754
755                self.addControlRow("scaling", self.__tr("Scaling (relative to page)"),
756                    cups.UI_SPINNER, current,
757                    (1, 800), 100, suffix=" %")
758
759                self.endControlGroup()
760
761                # Misc
762                    # PrettyPrint
763                    # job-sheets
764                    # mirror
765
766                self.beginControlGroup("misc", self.__tr("Miscellaneous"))
767
768                log.debug("Group: Misc")
769
770                current = utils.to_bool(current_options.get('prettyprint', '0'))
771
772                self.addControlRow("prettyprint",
773                    self.__tr('"Pretty Print" Text Documents (Add headers and formatting)'),
774                    cups.PPD_UI_BOOLEAN, current, [], 0)
775
776                log.debug("  Option: prettyprint")
777                log.debug("  Current value: %s" % current)
778
779                if not self.cur_device.device_type == DEVICE_TYPE_FAX:
780                    current = current_options.get('job-sheets', 'none').split(',')
781
782                    try:
783                        start = current[0]
784                    except IndexError:
785                        start = 'none'
786
787                    try:
788                        end = current[1]
789                    except IndexError:
790                        end = 'none'
791
792                    # TODO: Look for locally installed banner pages beyond the default CUPS ones?
793                    self.addControlRow("job-sheets", self.__tr("Banner Pages"), cups.UI_BANNER_JOB_SHEETS,
794                        (start, end),
795                        [("none", self.__tr("No banner page")),
796                         ('classified', self.__tr("Classified")),
797                         ('confidential', self.__tr("Confidential")),
798                         ('secret', self.__tr("Secret")),
799                         ('standard', self.__tr("Standard")),
800                         ('topsecret', self.__tr("Top secret")),
801                         ('unclassified', self.__tr("Unclassified"))], ('none', 'none'))
802
803                    log.debug("  Option: job-sheets")
804                    log.debug("  Current value: %s,%s" % (start, end))
805
806                current = utils.to_bool(current_options.get('mirror', '0'))
807
808                self.addControlRow("mirror", self.__tr('Mirror Printing'),
809                    cups.PPD_UI_BOOLEAN, current, [], 0)
810
811                log.debug("  Option: mirror")
812                log.debug("  Current value: %s" % current)
813
814                self.endControlGroup()
815
816                #Summary
817                    #color input
818                    #quality
819                quality_attr_name = "OutputModeDPI"
820                cur_outputmode_dpi = cups.findPPDAttribute(quality_attr_name, cur_outputmode)
821                if cur_outputmode_dpi is not None:
822                    log.debug("Adding Group: Summary outputmode is : %s" % cur_outputmode)
823                    log.debug("Adding Group: Summary outputmode dpi is : %s" % to_unicode (cur_outputmode_dpi))
824                    self.beginControlGroup("sumry", self.__tr("Summary"))
825                    self.addControlRow("colorinput", self.__tr('Color Input / Black Render'),
826                        cups.UI_INFO, to_unicode (cur_outputmode_dpi), [], read_only)
827                    self.addControlRow("quality", self.__tr('Print Quality'),
828                        cups.UI_INFO, cur_outputmode, [], read_only)
829                    self.endControlGroup()
830                    log.debug("End adding Group: Summary")
831
832
833                self.job_storage_enable = 0 #self.cur_device.mq.get('job-storage', JOB_STORAGE_DISABLE) == JOB_STORAGE_ENABLE
834
835
836                if self.job_storage_enable:
837                    self.job_storage_pin = to_unicode(current_options.get('HOLDKEY', '0000')[:4])
838                    self.job_storage_username = to_unicode(current_options.get('USERNAME', prop.username)[:16])
839                    self.job_storage_jobname = to_unicode(current_options.get('JOBNAME', to_unicode('Untitled'))[:16])
840                    hold = to_unicode(current_options.get('HOLD', to_unicode('OFF')))
841                    holdtype = to_unicode(current_options.get('HOLDTYPE', to_unicode('PUBLIC')))
842                    self.job_storage_use_pin = False
843                    duplicate = to_unicode(current_options.get('DUPLICATEJOB', to_unicode('REPLACE')))
844                    self.job_storage_auto_username = True
845                    self.job_storage_auto_jobname = True
846                    self.job_storage_mode = JOB_STORAGE_TYPE_OFF
847
848                    if hold == 'OFF':
849                        self.job_storage_mode = JOB_STORAGE_TYPE_OFF
850
851                    elif hold == 'ON':
852                        if holdtype == to_unicode('PUBLIC'):
853                            self.job_storage_mode = JOB_STORAGE_TYPE_QUICK_COPY
854
855                        else: # 'PRIVATE'
856                            self.job_storage_mode = JOB_STORAGE_TYPE_PERSONAL
857                            self.job_storage_use_pin = True
858
859                    elif hold == to_unicode('PROOF'):
860                        if holdtype == to_unicode('PUBLIC'):
861                            self.job_storage_mode = JOB_STORAGE_TYPE_PROOF_AND_HOLD
862                        else:
863                            self.job_storage_mode = JOB_STORAGE_TYPE_PERSONAL
864                            self.job_storage_use_pin = True
865
866                    elif hold == to_unicode('STORE'):
867                        self.job_storage_mode = JOB_STORAGE_TYPE_STORE
868                        self.job_storage_use_pin = (holdtype == 'PRIVATE')
869
870                    if duplicate == to_unicode('REPLACE'):
871                        self.job_storage_job_exist = JOB_STORAGE_EXISTING_JOB_REPLACE
872                    else: # u'APPEND'
873                        self.job_storage_job_exist = JOB_STORAGE_EXISTING_JOB_APPEND_1_99
874
875                    # option, text, typ, value, choices, default, read_only=False, suffix="", job_option=False)
876
877                    self.beginControlGroup("jobstorage", self.__tr("Job Storage and Secure Printing"))
878
879                    self.addControlRow("job-storage-mode", self.__tr("Mode"),
880                                       cups.UI_JOB_STORAGE_MODE, None, None, None)
881
882                    self.addControlRow("job-storage-pin", self.__tr("Make job private (use PIN to print)"),
883                                      cups.UI_JOB_STORAGE_PIN, None, None, None )
884
885                    self.addControlRow("job-storage-username", self.__tr("User name (for job identification)"),
886                                       cups.UI_JOB_STORAGE_USERNAME, None, None, None)
887
888                    self.addControlRow("job-storage-id", self.__tr("Job name/ID (for job identification)"),
889                                      cups.UI_JOB_STORAGE_ID, None, None, None)
890
891                    self.addControlRow("job-storage-id-exists", self.__tr("If job name/ID already exists..."),
892                                       cups.UI_JOB_STORAGE_ID_EXISTS, None, None, None)
893
894                    self.endControlGroup()
895                    self.updateJobStorageControls()
896
897                # use: self.job_options['xxx'] so that values can be picked up by getPrintCommand(
898
899
900            #except Exception, e:
901                #log.exception()
902            #    pass
903
904        finally:
905            cups.closePPD()
906            self.loading = False
907
908
909    def beginControlGroup(self, group, text):
910        log.debug("BeginGroup: %s" % group)
911        self.row = 0
912        self.widget = QWidget()
913        self.gridlayout = QGridLayout(self.widget)
914        self.group = group
915        self.text = text
916
917
918    def endControlGroup(self):
919        log.debug("EndGroup: %s" % self.group)
920        spacer = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding)
921        self.row += 1
922        self.gridlayout.addItem(spacer, self.row, 0, 1, 1)
923        i = self.addItem(self.widget, self.text)
924
925        if i:
926            self.setItemIcon(i, self.plus_icon)
927        else:
928            self.setItemIcon(i, self.minus_icon)
929
930        self.widget, self.gridlayout = None, None
931
932
933    def addControlRow(self, option, text, typ, value, choices, default, read_only=False, suffix="", job_option=False):
934
935        if typ == cups.PPD_UI_BOOLEAN: # () On (*) Off widget
936            HBoxLayout = QHBoxLayout()
937            HBoxLayout.setObjectName("HBoxLayout")
938
939            OptionLabel = QLabel(self.widget)
940            OptionLabel.setObjectName("OptionLabel")
941            HBoxLayout.addWidget(OptionLabel)
942
943            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
944            HBoxLayout.addItem(SpacerItem)
945
946            GroupBox = QFrame(self.widget)
947
948            gridlayout1 = QGridLayout(GroupBox)
949            OnRadioButton = OptionRadioButton(GroupBox, "OnRadioButton", self.group,
950                                              option, default, job_option)
951            gridlayout1.addWidget(OnRadioButton,0,0,1,1)
952            OffRadioButton = OptionRadioButton(GroupBox, "OffRadioButton", self.group,
953                                               option, default, job_option)
954            gridlayout1.addWidget(OffRadioButton,0,1,1,1)
955            HBoxLayout.addWidget(GroupBox)
956
957            DefaultButton = DefaultPushButton(self.widget, "defaultPushButton", self.group, option,
958                choices, default, (OnRadioButton, OffRadioButton), typ, job_option)
959
960            #GroupBox.setDefaultPushbutton(DefaultButton)
961            OnRadioButton.setDefaultPushbutton(DefaultButton)
962            OffRadioButton.setDefaultPushbutton(DefaultButton)
963
964            HBoxLayout.addWidget(DefaultButton)
965            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
966
967            OptionLabel.setText(text)
968            OnRadioButton.setText(self.__tr("On"))
969            OffRadioButton.setText(self.__tr("Off"))
970
971            DefaultButton.setText("Default")
972
973            #type of 'value' and 'default' can be unicode (ppd values), str, int or boolean, so we need to typecast it to bool for easy comparison
974            if value == True or value == 'True' or value == 'true':
975               value = True;
976            else:
977               value = False;
978
979            if default == True or default == 'True' or default == 'true':
980               default = True;
981            else:
982               default = False;
983
984            if value == default:
985                DefaultButton.setEnabled(False)
986            self.connect(DefaultButton, SIGNAL("clicked()"), self.DefaultButton_clicked)
987
988            if value:
989                OnRadioButton.setChecked(True)
990            else:
991                OffRadioButton.setChecked(True)
992            self.connect(OnRadioButton, SIGNAL("toggled(bool)"), self.BoolRadioButtons_clicked)
993
994            if read_only:
995                OnRadioButton.setEnabled(False)
996                OffRadioButton.setEnabled(False)
997                DefaultButton.setEnabled(False)
998
999
1000
1001        elif typ == cups.PPD_UI_PICKONE: # Combo box widget
1002            #print option, job_option
1003            HBoxLayout = QHBoxLayout()
1004            HBoxLayout.setObjectName("HBoxLayout")
1005
1006            OptionLabel = QLabel(self.widget)
1007            OptionLabel.setObjectName("OptionLabel")
1008            HBoxLayout.addWidget(OptionLabel)
1009
1010            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1011            HBoxLayout.addItem(SpacerItem)
1012
1013            ComboBox = OptionComboBox(0, self.widget, "ComboBox", self.group, option,
1014                                      choices, default, typ, None, job_option)
1015
1016            HBoxLayout.addWidget(ComboBox)
1017
1018            DefaultButton = DefaultPushButton(self.widget, "DefaultButton", self.group, option,
1019                choices, default, ComboBox, typ, job_option)
1020
1021            ComboBox.setDefaultPushbutton(DefaultButton)
1022            HBoxLayout.addWidget(DefaultButton)
1023
1024            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1025
1026            OptionLabel.setText(text)
1027            DefaultButton.setText("Default")
1028
1029            i, x, y = 0, None, None
1030            for c, t in choices:
1031                d = c.lower()
1032                if value is not None and d == value.lower():
1033                    x = i
1034
1035                if d == default.lower():
1036                    y = t
1037
1038                ComboBox.insertItem(i, t)
1039                i += 1
1040
1041            if x is not None:
1042                ComboBox.setCurrentIndex(x)
1043            else:
1044                ComboBox.setCurrentIndex(0)
1045
1046            if value is not None and value.lower() == default.lower():
1047                DefaultButton.setEnabled(False)
1048
1049            #self.linkPrintoutModeAndQuality(option, value)
1050#
1051#            if read_only:
1052#                optionComboBox.setEnabled(False)
1053#                defaultPushButton.setEnabled(False)
1054#            elif y is not None:
1055#                QToolTip.add(defaultPushButton, self.__tr('Set to default value of "%1".').arg(y))
1056#
1057
1058            self.connect(DefaultButton, SIGNAL("clicked()"), self.DefaultButton_clicked)
1059            self.connect(ComboBox, SIGNAL("currentIndexChanged(const QString &)"), self.ComboBox_indexChanged)
1060            self.connect(ComboBox, SIGNAL("highlighted(const QString &)"), self.ComboBox_highlighted)
1061
1062            control = ComboBox
1063
1064        elif typ == cups.UI_SPINNER: # Spinner widget
1065
1066            HBoxLayout = QHBoxLayout()
1067            HBoxLayout.setObjectName("HBoxLayout")
1068
1069            OptionLabel = QLabel(self.widget)
1070            OptionLabel.setObjectName("OptionLabel")
1071            HBoxLayout.addWidget(OptionLabel)
1072
1073            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1074            HBoxLayout.addItem(SpacerItem)
1075
1076            SpinBox = OptionSpinBox(self.widget,"SpinBox", self.group, option, default, job_option)
1077            HBoxLayout.addWidget(SpinBox)
1078
1079            DefaultButton = DefaultPushButton(self.widget,"DefaultButton", self.group, option,
1080                choices, default, SpinBox, typ, job_option)
1081
1082            SpinBox.setDefaultPushbutton(DefaultButton)
1083            HBoxLayout.addWidget(DefaultButton)
1084
1085            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1086
1087            min, max = choices
1088            SpinBox.setMinimum(min)
1089            SpinBox.setMaximum(max)
1090            SpinBox.setValue(value)
1091
1092            if suffix:
1093                SpinBox.setSuffix(suffix)
1094
1095            OptionLabel.setText(text)
1096            DefaultButton.setText("Default")
1097
1098            self.connect(SpinBox, SIGNAL("valueChanged(int)"), self.SpinBox_valueChanged)
1099            self.connect(DefaultButton, SIGNAL("clicked()"), self.DefaultButton_clicked)
1100
1101            DefaultButton.setEnabled(not value == default)
1102
1103            if read_only:
1104                SpinBox.setEnabled(False)
1105                DefaultButton.setEnabled(False)
1106
1107        elif typ == cups.UI_BANNER_JOB_SHEETS:  # Job sheets widget
1108            HBoxLayout = QHBoxLayout()
1109            HBoxLayout.setObjectName("HBoxLayout")
1110
1111            OptionLabel = QLabel(self.widget)
1112            OptionLabel.setObjectName("OptionLabel")
1113            HBoxLayout.addWidget(OptionLabel)
1114
1115            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1116            HBoxLayout.addItem(SpacerItem)
1117
1118            StartLabel = QLabel(self.widget)
1119            HBoxLayout.addWidget(StartLabel)
1120
1121            StartComboBox = OptionComboBox(0, self.widget, "StartComboBox", self.group,
1122                "start", choices, default, typ)
1123
1124            HBoxLayout.addWidget(StartComboBox)
1125
1126            EndLabel = QLabel(self.widget)
1127            HBoxLayout.addWidget(EndLabel)
1128
1129            EndComboBox = OptionComboBox(0, self.widget, "EndComboBox", self.group, "end", choices,
1130                default, typ, StartComboBox)
1131
1132            HBoxLayout.addWidget(EndComboBox)
1133
1134            StartComboBox.setOther(EndComboBox)
1135
1136            DefaultButton = DefaultPushButton(self.widget, "DefaultButton", self.group, option, choices,
1137                default, (StartComboBox, EndComboBox), typ, job_option)
1138
1139            HBoxLayout.addWidget(DefaultButton)
1140
1141            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1142
1143            StartComboBox.setDefaultPushbutton(DefaultButton)
1144            EndComboBox.setDefaultPushbutton(DefaultButton)
1145
1146            OptionLabel.setText(text)
1147            DefaultButton.setText("Default")
1148
1149            StartLabel.setText(self.__tr("Start:"))
1150            EndLabel.setText(self.__tr("End:"))
1151
1152            s, e, y, z = None, None, None, None
1153            for c, t in choices:
1154                d = c.lower()
1155                if value is not None:
1156                    if d == value[0].lower():
1157                        s = t
1158
1159                    if d == value[1].lower():
1160                        e = t
1161
1162                if d == default[0].lower():
1163                    y = t
1164
1165                if d == default[1].lower():
1166                    z = t
1167
1168                StartComboBox.insertItem(0, t)
1169                EndComboBox.insertItem(0, t)
1170
1171            if s is not None:
1172                StartComboBox.setCurrentIndex(StartComboBox.findText(s))
1173
1174            if e is not None:
1175                EndComboBox.setCurrentIndex(EndComboBox.findText(e))
1176
1177            if value is not None and \
1178                value[0].lower() == default[0].lower() and \
1179                value[1].lower() == default[1].lower():
1180
1181                DefaultButton.setEnabled(False)
1182
1183            self.connect(StartComboBox, SIGNAL("activated(const QString&)"), self.BannerComboBox_activated)
1184            self.connect(EndComboBox, SIGNAL("activated(const QString&)"), self.BannerComboBox_activated)
1185            self.connect(DefaultButton, SIGNAL("clicked()"), self.DefaultButton_clicked)
1186
1187        elif typ == cups.PPD_UI_PICKMANY:
1188            log.error("Unrecognized type: pickmany")
1189
1190        elif typ == cups.UI_UNITS_SPINNER:
1191            log.error("Unrecognized type: units spinner")
1192
1193        elif typ == cups.UI_PAGE_RANGE:
1194            HBoxLayout = QHBoxLayout()
1195            HBoxLayout.setObjectName("HBoxLayout")
1196
1197            OptionLabel = QLabel(self.widget)
1198            OptionLabel.setObjectName("OptionLabel")
1199            HBoxLayout.addWidget(OptionLabel)
1200
1201            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1202            HBoxLayout.addItem(SpacerItem)
1203
1204            GroupBox = QFrame(self.widget)
1205
1206            gridlayout1 = QGridLayout(GroupBox)
1207
1208            AllRadioButton = PageRangeRadioButton(GroupBox, "AllRadioButton",
1209                                               self.group, option, default)
1210
1211            gridlayout1.addWidget(AllRadioButton,0,0,1,1)
1212            RangeRadioButton = PageRangeRadioButton(GroupBox, "RangeRadioButton",
1213                                                 self.group, option, default)
1214
1215            gridlayout1.addWidget(RangeRadioButton,0,1,1,1)
1216            HBoxLayout.addWidget(GroupBox)
1217
1218            PageRangeEdit = QLineEdit(self.widget)
1219            HBoxLayout.addWidget(PageRangeEdit)
1220            PageRangeEdit.setValidator(RangeValidator(PageRangeEdit))
1221
1222            AllRadioButton.setRangeEdit(PageRangeEdit)
1223            RangeRadioButton.setRangeEdit(PageRangeEdit)
1224
1225            DefaultButton = DefaultPushButton(self.widget, "defaultPushButton", self.group, option,
1226                choices, default, (AllRadioButton, RangeRadioButton, PageRangeEdit), typ, job_option)
1227
1228            AllRadioButton.setDefaultPushbutton(DefaultButton)
1229            RangeRadioButton.setDefaultPushbutton(DefaultButton)
1230
1231            HBoxLayout.addWidget(DefaultButton)
1232            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1233
1234            OptionLabel.setText(text)
1235            AllRadioButton.setText(self.__tr("All pages"))
1236            RangeRadioButton.setText(self.__tr("Page Range:"))
1237
1238            DefaultButton.setText("Default")
1239            DefaultButton.setEnabled(False)
1240
1241            AllRadioButton.setChecked(True)
1242            PageRangeEdit.setEnabled(False)
1243
1244            # TODO: Set current
1245
1246            self.connect(AllRadioButton, SIGNAL("toggled(bool)"), self.PageRangeAllRadio_toggled)
1247            self.connect(RangeRadioButton, SIGNAL("toggled(bool)"), self.PageRangeRangeRadio_toggled)
1248            self.connect(DefaultButton, SIGNAL("clicked()"), self.DefaultButton_clicked)
1249            self.connect(PageRangeEdit, SIGNAL("textChanged(const QString &)"), self.PageRangeEdit_textChanged)
1250            self.connect(PageRangeEdit, SIGNAL("editingFinished()"), self.PageRangeEdit_editingFinished)
1251
1252        elif typ == cups.UI_JOB_STORAGE_MODE:
1253            HBoxLayout = QHBoxLayout()
1254            HBoxLayout.setObjectName("HBoxLayout")
1255
1256            OptionLabel = QLabel(self.widget)
1257            OptionLabel.setObjectName("OptionLabel")
1258            HBoxLayout.addWidget(OptionLabel)
1259
1260            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1261            HBoxLayout.addItem(SpacerItem)
1262
1263            self.JobStorageModeComboBox = QComboBox(self.widget)
1264            HBoxLayout.addWidget(self.JobStorageModeComboBox)
1265
1266            self.JobStorageModeDefaultButton = QPushButton(self.widget)
1267            HBoxLayout.addWidget(self.JobStorageModeDefaultButton)
1268
1269            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1270
1271            OptionLabel.setText(text)
1272            self.JobStorageModeDefaultButton.setText(self.__tr("Default"))
1273
1274            self.JobStorageModeComboBox.addItem(self.__tr("Off/Disabled"), JOB_STORAGE_TYPE_OFF)
1275            self.JobStorageModeComboBox.addItem(self.__tr("Proof and Hold"), JOB_STORAGE_TYPE_PROOF_AND_HOLD)
1276            self.JobStorageModeComboBox.addItem(self.__tr("Personal/Private Job"), JOB_STORAGE_TYPE_PERSONAL)
1277            self.JobStorageModeComboBox.addItem(self.__tr("Quick Copy"), JOB_STORAGE_TYPE_QUICK_COPY)
1278            self.JobStorageModeComboBox.addItem(self.__tr("Stored Job"), JOB_STORAGE_TYPE_STORE)
1279
1280            self.connect(self.JobStorageModeComboBox, SIGNAL("activated(int)"),
1281                        self.JobStorageModeComboBox_activated)
1282
1283            self.connect(self.JobStorageModeDefaultButton, SIGNAL("clicked()"),
1284                        self.JobStorageModeDefaultButton_clicked)
1285
1286
1287        elif typ == cups.UI_JOB_STORAGE_PIN:
1288            HBoxLayout = QHBoxLayout()
1289            HBoxLayout.setObjectName("HBoxLayout")
1290
1291            OptionLabel = QLabel(self.widget)
1292            OptionLabel.setObjectName("OptionLabel")
1293            HBoxLayout.addWidget(OptionLabel)
1294
1295            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1296            HBoxLayout.addItem(SpacerItem)
1297
1298            self.JobStoragePinGroupBox = QFrame(self.widget)
1299
1300            gridlayout1 = QGridLayout(self.JobStoragePinGroupBox)
1301            self.JobStoragePinOffRadioButton = QRadioButton(self.JobStoragePinGroupBox)
1302            gridlayout1.addWidget(self.JobStoragePinOffRadioButton, 0, 0, 1, 1)
1303
1304            self.JobStoragePinPrivateRadioButton = QRadioButton(self.JobStoragePinGroupBox)
1305            gridlayout1.addWidget(self.JobStoragePinPrivateRadioButton, 0, 1, 1, 1)
1306
1307            self.JobStoragePinEdit = QLineEdit(self.JobStoragePinGroupBox)
1308            self.JobStoragePinEdit.setMaxLength(4)
1309            self.JobStoragePinEdit.setValidator(PinValidator(self.JobStoragePinEdit))
1310            gridlayout1.addWidget(self.JobStoragePinEdit, 0, 2, 1, 1)
1311
1312            HBoxLayout.addWidget(self.JobStoragePinGroupBox)
1313
1314            self.JobStoragePinDefaultButton = QPushButton(self.widget)
1315            HBoxLayout.addWidget(self.JobStoragePinDefaultButton)
1316
1317            self.JobStoragePinOffRadioButton.setText(self.__tr("Public/Off"))
1318            self.JobStoragePinPrivateRadioButton.setText(self.__tr("Private/Use PIN:"))
1319
1320            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1321
1322            OptionLabel.setText(text)
1323            self.JobStoragePinDefaultButton.setText(self.__tr("Default"))
1324
1325            self.connect(self.JobStoragePinOffRadioButton, SIGNAL("toggled(bool)"),
1326                            self.JobStoragePinOffRadioButton_toggled)
1327
1328            self.connect(self.JobStoragePinPrivateRadioButton, SIGNAL("toggled(bool)"),
1329                            self.JobStoragePinPrivateRadioButton_toggled)
1330
1331            self.connect(self.JobStoragePinDefaultButton, SIGNAL("clicked()"),
1332                            self.JobStoragePinDefaultButton_clicked)
1333
1334            self.connect(self.JobStoragePinEdit, SIGNAL("textEdited(const QString &)"),
1335                        self.JobStoragePinEdit_textEdited)
1336
1337
1338        elif typ == cups.UI_JOB_STORAGE_USERNAME:
1339            HBoxLayout = QHBoxLayout()
1340            HBoxLayout.setObjectName("HBoxLayout")
1341
1342            OptionLabel = QLabel(self.widget)
1343            OptionLabel.setObjectName("OptionLabel")
1344            HBoxLayout.addWidget(OptionLabel)
1345            OptionLabel.setText(text)
1346
1347            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1348            HBoxLayout.addItem(SpacerItem)
1349
1350            self.JobStorageUsernameGroupBox = QFrame(self.widget)
1351
1352            gridlayout1 = QGridLayout(self.JobStorageUsernameGroupBox)
1353            self.JobStorageUsernameAutoRadioButton = QRadioButton(self.JobStorageUsernameGroupBox)
1354            gridlayout1.addWidget(self.JobStorageUsernameAutoRadioButton, 0, 0, 1, 1)
1355
1356            self.JobStorageUsernameCustomRadioButton = QRadioButton(self.JobStorageUsernameGroupBox)
1357            gridlayout1.addWidget(self.JobStorageUsernameCustomRadioButton, 0, 1, 1, 1)
1358
1359            self.JobStorageUsernameEdit = QLineEdit(self.JobStorageUsernameGroupBox)
1360            self.JobStorageUsernameEdit.setValidator(UsernameAndJobnameValidator(self.JobStorageUsernameEdit))
1361            self.JobStorageUsernameEdit.setMaxLength(16)
1362            gridlayout1.addWidget(self.JobStorageUsernameEdit, 0, 2, 1, 1)
1363
1364            HBoxLayout.addWidget(self.JobStorageUsernameGroupBox)
1365
1366            self.JobStorageUsernameDefaultButton = QPushButton(self.widget)
1367            HBoxLayout.addWidget(self.JobStorageUsernameDefaultButton)
1368
1369            self.JobStorageUsernameAutoRadioButton.setText(self.__tr("Automatic"))
1370            self.JobStorageUsernameCustomRadioButton.setText(self.__tr("Custom:"))
1371            self.JobStorageUsernameDefaultButton.setText(self.__tr("Default"))
1372
1373            self.connect(self.JobStorageUsernameAutoRadioButton, SIGNAL("toggled(bool)"),
1374                            self.JobStorageUsernameAutoRadioButton_toggled)
1375
1376            self.connect(self.JobStorageUsernameCustomRadioButton, SIGNAL("toggled(bool)"),
1377                            self.JobStorageUsernameCustomRadioButton_toggled)
1378
1379            self.connect(self.JobStorageUsernameDefaultButton, SIGNAL("clicked()"),
1380                        self.JobStorageUsernameDefaultButton_clicked)
1381
1382            self.connect(self.JobStorageUsernameEdit, SIGNAL("textEdited(const QString &)"),
1383                        self.JobStorageUsernameEdit_textEdited)
1384
1385            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1386
1387        elif typ == cups.UI_JOB_STORAGE_ID:
1388            HBoxLayout = QHBoxLayout()
1389            HBoxLayout.setObjectName("HBoxLayout")
1390
1391            OptionLabel = QLabel(self.widget)
1392            OptionLabel.setObjectName("OptionLabel")
1393            HBoxLayout.addWidget(OptionLabel)
1394            OptionLabel.setText(text)
1395
1396            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1397            HBoxLayout.addItem(SpacerItem)
1398
1399            self.JobStorageIDGroupBox = QFrame(self.widget)
1400
1401            gridlayout1 = QGridLayout(self.JobStorageIDGroupBox)
1402            self.JobStorageIDAutoRadioButton = QRadioButton(self.JobStorageIDGroupBox)
1403            gridlayout1.addWidget(self.JobStorageIDAutoRadioButton, 0, 0, 1, 1)
1404
1405            self.JobStorageIDCustomRadioButton = QRadioButton(self.JobStorageIDGroupBox)
1406            gridlayout1.addWidget(self.JobStorageIDCustomRadioButton, 0, 1, 1, 1)
1407
1408            self.JobStorageIDEdit = QLineEdit(self.JobStorageIDGroupBox)
1409            self.JobStorageIDEdit.setValidator(UsernameAndJobnameValidator(self.JobStorageIDEdit))
1410            self.JobStorageIDEdit.setMaxLength(16)
1411            gridlayout1.addWidget(self.JobStorageIDEdit, 0, 2, 1, 1)
1412
1413            HBoxLayout.addWidget(self.JobStorageIDGroupBox)
1414
1415            self.JobStorageIDDefaultButton = QPushButton(self.widget)
1416            HBoxLayout.addWidget(self.JobStorageIDDefaultButton)
1417
1418            self.JobStorageIDAutoRadioButton.setText(self.__tr("Automatic"))
1419            self.JobStorageIDCustomRadioButton.setText(self.__tr("Custom:"))
1420            self.JobStorageIDDefaultButton.setText(self.__tr("Default"))
1421
1422            self.connect(self.JobStorageIDAutoRadioButton, SIGNAL("toggled(bool)"),
1423                            self.JobStorageIDAutoRadioButton_toggled)
1424
1425            self.connect(self.JobStorageIDCustomRadioButton, SIGNAL("toggled(bool)"),
1426                            self.JobStorageIDCustomRadioButton_toggled)
1427
1428            self.connect(self.JobStorageIDDefaultButton, SIGNAL("clicked()"),
1429                        self.JobStorageIDDefaultButton_clicked)
1430
1431            self.connect(self.JobStorageIDEdit, SIGNAL("textEdited(const QString &)"),
1432                        self.JobStorageIDEdit_textEdited)
1433
1434            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1435
1436        elif typ == cups.UI_JOB_STORAGE_ID_EXISTS:
1437            HBoxLayout = QHBoxLayout()
1438            HBoxLayout.setObjectName("HBoxLayout")
1439
1440            OptionLabel = QLabel(self.widget)
1441            OptionLabel.setObjectName("OptionLabel")
1442            HBoxLayout.addWidget(OptionLabel)
1443            OptionLabel.setText(text)
1444
1445            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1446            HBoxLayout.addItem(SpacerItem)
1447
1448            self.JobStorageExistingComboBox = QComboBox(self.widget)
1449            HBoxLayout.addWidget(self.JobStorageExistingComboBox)
1450
1451            self.JobStorageExistingDefaultButton = QPushButton(self.widget)
1452            HBoxLayout.addWidget(self.JobStorageExistingDefaultButton)
1453
1454            self.JobStorageExistingComboBox.addItem(self.__tr("Replace existing job"),
1455                             JOB_STORAGE_EXISTING_JOB_REPLACE)
1456
1457            self.JobStorageExistingComboBox.addItem(self.__tr("Use job name appended with 1-99"),
1458                             JOB_STORAGE_EXISTING_JOB_APPEND_1_99)
1459
1460            self.JobStorageExistingDefaultButton.setText(self.__tr("Default"))
1461
1462            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1463
1464            self.connect(self.JobStorageExistingComboBox, SIGNAL("activated(int)"),
1465                        self.JobStorageExistingComboBox_activated)
1466
1467            self.connect(self.JobStorageExistingDefaultButton, SIGNAL("clicked()"),
1468                        self.JobStorageExistingDefaultButton_clicked)
1469
1470        elif typ == cups.UI_INFO:
1471            HBoxLayout = QHBoxLayout()
1472            HBoxLayout.setObjectName("HBoxLayout")
1473
1474            OptionName = QLabel(self.widget)
1475            OptionName.setObjectName("OptionLabel")
1476            HBoxLayout.addWidget(OptionName)
1477            OptionName.setText(text)
1478
1479            SpacerItem = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
1480            HBoxLayout.addItem(SpacerItem)
1481
1482            if text == 'Print Quality':
1483                self.PQValueLabel = QLabel(self.widget)
1484                self.PQValueLabel.setObjectName("PQValueLabel")
1485                HBoxLayout.addWidget(self.PQValueLabel)
1486                self.PQValueLabel.setText(value)
1487            elif text == 'Color Input / Black Render':
1488                self.PQColorInputLabel = QLabel(self.widget)
1489                self.PQColorInputLabel.setObjectName("PQColorInputLabel")
1490                HBoxLayout.addWidget(self.PQColorInputLabel)
1491                self.PQColorInputLabel.setText(value)
1492            else:
1493                OptionValue = QLabel(self.widget)
1494                OptionValue.setObjectName("OptionValue")
1495                HBoxLayout.addWidget(OptionValue)
1496                OptionValue.setText(value)
1497
1498            self.gridlayout.addLayout(HBoxLayout, self.row, 0, 1, 1)
1499
1500        else:
1501            log.error("Invalid UI value: %s/%s" % (self.group, option))
1502
1503        self.row += 1
1504
1505
1506
1507    def BannerComboBox_activated(self, a): # cups.UI_BANNER_JOB_SHEETS
1508        a = to_unicode(a)
1509        sender = self.sender()
1510        choice = None
1511
1512        start, end = None, None
1513        for c, t in sender.choices:
1514            if t == a:
1515                start = c
1516                break
1517
1518        for c, t in sender.other.choices:
1519            if t == sender.other.currentText():
1520                end = c
1521                break
1522
1523        if sender.option == 'end':
1524            start, end = end, start
1525
1526        if start is not None and \
1527            end is not None and \
1528            start.lower() == sender.default[0].lower() and \
1529            end.lower() == sender.default[1].lower():
1530                self.removePrinterOption('job-sheets')
1531                sender.pushbutton.setEnabled(False)
1532        else:
1533            sender.pushbutton.setEnabled(True)
1534
1535            if start is not None and \
1536                end is not None:
1537
1538                self.setPrinterOption('job-sheets', ','.join([start, end]))
1539
1540
1541    def ComboBox_highlighted(self, t):
1542        t = to_unicode(t)
1543        sender = self.sender()
1544        choice = None
1545
1546        #print sender, sender.option, sender.job_option
1547
1548        choice = None
1549        for c, a in sender.choices:
1550            if a == t:
1551                choice = c
1552                break
1553
1554        if choice is not None and choice == sender.default:
1555            if sender.job_option:
1556                self.job_options[sender.option] = sender.default
1557            else:
1558                self.removePrinterOption(sender.option)
1559            sender.pushbutton.setEnabled(False)
1560
1561        else:
1562            sender.pushbutton.setEnabled(True)
1563
1564            if choice is not None:
1565                if sender.job_option:
1566                    self.job_options[sender.option] = choice
1567                else:
1568                    self.setPrinterOption(sender.option, choice)
1569
1570            #self.linkPrintoutModeAndQuality(sender.option, choice)
1571
1572    if 0:
1573        pass
1574        #    def linkPrintoutModeAndQuality(self, option, choice):
1575        #        if option.lower() == 'quality' and \
1576        #            choice is not None:
1577        #
1578        #            try:
1579        #                c = self.items['o:PrintoutMode'].control
1580        #            except KeyError:
1581        #                return
1582        #            else:
1583        #                if c is not None:
1584        #                    if choice.lower() == 'fromprintoutmode':
1585        #                        # from printoutmode selected
1586        #                        # determine printoutmode option combo enable state
1587        #                        c.setEnabled(True)
1588        #                        QToolTip.remove(c)
1589        #                        a = unicode(c.currentText())
1590        #
1591        #                        # determine printoutmode default button state
1592        #                        link_choice = None
1593        #                        for x, t in c.choices:
1594        #                            if t == a:
1595        #                                link_choice = x
1596        #                                break
1597        #
1598        #                        if link_choice is not None and \
1599        #                            link_choice.lower() == c.default.lower():
1600        #
1601        #                            c.pushbutton.setEnabled(False)
1602        #                        else:
1603        #                            c.pushbutton.setEnabled(True)
1604        #
1605        #                    else: # fromprintoutmode not selected, disable printoutmode
1606        #                        c.setEnabled(False)
1607        #                        QToolTip.add(c, self.__tr("""Set Quality to "Controlled by 'Printout Mode'" to enable."""))
1608        #                        c.pushbutton.setEnabled(False)
1609        #
1610
1611    def SpinBox_valueChanged(self, i): # cups.UI_SPINNER
1612        sender = self.sender()
1613        if sender.option == "HPDigit":
1614           self.pin_count = 1
1615        if not sender.job_option:
1616            if i == sender.default:
1617                self.removePrinterOption(sender.option)
1618                sender.pushbutton.setEnabled(False)
1619                if sender.option == "HPDigit":
1620                   self.pin_count = 0
1621            else:
1622                sender.pushbutton.setEnabled(True)
1623                self.setPrinterOption(sender.option, str(i))
1624
1625        else:
1626            try:
1627                self.job_options[sender.option] = int(i)
1628            except ValueError:
1629                self.job_options[sender.option] = sender.default
1630
1631
1632    def BoolRadioButtons_clicked(self, b): # cups.PPD_UI_BOOLEAN
1633        sender = self.sender()
1634        b = int(b)
1635        if sender.default == True or sender.default == "True" or sender.default == "true":
1636            sender.default = int(True)
1637        else:
1638            sender.default = int(False)
1639
1640        if b == sender.default:
1641            self.removePrinterOption(sender.option)
1642            sender.pushbutton.setEnabled(False)
1643        else:
1644            sender.pushbutton.setEnabled(True)
1645
1646            if b:
1647                self.setPrinterOption(sender.option, "true")
1648            else:
1649                self.setPrinterOption(sender.option, "false")
1650
1651    def ComboBox_indexChanged(self, currentItem):
1652        sender = self.sender()
1653        currentItem = to_unicode(currentItem)
1654        # Checking for summary control
1655        labelPQValaue = getattr(self, 'PQValueLabel', None)
1656        labelPQColorInput = getattr(self, 'PQColorInputLabel', None)
1657        # When output mode combo item is changed, we need to update the summary information
1658        if currentItem is not None and sender.option == 'OutputMode' and labelPQValaue is not None and labelPQColorInput is not None:
1659            # Setting output mode
1660            self.PQValueLabel.setText(currentItem)
1661
1662            # Getting DPI custom attributefrom the PPD
1663            # Setting color input
1664            quality_attr_name = "OutputModeDPI"
1665            cups.openPPD(self.cur_printer)
1666            outputmode_dpi = cups.findPPDAttribute(quality_attr_name, currentItem)
1667            log.debug("Outputmode changed, setting outputmode_dpi: %s" % outputmode_dpi)
1668            cups.closePPD()
1669            self.PQColorInputLabel.setText(outputmode_dpi)
1670
1671            log.debug("Outputmode changed, setting value outputmode: %s" % currentItem)
1672
1673    def DefaultButton_clicked(self):
1674        sender = self.sender()
1675        sender.setEnabled(False)
1676
1677        if sender.typ == cups.PPD_UI_BOOLEAN: # () On  (*) Off
1678            if sender.default == True or sender.default == 'True' or sender.default == 'true':
1679                sender.default = True
1680            else:
1681                sender.default = False
1682            if sender.default:
1683                sender.control[0].setChecked(True)
1684                sender.control[0].setFocus(Qt.OtherFocusReason)
1685            else:
1686                sender.control[1].setChecked(True)
1687                sender.control[1].setFocus(Qt.OtherFocusReason)
1688
1689            if not sender.job_option:
1690                self.removePrinterOption(sender.option)
1691
1692        elif sender.typ == cups.PPD_UI_PICKONE: # [     \/]
1693            choice, text = None, None
1694
1695            for c, t in sender.choices:
1696                if c == sender.default:
1697                    choice = c
1698                    text = t
1699                    self.job_options[sender.option] = t
1700                    break
1701
1702            if choice is not None:
1703                if not sender.job_option:
1704                    self.removePrinterOption(sender.option)
1705                index = sender.control.findText(text)
1706                sender.control.setCurrentIndex(index)
1707
1708                #self.linkPrintoutModeAndQuality(sender.option, choice) # TODO:
1709                sender.control.setFocus(Qt.OtherFocusReason)
1710
1711        elif sender.typ == cups.UI_SPINNER: # [ x /\|\/]
1712            sender.control.setValue(sender.default)
1713            if not sender.job_option:
1714                self.removePrinterOption(sender.option)
1715
1716            sender.control.setFocus(Qt.OtherFocusReason)
1717
1718        elif sender.typ == cups.UI_BANNER_JOB_SHEETS: # start: [     \/]  end: [     \/]
1719            start, end, start_text, end_text = None, None, None, None
1720            for c, t in sender.choices:
1721                if c == sender.default[0]:
1722                    start = c
1723                    start_text = t
1724
1725                if c == sender.default[1]:
1726                    end = c
1727                    end_text = t
1728
1729            if start is not None:
1730                index = sender.control[0].findText(start_text)
1731                sender.control[0].setCurrentIndex(index)
1732
1733            if end is not None:
1734                index = sender.control[1].findText(end_text)
1735                sender.control[1].setCurrentIndex(index)
1736
1737            if not sender.job_option:
1738                self.removePrinterOption('job-sheets')
1739
1740            sender.control[0].setFocus(Qt.OtherFocusReason)
1741
1742        elif sender.typ == cups.UI_PAGE_RANGE: # (*) All () Pages: [    ]
1743            sender.control[0].setChecked(True) # all radio button
1744            sender.control[0].setFocus(Qt.OtherFocusReason)
1745            sender.control[2].setEnabled(False) # range edit box
1746
1747
1748    def PageRangeAllRadio_toggled(self, b):
1749        if b:
1750            sender = self.sender()
1751            sender.edit_control.setEnabled(False)
1752            sender.pushbutton.setEnabled(False)
1753            self.job_options['pagerange'] = ''
1754
1755
1756    def PageRangeRangeRadio_toggled(self, b):
1757        if b:
1758            sender = self.sender()
1759            sender.pushbutton.setEnabled(True)
1760            sender.edit_control.setEnabled(True)
1761            self.job_options['pagerange'] = to_unicode(sender.edit_control.text())
1762
1763
1764    def PageRangeEdit_editingFinished(self):
1765        sender = self.sender()
1766        t, ok, x = self.job_options['pagerange'], True, []
1767
1768
1769        try:
1770            x = utils.expand_range(t)
1771        except ValueError:
1772            ok = False
1773
1774        if ok:
1775            for y in x:
1776                if y <= 0  or y > 999:
1777                    ok = False
1778                    break
1779
1780        if not ok:
1781            self.job_options['pagerange'] = ''
1782            log.error("Invalid page range: %s" % t)
1783            FailureUI(self, self.__tr("<b>Invalid page range.</b><p>Please enter a range using page numbers (1-999), dashes, and commas. For example: 1-2,3,5-7</p>"))
1784            sender.setFocus(Qt.OtherFocusReason)
1785
1786
1787    def PageRangeEdit_textChanged(self, t):
1788        self.job_options['pagerange'] = to_unicode(t) # Do range validation only in PageRangeEdit_editingFinished method
1789
1790    #
1791    # Job Storage
1792    #
1793
1794    def updateJobStorageControls(self):
1795        beginWaitCursor()
1796        try:
1797            # Mode
1798            self.JobStorageModeComboBox.setCurrentIndex(self.JobStorageModeComboBox.findData(self.job_storage_mode))
1799            self.JobStorageModeDefaultButton.setEnabled(self.job_storage_mode != JOB_STORAGE_TYPE_OFF)
1800
1801            # PIN
1802            self.JobStoragePinPrivateRadioButton.setChecked(self.job_storage_use_pin)
1803
1804            # Username
1805            self.JobStorageUsernameAutoRadioButton.setChecked(self.job_storage_auto_username)
1806
1807            # Jobname/ID
1808            self.JobStorageIDAutoRadioButton.setChecked(self.job_storage_auto_jobname)
1809
1810            # Dup/existing ID
1811            self.JobStorageExistingComboBox.setCurrentIndex(self.JobStorageExistingComboBox.findData(self.job_storage_job_exist))
1812
1813            if self.job_storage_mode == JOB_STORAGE_TYPE_OFF:
1814                # PIN
1815                self.JobStoragePinGroupBox.setEnabled(False)
1816                self.JobStoragePinEdit.setEnabled(False)
1817                self.JobStoragePinDefaultButton.setEnabled(False)
1818                self.JobStoragePinEdit.setText(QString())
1819
1820                # Username
1821                self.JobStorageUsernameGroupBox.setEnabled(False)
1822                self.JobStorageUsernameEdit.setEnabled(False)
1823                self.JobStorageUsernameDefaultButton.setEnabled(False)
1824
1825                # Jobname/ID
1826                self.JobStorageIDGroupBox.setEnabled(False)
1827                self.JobStorageIDEdit.setEnabled(False)
1828                self.JobStorageIDDefaultButton.setEnabled(False)
1829
1830                # Duplicate/existing Jobname/ID
1831                self.JobStorageExistingComboBox.setEnabled(False)
1832
1833            else:
1834                # PIN
1835                if self.job_storage_mode in (JOB_STORAGE_TYPE_PERSONAL, JOB_STORAGE_TYPE_STORE):
1836                    self.JobStoragePinGroupBox.setEnabled(True)
1837                    self.JobStoragePinDefaultButton.setEnabled(self.job_storage_use_pin)
1838                    self.JobStoragePinEdit.setEnabled(self.job_storage_use_pin)
1839                    self.JobStoragePinEdit.setText(QString(self.job_storage_pin))
1840                else:
1841                    self.JobStoragePinGroupBox.setEnabled(False)
1842                    self.JobStoragePinEdit.setEnabled(False)
1843                    self.JobStoragePinDefaultButton.setEnabled(False)
1844                    self.JobStoragePinEdit.setText(QString())
1845
1846                # Username
1847                self.JobStorageUsernameGroupBox.setEnabled(True)
1848                self.JobStorageUsernameEdit.setEnabled(not self.job_storage_auto_username)
1849                self.JobStorageUsernameDefaultButton.setEnabled(not self.job_storage_auto_username)
1850                self.JobStorageUsernameEdit.setText(QString(self.job_storage_username))
1851
1852                # Jobname/ID
1853                self.JobStorageIDGroupBox.setEnabled(True)
1854                self.JobStorageIDEdit.setEnabled(not self.job_storage_auto_jobname)
1855                self.JobStorageIDDefaultButton.setEnabled(not self.job_storage_auto_jobname)
1856                self.JobStorageIDEdit.setText(QString(self.job_storage_jobname))
1857
1858                # Duplicate/existing JobName/ID
1859                self.JobStorageExistingComboBox.setEnabled(not self.job_storage_auto_jobname)
1860                self.JobStorageExistingDefaultButton.setEnabled(not self.job_storage_auto_jobname and self.job_storage_job_exist != JOB_STORAGE_EXISTING_JOB_REPLACE)
1861
1862        finally:
1863            endWaitCursor()
1864
1865
1866    def saveJobStorageOptions(self):
1867        beginWaitCursor()
1868        try:
1869            log.debug("Saving job storage options...")
1870
1871            if self.job_storage_mode == JOB_STORAGE_TYPE_OFF:
1872                log.debug("Job storage mode = JOB_STORAGE_TYPE_OFF")
1873                self.setPrinterOption('HOLD', 'OFF')
1874                self.removePrinterOption('HOLDTYPE')
1875                self.removePrinterOption('USERNAME')
1876                self.removePrinterOption('JOBNAME')
1877                self.removePrinterOption('DUPLICATEJOB')
1878
1879            elif self.job_storage_mode == JOB_STORAGE_TYPE_PROOF_AND_HOLD:
1880                log.debug("Job storage mode = JOB_STORAGE_TYPE_PROOF_AND_HOLD")
1881                self.setPrinterOption('HOLD', 'PROOF')
1882                #self.removePrinterOption('HOLDTYPE')
1883                self.setPrinterOption('HOLDTYPE', 'PUBLIC')
1884
1885            elif self.job_storage_mode == JOB_STORAGE_TYPE_PERSONAL:
1886                log.debug("Job storage mode = JOB_STORAGE_TYPE_PERSONAL")
1887
1888                if self.job_storage_use_pin:
1889                    self.setPrinterOption('HOLD', 'ON')
1890                else:
1891                    self.setPrinterOption('HOLD', 'PROOF')
1892                    self.setPrinterOption('HOLDTYPE', 'PUBLIC')
1893
1894
1895            elif self.job_storage_mode == JOB_STORAGE_TYPE_QUICK_COPY:
1896                log.debug("Job storage mode = JOB_STORAGE_TYPE_QUICK_COPY")
1897                self.setPrinterOption('HOLD', 'ON')
1898                self.setPrinterOption('HOLDTYPE', 'PUBLIC')
1899
1900            elif self.job_storage_mode == JOB_STORAGE_TYPE_STORE:
1901                log.debug("Job storage mode = JOB_STORAGE_TYPE_STORE")
1902                self.setPrinterOption('HOLD', 'STORE')
1903
1904                if not self.job_storage_use_pin:
1905                    self.removePrinterOption('HOLDTYPE')
1906
1907            # PIN
1908            log.debug("Job storage use pin = %d" % self.job_storage_use_pin)
1909            if self.job_storage_use_pin:
1910                self.setPrinterOption('HOLDTYPE', 'PRIVATE')
1911
1912            #else:
1913            #    self.removePrinterOption('HOLDKEY')
1914
1915            # Dup/exisiting
1916            if self.job_storage_job_exist == JOB_STORAGE_EXISTING_JOB_REPLACE:
1917                log.debug("Job storage duplicate = JOB_STORAGE_EXISTING_JOB_REPLACE")
1918                self.setPrinterOption('DUPLICATEJOB', 'REPLACE')
1919
1920            else: # JOB_STORAGE_EXISTING_JOB_APPEND_1_99
1921                log.debug("Job storage duplicate = JOB_STORAGE_EXISTING_JOB_APPEND_1_99")
1922                self.setPrinterOption('DUPLICATEJOB', 'APPEND')
1923
1924
1925        finally:
1926            endWaitCursor()
1927
1928
1929    #
1930    # Mode
1931    #
1932
1933    def JobStorageModeComboBox_activated(self, i):
1934        sender = self.sender()
1935        mode, ok = value_int(sender.itemData(i))
1936        if ok:
1937            self.job_storage_mode = mode
1938            self.saveJobStorageOptions()
1939            self.updateJobStorageControls()
1940
1941
1942    def JobStorageModeDefaultButton_clicked(self):
1943        self.JobStorageModeComboBox.emit(SIGNAL("activated(int)"), JOB_STORAGE_TYPE_OFF)
1944
1945
1946    #
1947    # PIN
1948    #
1949
1950    def JobStoragePinOffRadioButton_toggled(self, b):
1951        self.job_storage_use_pin = not b
1952        self.updateJobStorageControls()
1953        self.saveJobStorageOptions()
1954
1955
1956    def JobStoragePinPrivateRadioButton_toggled(self, b):
1957        self.job_storage_use_pin = b
1958        self.updateJobStorageControls()
1959        self.saveJobStorageOptions()
1960
1961
1962    def JobStoragePinDefaultButton_clicked(self):
1963        self.JobStoragePinOffRadioButton.emit(SIGNAL("toggled(bool)"), True)
1964
1965
1966    def JobStoragePinEdit_textEdited(self, s):
1967        self.job_storage_pin = to_unicode(s)
1968        self.setPrinterOption('HOLDKEY', self.job_storage_pin.encode('ascii'))
1969
1970
1971
1972    #
1973    # Username
1974    #
1975
1976    def JobStorageUsernameAutoRadioButton_toggled(self, b):
1977        self.job_storage_auto_username = b
1978        self.updateJobStorageControls()
1979        self.saveJobStorageOptions()
1980
1981
1982    def JobStorageUsernameCustomRadioButton_toggled(self, b):
1983        self.job_storage_auto_username = not b
1984        self.updateJobStorageControls()
1985        self.saveJobStorageOptions()
1986
1987
1988    def JobStorageUsernameDefaultButton_clicked(self):
1989        self.JobStorageUsernameAutoRadioButton.emit(SIGNAL("toggled(bool)"), True)
1990
1991
1992    def JobStorageUsernameEdit_textEdited(self, s):
1993        self.job_storage_username = to_unicode(s)
1994        self.setPrinterOption('USERNAME', self.job_storage_username.encode('ascii'))
1995
1996    #
1997    # Jobname/ID
1998    #
1999
2000    def JobStorageIDAutoRadioButton_toggled(self, b):
2001        self.job_storage_auto_jobname = b
2002        self.updateJobStorageControls()
2003        self.saveJobStorageOptions()
2004
2005
2006    def JobStorageIDCustomRadioButton_toggled(self, b):
2007        self.job_storage_auto_jobname = not b
2008        self.updateJobStorageControls()
2009        self.saveJobStorageOptions()
2010
2011
2012    def JobStorageIDDefaultButton_clicked(self):
2013        self.JobStorageIDAutoRadioButton.emit(SIGNAL("toggled(bool)"), True)
2014
2015
2016    def JobStorageIDEdit_textEdited(self, s):
2017        self.job_storage_jobname = to_unicode(s)
2018        self.setPrinterOption('JOBNAME', self.job_storage_jobname.encode('ascii'))
2019
2020    #
2021    # Duplicate/existing Jobname/ID
2022    #
2023
2024    def JobStorageExistingComboBox_activated(self, i):
2025        sender = self.sender()
2026        opt, ok = value_int(sender.itemData(i))
2027        if ok:
2028            self.job_storage_job_exist = opt
2029            self.updateJobStorageControls()
2030            self.saveJobStorageOptions()
2031
2032
2033    def JobStorageExistingDefaultButton_clicked(self):
2034        self.JobStorageExistingComboBox.emit(SIGNAL("activated(int)"), JOB_STORAGE_EXISTING_JOB_REPLACE)
2035
2036
2037    #
2038    # Printer I/O
2039    #
2040
2041    def setPrinterOption(self, option, value):
2042        log.debug("setPrinterOption(%s, %s)" % (option, value))
2043        cups.openPPD(self.cur_printer)
2044
2045        try:
2046            if option == "HPDigit":
2047               if len(value) == 1:
2048                  value = '000' + value
2049               if len(value) == 2:
2050                  value += '00' + value
2051               if len(value) == 3:
2052                  value += '0' + value
2053               if len(value) != 4:
2054                  value = value[-4:]
2055            cups.addOption("%s=%s" % (option, value))
2056            cups.setOptions()
2057        finally:
2058            cups.closePPD()
2059
2060    def removePrinterOption(self, option):
2061        log.debug("removePrinterOption(%s)" % option)
2062        cups.openPPD(self.cur_printer)
2063
2064        try:
2065            cups.removeOption(option)
2066            cups.setOptions()
2067        finally:
2068            cups.closePPD()
2069
2070
2071    def __tr(self,s,c = None):
2072        return qApp.translate("PrintSettingsToolbox",s,c)
2073
2074