Code sync
[external/hplip.git] / ui4 / printdialog.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 # Authors: Don Welch
20 #
21
22
23 # Local
24 from base.g import *
25 from base import device, utils
26 from prnt import cups
27 from base.codes import *
28 from ui_utils import *
29
30 # Qt
31 from PyQt4.QtCore import *
32 from PyQt4.QtGui import *
33
34 # Ui
35 from printdialog_base import Ui_Dialog
36 from filetable import FileTable, FILETABLE_TYPE_PRINT
37 from printernamecombobox import PRINTERNAMECOMBOBOX_TYPE_PRINTER_ONLY
38
39 PAGE_FILE = 0
40 PAGE_OPTIONS = 1
41 PAGE_MAX = 1
42
43
44 class PrintDialog(QDialog, Ui_Dialog):
45     def __init__(self, parent, printer_name, args=None):
46         QDialog.__init__(self, parent)
47         self.setupUi(self)
48
49         self.printer_name = printer_name
50
51         # User settings
52         self.user_settings = UserSettings()
53         self.user_settings.load()
54         self.user_settings.debug()
55
56         self.initUi()
57
58         self.file_list = []
59         if args is not None:
60             for a in args:
61                 self.Files.addFileFromUI(os.path.abspath(a))
62
63         self.devices = {}
64
65
66         QTimer.singleShot(0, self.updateFilePage)
67
68
69     def initUi(self):
70         self.OptionsToolBox.include_job_options = True
71
72         # connect signals/slots
73         self.connect(self.CancelButton, SIGNAL("clicked()"), self.CancelButton_clicked)
74         self.connect(self.BackButton, SIGNAL("clicked()"), self.BackButton_clicked)
75         self.connect(self.NextButton, SIGNAL("clicked()"), self.NextButton_clicked)
76
77         self.initFilePage()
78         self.initOptionsPage()
79
80         # Application icon
81         self.setWindowIcon(QIcon(load_pixmap('hp_logo', '128x128')))
82
83         if self.printer_name:
84             self.PrinterName.setInitialPrinter(self.printer_name)
85
86         self.StackedWidget.setCurrentIndex(0)
87
88
89     #
90     # File Page
91     #
92
93     def initFilePage(self):
94         self.Files.setType(FILETABLE_TYPE_PRINT)
95         #self.Files.setWorkingDir(user_conf.workingDirectory())
96         self.Files.setWorkingDir(self.user_settings.working_dir)
97         self.connect(self.Files, SIGNAL("isEmpty"), self.Files_isEmpty)
98         self.connect(self.Files, SIGNAL("isNotEmpty"), self.Files_isNotEmpty)
99
100
101     def updateFilePage(self):
102         self.NextButton.setText(self.__tr("Next >"))
103         self.NextButton.setEnabled(self.Files.isNotEmpty())
104         self.BackButton.setEnabled(False)
105         self.updateStepText(PAGE_FILE)
106         self.Files.updateUi()
107
108     def Files_isEmpty(self):
109         self.NextButton.setEnabled(False)
110
111
112     def Files_isNotEmpty(self):
113         self.NextButton.setEnabled(True)
114
115
116     #
117     # Options Page
118     #
119
120     def initOptionsPage(self):
121         self.BackButton.setEnabled(True)
122         self.PrinterName.setType(PRINTERNAMECOMBOBOX_TYPE_PRINTER_ONLY)
123
124         self.connect(self.PrinterName, SIGNAL("PrinterNameComboBox_currentChanged"),
125             self.PrinterNameComboBox_currentChanged)
126
127         self.connect(self.PrinterName, SIGNAL("PrinterNameComboBox_noPrinters"),
128             self.PrinterNameComboBox_noPrinters)
129
130
131     def updateOptionsPage(self):
132         QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
133         try:
134             self.PrinterName.updateUi()
135             self.BackButton.setEnabled(True)
136             num_files = len(self.Files.file_list)
137
138             if  num_files > 1:
139                 self.NextButton.setText(self.__tr("Print %1 Files").arg(num_files))
140             else:
141                 self.NextButton.setText(self.__tr("Print File"))
142
143             self.updateStepText(PAGE_OPTIONS)
144             # TODO: Enable print button only if printer is accepting and all options are OK (esp. page range)
145         finally:
146             QApplication.restoreOverrideCursor()
147
148
149     def PrinterNameComboBox_currentChanged(self, device_uri, printer_name):
150         try:
151             self.devices[device_uri]
152         except KeyError:
153             self.devices[device_uri] = device.Device(device_uri)
154
155         self.OptionsToolBox.updateUi(self.devices[device_uri], printer_name)
156
157
158     def PrinterNameComboBox_noPrinters(self):
159         FailureUI(self, self.__tr("<b>No printers found.</b><p>Please setup a printer and try again."))
160         self.close()
161
162
163     #
164     # Print
165     #
166
167     def executePrint(self):
168         for cmd in self.OptionsToolBox.getPrintCommands(self.Files.file_list):
169             log.debug(cmd)
170             status, output = utils.run(cmd, log_output=True, password_func=None, timeout=1)
171             if status != 0:
172                 FailureUI(self, self.__tr("<b>Print command failed with status code %1.</b><p>%2</p>").arg(status).arg(cmd))
173
174         self.close()
175         #print file('/home/dwelch/.cups/lpoptions', 'r').read()
176
177     #
178     # Misc
179     #
180
181     def CancelButton_clicked(self):
182         self.close()
183
184
185     def BackButton_clicked(self):
186         p = self.StackedWidget.currentIndex()
187         if p == PAGE_OPTIONS:
188             self.StackedWidget.setCurrentIndex(PAGE_FILE)
189             self.updateFilePage()
190
191         else:
192             log.error("Invalid page!") # shouldn't happen!
193
194
195     def NextButton_clicked(self):
196         p = self.StackedWidget.currentIndex()
197         if p == PAGE_FILE:
198             self.StackedWidget.setCurrentIndex(PAGE_OPTIONS)
199             self.updateOptionsPage()
200
201         elif p == PAGE_OPTIONS:
202             self.executePrint()
203
204
205     def updateStepText(self, p):
206         self.StepText.setText(self.__tr("Step %1 of %2").arg(p+1).arg(PAGE_MAX+1))
207
208
209     def __tr(self,s,c = None):
210         return qApp.translate("PrintDialog",s,c)
211
212
213
214 """
215    def printButton_clicked(self):
216         if self.invalid_page_range:
217             self.form.FailureUI(self.__tr("<b>Cannot print: Invalid page range: %1</b><p>A valid page range is a list of pages or ranges of pages separated by commas (e.g., 1-2,4,6-7)").arg(self.pageRangeEdit.text()))
218             return
219
220         try:
221             try:
222                 self.cur_device.open()
223             except Error:
224                 self.form.FailureUI(self.__tr("<b>Cannot print: Device is busy or not available.</b><p>Please check device and try again."))
225                 return
226
227             if 1: # Go ahead and allow - print will be queued in CUPS if not rejecting
228                 printers = cups.getPrinters()
229                 for p in printers:
230                     if p.name == self.cur_printer:
231                         break
232
233                 if p.state == cups.IPP_PRINTER_STATE_STOPPED:
234                     self.form.FailureUI(self.__tr("<b>Cannot print: Printer is stopped.</b><p>Please START the printer to continue this print. Job will begin printing once printer is started."))
235
236                 if not p.accepting:
237                     self.form.FailureUI(self.__tr("<b>Cannot print: Printer is not accepting jobs.</b><p>Please set the printer to ACCEPTING JOBS to continue printing."))
238                     return
239
240                 copies = int(self.copiesSpinBox.value())
241                 all_pages = self.pages_button_group == 0
242                 page_range = unicode(self.pageRangeEdit.text())
243                 page_set = int(self.pageSetComboBox.currentItem())
244
245                 cups.resetOptions()
246                 cups.openPPD(self.cur_printer)
247                 current_options = dict(cups.getOptions())
248                 cups.closePPD()
249
250                 nup = int(current_options.get("number-up", 1))
251
252                 for p, t, d in self.file_list:
253
254                     alt_nup = (nup > 1 and t == 'application/postscript' and utils.which('psnup'))
255
256                     if utils.which('lpr'):
257                         if alt_nup:
258                             cmd = ' '.join(['psnup', '-%d' % nup, ''.join(['"', p, '"']), '| lpr -P', self.cur_printer])
259                         else:
260                             cmd = ' '.join(['lpr -P', self.cur_printer])
261
262                         if copies > 1:
263                             cmd = ' '.join([cmd, '-#%d' % copies])
264
265                     else:
266                         if alt_nup:
267                             cmd = ' '.join(['psnup', '-%d' % nup, ''.join(['"', p, '"']), '| lp -c -d', self.cur_printer])
268                         else:
269                             cmd = ' '.join(['lp -c -d', self.cur_printer])
270
271                         if copies > 1:
272                             cmd = ' '.join([cmd, '-n%d' % copies])
273
274
275                     if not all_pages and len(page_range) > 0:
276                         cmd = ' '.join([cmd, '-o page-ranges=%s' % page_range])
277
278                     if page_set > 0:
279                         if page_set == 1:
280                             cmd = ' '.join([cmd, '-o page-set=even'])
281                         else:
282                             cmd = ' '.join([cmd, '-o page-set=odd'])
283
284
285                     # Job Storage
286                     # self.job_storage_mode = (0=Off, 1=P&H, 2=PJ, 3=QC, 4=SJ)
287                     # self.job_storage_pin = u"" (dddd)
288                     # self.job_storage_use_pin = True|False
289                     # self.job_storage_username = u""
290                     # self.job_storage_auto_username = True|False
291                     # self.job_storage_jobname = u""
292                     # self.job_storage_auto_jobname = True|False
293                     # self.job_storage_job_exist = (0=replace, 1=job name+(1-99))
294
295                     if self.job_storage_avail:
296                         if self.job_storage_mode: # On
297
298                             if self.job_storage_mode == 1: # Proof and Hold
299                                 cmd = ' '.join([cmd, '-o HOLD=PROOF'])
300
301                             elif self.job_storage_mode == 2: # Private Job
302                                 if self.job_storage_use_pin:
303                                     cmd = ' '.join([cmd, '-o HOLD=ON'])
304                                     cmd = ' '.join([cmd, '-o HOLDTYPE=PRIVATE'])
305                                     cmd = ' '.join([cmd, '-o HOLDKEY=%s' % self.job_storage_pin.encode('ascii')])
306                                 else:
307                                     cmd = ' '.join([cmd, '-o HOLD=PROOF'])
308                                     cmd = ' '.join([cmd, '-o HOLDTYPE=PRIVATE'])
309
310                             elif self.job_storage_mode == 3: # Quick Copy
311                                 cmd = ' '.join([cmd, '-o HOLD=ON'])
312                                 cmd = ' '.join([cmd, '-o HOLDTYPE=PUBLIC'])
313
314                             elif self.job_storage_mode == 4: # Store Job
315                                 if self.job_storage_use_pin:
316                                     cmd = ' '.join([cmd, '-o HOLD=STORE'])
317                                     cmd = ' '.join([cmd, '-o HOLDTYPE=PRIVATE'])
318                                     cmd = ' '.join([cmd, '-o HOLDKEY=%s' % self.job_storage_pin.encode('ascii')])
319                                 else:
320                                     cmd = ' '.join([cmd, '-o HOLD=STORE'])
321
322                             cmd = ' '.join([cmd, '-o USERNAME=%s' % self.job_storage_username.encode('ascii')\
323                                 .replace(" ", "_")])
324
325                             cmd = ' '.join([cmd, '-o JOBNAME=%s' % self.job_storage_jobname.encode('ascii')\
326                                 .replace(" ", "_")])
327
328                             if self.job_storage_job_exist == 1:
329                                 cmd = ' '.join([cmd, '-o DUPLICATEJOB=APPEND'])
330                             else:
331                                 cmd = ' '.join([cmd, '-o DUPLICATEJOB=REPLACE'])
332
333                         else: # Off
334                             cmd = ' '.join([cmd, '-o HOLD=OFF'])
335
336
337                     if not alt_nup:
338                         cmd = ''.join([cmd, ' "', p, '"'])
339
340                     log.debug("Printing: %s" % cmd)
341
342                     code = os.system(cmd)
343                     if code != 0:
344                         log.error("Print command failed.")
345                         self.form.FailureUI(self.__tr("Print command failed with error code %1").arg(code))
346
347                 self.form.close()
348
349         finally:
350             self.cur_device.close()
351
352 """