#!/usr/bin/python3 # -*- coding: utf-8 -*- """ XXX Author: Radek HuĊĦek """ from PyQt5.QtWidgets import * from PyQt5.QtCore import * import sys import subprocess as sp import ast def exec_pipeline(pipeline, inp, out = None, err_callback = None): def make_proc(cmd): p = QProcess() p.setProgram(cmd[0]) p.setArguments(cmd[1:]) return p def readChunk(cb, proc, channel): def x(): proc.setReadChannel(channel) cb(str(proc.readAll(), encoding='utf-8')) return x procs = [ make_proc(cmd) for cmd in pipeline ] for a, b in zip(procs, procs[1:]): a.setStandardOutputProcess(b) procs[0].setStandardInputFile(inp) if out is None: if err_callback is not None: procs[-1].readyReadStandardOutput.connect( readChunk(err_callback, procs[-1], QProcess.StandardOutput)) else: procs[-1].setStandardOutputFile(out) if err_callback is not None: for p in procs: p.readyReadStandardError.connect( readChunk(err_callback, p, QProcess.StandardError)) err_callback("< '%s' \\\n" % inp) err_callback(" |\n".join(("'%s'" % "' '".join(cmd)) for cmd in pipeline)) err_callback("\n") for p in procs: p.start(QProcess.Unbuffered | QProcess.ReadWrite) for p in procs: while not p.waitForFinished(30): QApplication.instance().processEvents() SAVE_AS_FILE = object() PRINTERS = ast.literal_eval("[\n%s\n]" % "".join(sys.stdin)) PRINTERS.append(("Save as ...", SAVE_AS_FILE)) for l in sp.check_output(["lpstat", "-a"]).decode("UTF-8").split("\n"): p = l.split(" ")[0] if p == "": continue PRINTERS.append((p, ["lp", "-d", p])) class CPP(QWidget): def __init__(self, pdf, user): super().__init__() self._pdf = pdf vbox = QVBoxLayout() vbox.addStretch(1) o = QLabel("Printing %s" % (pdf,), self) o.setMinimumWidth(400) o.setMaximumWidth(800) o.setWordWrap(True) vbox.addWidget(o) hbox = QHBoxLayout() hbox.addWidget(QLabel("Duplex:")) self._duplex = QComboBox(self) self._duplex.addItem("None", 'duplex=one-sided') self._duplex.addItem("Long Edge", "duplex=two-sided-long-edge") self._duplex.addItem("Short Side", "duplex=two-sided-long-edge") self._duplex.setCurrentIndex(1) self._pdfbook = QCheckBox('Use pdfbook', self) self._staple = QCheckBox('Staple', self) self._staple.setEnabled(False) def _pdfbook_changed(enabled): self._staple.setEnabled(enabled) self._duplex.setEnabled(not enabled) if enabled: self._duplex.setCurrentIndex(1) else: self._staple.setChecked(False) self._pdfbook.clicked[bool].connect(_pdfbook_changed) hbox.addWidget(self._duplex) vbox.addLayout(hbox) vbox.addWidget(self._pdfbook) vbox.addWidget(self._staple) o = QComboBox(self) for (p, cmd) in PRINTERS: o.addItem(p, cmd) vbox.addWidget(o) self._printer = o hbox = QHBoxLayout() b_p = QPushButton("Print", self) b_p.clicked.connect(self.print) hbox.addWidget(b_p) self._button_print = b_p b_c = QPushButton("Cancel", self) b_c.clicked.connect(self.close) hbox.addWidget(b_c) self._button_cancel = b_c vbox.addLayout(hbox) self._logger = QTextEdit() self._logger.setReadOnly(True) vbox.addWidget(self._logger) self.setLayout(vbox) self.setWindowTitle('CUPS pdf printer postprocessor') self.show() def print(self): lp = QProcess() self._button_print.setEnabled(False) log = [] pipeline = [] def logMsg(msg): log.append(msg) self._logger.setPlainText("".join(log)) if self._pdfbook.isChecked(): pipeline.append([ "pdfbook", "/dev/stdin", "-o", "/dev/stdout" ]) if self._printer.currentData() is SAVE_AS_FILE: f = QFileDialog.getSaveFileName(self, 'Save as ...') if not f[0]: self.close() pipeline.append([ "dd", "of=%s" % (f[0],) ]) else: cmd = self._printer.currentData().copy() cmd += [ "-o", self._duplex.currentData() ] if self._staple.isChecked(): cmd += [ "-o", "XRFold=BiFoldStaple" ] cmd.append("-") pipeline.append(cmd) exec_pipeline(pipeline, self._pdf, err_callback=logMsg) self._button_cancel.setText("Close") if __name__ == '__main__': app = QApplication(sys.argv[2:]) ex = CPP(sys.argv[1], sys.argv[2]) sys.exit(app.exec_())