Back to index

texmacs  1.0.7.15
QTMPrinterSettings.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003  * MODULE     : QTMPrinterSettings.cpp
00004  * DESCRIPTION:
00005  * COPYRIGHT  : (C) 2010 Miguel de Benito Delgado
00006  *******************************************************************************
00007  * This software falls under the GNU general public license version 3 or later.
00008  * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009  * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010  ******************************************************************************/
00011 
00012 #include "QTMPrinterSettings.hpp"
00013 #include "tm_ostream.hpp"
00014 #include "qt_utilities.hpp"
00015 
00016 #include <QPrinter>
00017 #include <QPrinterInfo>
00018 #include <QProcess>
00019 #include <QRegExp>
00020 
00024 QTMPrinterSettings::QTMPrinterSettings()
00025 : collateCopies(true), blackWhite(true), printerName(""), fileName(""), 
00026   paperSize("A4"), dpi(600), firstPage(0), lastPage(0), printOddPages(true), 
00027   printEvenPages(true), fitToPage(true), copyCount(1), duplex(false),
00028   pagesPerSide(1), pagesOrder(LR_TB), orientation(Portrait)
00029 {
00030   configProgram = new QProcess(this);
00031 
00032   // See the class documentation for an explanation of the connected signal
00033   QObject::connect(configProgram, SIGNAL(finished(int, QProcess::ExitStatus)),
00034                    this, SLOT(systemCommandFinished(int, QProcess::ExitStatus)));
00035 }
00036 
00041 void
00042 QTMPrinterSettings::getFromQPrinter(const QPrinter& from) {
00043   printerName   = from.printerName ();
00044   fileName      = from.outputFileName ();
00045   orientation   = (from.orientation() == QPrinter::Landscape) 
00046                   ? Landscape : Portrait;
00047   paperSize     = qtPaperSizeToQString(from.paperSize());
00048   dpi           = from.resolution ();
00049   firstPage     = from.fromPage ();
00050   lastPage      = from.toPage ();
00051 #if (QT_VERSION >= 0x040700)
00052   copyCount     = from.copyCount ();
00053 #endif
00054   collateCopies = from.collateCopies();
00055   blackWhite    = (from.colorMode () == QPrinter::Color);
00056   printProgram  = from.printProgram();
00057 }
00058 
00063 void
00064 QTMPrinterSettings::setToQPrinter(QPrinter& to) const {
00065   to.setResolution(dpi);
00066   to.setFromTo(firstPage, lastPage);  
00067   to.setOrientation((orientation == Landscape) ?
00068                     QPrinter::Landscape : QPrinter::Portrait);
00069   to.setOutputFileName(fileName);
00070   to.setPaperSize(qStringToQtPaperSize(paperSize));
00071 #if (QT_VERSION >= 0x040700)
00072   to.setCopyCount(copyCount);
00073 #endif  
00074   to.setCollateCopies(collateCopies);
00075   to.setColorMode(blackWhite ? QPrinter::Color : QPrinter::GrayScale);
00076 }
00077 
00082 QString
00083 QTMPrinterSettings::qtPaperSizeToQString(const QPrinter::PaperSize _size) {
00084   
00085 #define PAPER(fmt)  case QPrinter::fmt : return "fmt"
00086   switch (_size) {
00087       PAPER (A0) ; PAPER (A1) ; PAPER (A2) ; PAPER (A3) ; PAPER (A4) ;
00088       PAPER (A5) ; PAPER (A6) ; PAPER (A7) ; PAPER (A8) ; PAPER (A9) ;
00089       PAPER (B0) ; PAPER (B1) ; PAPER (B2) ; PAPER (B3) ; PAPER (B4) ;
00090       PAPER (B5) ; PAPER (B6) ; PAPER (B7) ; PAPER (B8) ; PAPER (B9) ;
00091       PAPER (B10) ;  PAPER (Letter) ;
00092     default: return "A4";
00093   }
00094 #undef PAPER
00095 }
00096 
00100 QPrinter::PaperSize
00101 QTMPrinterSettings::qStringToQtPaperSize(const QString& _size) {
00102   
00103 #define PAPER(fmt)  if(_size == "fmt") return QPrinter::fmt
00104   PAPER (A0) ; PAPER (A1) ; PAPER (A2) ; PAPER (A3) ; PAPER (A4) ;
00105   PAPER (A5) ; PAPER (A6) ; PAPER (A7) ; PAPER (A8) ; PAPER (A9) ;
00106   PAPER (B0) ; PAPER (B1) ; PAPER (B2) ; PAPER (B3) ; PAPER (B4) ;
00107   PAPER (B5) ; PAPER (B6) ; PAPER (B7) ; PAPER (B8) ; PAPER (B9) ;
00108   PAPER (B10) ;  PAPER (Letter) ;
00109   return QPrinter::A4;  // Default
00110 #undef PAPER
00111 }
00112 
00113 
00122 QStringList
00123 QTMPrinterSettings::getChoices(DriverChoices _which, int& _default) {
00124   QStringList _ret;
00125   switch (_which) {
00126     case PageSize:
00127       _ret = printerOptions["PageSize"].split(" ", QString::SkipEmptyParts);
00128       break;
00129     case Resolution:
00130       _ret = printerOptions["Resolution"].split(" ", QString::SkipEmptyParts);
00131       break;
00132     case Duplex:
00133       _ret = printerOptions["Duplex"].split(" ", QString::SkipEmptyParts);
00134       break;
00135     case ColorModel:
00136       _ret = printerOptions["ColorModel"].split(" ", QString::SkipEmptyParts);
00137       break;
00138     case Collate:
00139       _ret = printerOptions["Collate"].split(" ", QString::SkipEmptyParts);
00140       break;
00141   }
00142   
00143   // FIXME: this is CUPS specific (marking the default option with an asterisk)
00144   for (int i=0; i<_ret.size(); ++i)
00145     if (_ret[i].trimmed().startsWith("*")) {
00146       _ret[i] = _ret[i].trimmed().remove(0,1);
00147       _default = i;
00148     }
00149   return _ret;
00150 }
00151 
00152 
00153 #if defined(Q_WS_MAC) || defined(Q_WS_X11)
00154 
00158 CupsQTMPrinterSettings::CupsQTMPrinterSettings() : QTMPrinterSettings() {
00159   printProgram = "lp ";
00160 }
00161 
00165 bool
00166 CupsQTMPrinterSettings::fromSystemConfig(const QString& printer) {
00167   if (configProgram->state() != QProcess::NotRunning)
00168     return false;
00169   
00170   // Watch out! the order of the options is relevant!
00171   configProgram->start(QString("lpoptions -p \"%1\" -l").arg(printer));
00172   //, 
00173   //                   QStringList() << QString("-p \"%1\"").arg(printer)
00174   //                                 << "-l");
00175   
00176   
00177   printerName = printer;
00178   return true;
00179 }
00180 
00197 void
00198 CupsQTMPrinterSettings::systemCommandFinished(int exitCode, 
00199                                               QProcess::ExitStatus exitStatus) {
00200   (void) exitCode;
00201   
00202   printerOptions.clear();
00203 
00204   if (exitStatus != QProcess::NormalExit) {
00205     emit doneReading();
00206     return;
00207   }
00208     
00209   QRegExp rx("^(\\w+)/(.+):(.*)$"); // Param/Param desc: val1 val2 *default val4
00210   rx.setMinimal(true);              // Non-greedy matching
00211   
00212   QList<QByteArray> _lines = configProgram->readAllStandardOutput().split('\n');
00213   foreach (QString _line, _lines) {
00214     if(rx.indexIn(_line) == -1)      // No matches?
00215       continue;
00216     // Store for further parsing later, see QTMPrinterSettings::getChoices()
00217     printerOptions[rx.cap(1)] = rx.cap(3);   
00218   }
00219   emit doneReading();
00220 }
00221 
00222 
00229 QString
00230 CupsQTMPrinterSettings::toSystemCommand() const {
00231   QString _cmd;
00232   
00233   if (! printProgram.isEmpty())
00234     _cmd += printProgram;
00235   
00236   if (! printerName.isEmpty())
00237     _cmd += QString(" -d \"%1\"").arg(printerName);
00238   
00239   _cmd += QString(" -o orientation-requested=%1").arg(orientation);
00240   
00241   if (duplex && (orientation==Landscape || orientation == ReverseLandscape))
00242     _cmd += " -o sides=two-sided-short-edge";
00243   else if (duplex && (orientation==Portrait || orientation == ReversePortrait))
00244     _cmd += " -o sides=two-sided-long-edge";
00245  
00246   if (fitToPage)
00247     _cmd += " -o fitplot";
00248 
00249   if (pagesPerSide > 1) {
00250     _cmd += QString(" -o number-up=%1").arg(pagesPerSide);
00251 
00252     // -o number-up-layout=string
00253     // specifies the n-up image order in any of eight permutations from btlr 
00254     // (bottom, top, left, right) to tbrl.
00255     _cmd += " -o number-up-layout=";
00256     switch (pagesOrder) {
00257       case LR_TB: _cmd += "lrtb"; break; case RL_TB: _cmd += "rltb"; break;
00258       case TB_LR: _cmd += "tblr"; break; case TB_RL: _cmd += "tbrl"; break;
00259       case LR_BT: _cmd += "lrbt"; break; case RL_BT: _cmd += "rlbt"; break;
00260       case BT_LR: _cmd += "btlr"; break; case BT_RL: _cmd += "btrl"; break;
00261       default: _cmd += "lrtb"; break;
00262     }
00263   }
00264   
00265   // Specifies which pages to print in the document. The list can contain a list
00266   // of numbers and ranges (#-#) separated by commas (e.g. 1,3-5,16).
00267   // The page numbers refer to the output pages and not the document's original
00268   // pages - options like "number-up" can affect the numbering of the pages.
00269   if (firstPage != 0 || lastPage != 0) {
00270     int f = (int)floor(firstPage / pagesPerSide);    f = (f==0) ? 1 : f;
00271     int l = (int)ceil (lastPage / pagesPerSide);     l = (l==0) ? 1 : l;
00272     if (firstPage > lastPage )
00273       _cmd += " -o outputorder=reverse";
00274     
00275     _cmd += QString(" -o page-ranges=%1-%2").arg(f).arg(l);
00276   }
00277     
00278   if (copyCount > 1) {
00279     _cmd += QString(" -o Collate=") + (collateCopies ? "True" : "False");
00280     _cmd += QString(" -n %1").arg(copyCount);
00281   }
00282   
00283   if (! printOddPages)
00284     _cmd += " -o page-set=even";
00285   else if(! printEvenPages)
00286     _cmd += " -o page-set=odd";
00287 
00288   _cmd += " -- ";  // Marks the end of options; use this to print a file whose 
00289                    // name begins with a dash (-).
00290   _cmd += '"' + fileName + '"';
00291   
00292   return _cmd;
00293 }
00294 
00295 
00302 QList<QPair<QString,QString> >
00303 CupsQTMPrinterSettings::availablePrinters() {
00304   QList<QPair<QString,QString> > _ret;
00305   QProcess stat(this);
00306   stat.start("lpstat -a");
00307   if(! stat.waitForFinished(2000)) // 2 sec.
00308     return _ret;
00309   QRegExp rx("^(\\w+) +.*$");
00310   rx.setMinimal(true);
00311   QList<QByteArray> _lines = stat.readAllStandardOutput().split('\n');
00312   foreach (QString _line, _lines) {
00313     if(rx.indexIn(_line) == -1)      // No matches?
00314       continue;
00315     
00316     _ret << QPair<QString,QString>(rx.cap(1),rx.cap(1));
00317   }
00318   return _ret;
00319 }
00320 
00321 #endif
00322 
00323 #ifdef Q_WS_WIN 
00324 
00329 WinQTMPrinterSettings::WinQTMPrinterSettings() : QTMPrinterSettings() {
00330   // -sDEVICE=mswinpr2
00331   // Selects the MS Windows printer device.
00332   //  
00333   // -dNoCancel
00334   // Hides the progress dialog, which shows the percent of the document page 
00335   // already processed and also provides a cancel button.
00336   //printProgram = "gs -sDEVICE=mswinpr2";
00337   printProgram = "gsprint";
00338 }
00339 
00344 bool 
00345 WinQTMPrinterSettings::fromSystemConfig(const QString& printer) {
00346   if (configProgram->state() != QProcess::NotRunning)
00347     return false;
00348   /* This (untested) alternative uses (wrong) postscript to read printer options
00349   configProgram->start(QString("gs"), QStringList() 
00350                        << "-sDEVICE=mswinpr2"
00351                        << QString("-sOutputFile=\"\\\\spool\\%1\"").arg(printer)
00352                        << "-c \"currentpagedevice /Duplex get ==\"");
00353    */
00354   
00355   // See the docs for QProcess::start() for the reason behind the triple \"
00356   configProgram->start(QString("winprinfo --printer=\"\"\"%1\"\"\"").arg(printer));
00357   printerName = printer;
00358   return true;
00359 }
00360 
00368 QString
00369 WinQTMPrinterSettings::toSystemCommand() const {
00370   QString _cmd;
00371   
00372   if (! printProgram.isEmpty())
00373     _cmd += printProgram;
00374   
00375   /* 
00376   // This (untested) code is for use with the mswinpr2 driver:
00377   _cmd += QString(" -sOutputFile=\"\\\\spool\\%1\" ").arg(printerName);
00378   _cmd += QString(" -c << /Duplex %1 /Tumble %2 >> setpagedevice").
00379               arg(duplex ? "true" : "false").
00380               arg((orientation == Landscape || orientation == ReverseLandscape) 
00381                   ? "true" : "false");
00382   
00383   // -f Interprets following non-switch arguments as file names to be executed
00384   // using the normal run command. Since this is the default behavior, 
00385   // -f is useful only for terminating the list of tokens for the -c switch.
00386   _cmd += QString(" -f \"%1\"").arg(fileName);
00387   */
00388   
00389   _cmd += " -noquery";  // Don't show printer setup dialog.
00390 
00391   if (! printerName.isEmpty())
00392     _cmd += QString(" -printer \"%1\"").arg(printerName);
00393   
00394   if (duplex)
00395     _cmd += QString(" -duplex_%1").
00396                 arg((orientation == Portrait || orientation == ReversePortrait)
00397                     ? "vertical" : "horizontal");
00398   else
00399     _cmd += (orientation == Portrait || orientation == ReversePortrait)
00400              ? " -portrait" : " -landscape";    
00401   
00402   if (pagesPerSide > 1)
00403     _cmd += QString(" -copies %1").arg(pagesPerSide);
00404     
00405   // Specifies which pages to print in the document. The list can contain a list
00406   // of numbers and ranges (#-#) separated by commas (e.g. 1,3-5,16).
00407   // The page numbers refer to the output pages and not the document's original
00408   // pages - options like "number-up" can affect the numbering of the pages.
00409   if (firstPage != 0 || lastPage != 0) {
00410     int f = (int)floor(firstPage / pagesPerSide);    f = (f==0) ? 1 : f;
00411     int l = (int)ceil (lastPage / pagesPerSide);     l = (l==0) ? 1 : l;
00412     // FIXME: what happens if f > l?
00413     _cmd += QString(" -from %1 -to %2").arg(f).arg(l);
00414   }
00415   
00416   if (copyCount > 1)
00417      _cmd += QString(" -copies %1").arg(pagesPerSide);
00418   
00419   if (! printOddPages)
00420     _cmd += " -even";
00421   else if(! printEvenPages)
00422     _cmd += " -odd";
00423   
00424   _cmd += '"' + fileName + '"';
00425   
00426   return _cmd;
00427 }
00428 
00432 void
00433 WinQTMPrinterSettings::systemCommandFinished(int exitCode, 
00434                                            QProcess::ExitStatus exitStatus) {
00435   (void) exitCode;
00436   
00437   printerOptions.clear();
00438   
00439   if (exitStatus != QProcess::NormalExit) {
00440     emit doneReading();
00441     return;
00442   }
00443   
00444   int resolutionsCounter = 0;
00445   bool readingSizes = false;
00446   QList<QByteArray> _lines = configProgram->readAllStandardOutput().split('\n');
00447   foreach (QString _line, _lines) {
00448     // Parse special lines after the DC_ENUMRESOLUTIONS : (see below)
00449     if (resolutionsCounter > 0) {
00450       --resolutionsCounter;
00451       QRegExp rx2("^.*x=(\\d)+.*y=(\\d)+.*$");
00452       rx2.setMinimal(true);
00453       if (rx2.indexIn(_line) > -1)
00454         printerOptions["Resolution"] += QString("%1x%2dpi ").
00455                                                 arg(rx2.cap(1)).arg(rx2.cap(2));
00456       continue;
00457     }
00458 
00459     if (_line.contains("PAPER SIZES FROM THE DEVMODE")) {
00460       readingSizes = true;
00461       //printerOptions["PaperSize"] = QString();
00462       continue;
00463     }
00464                                                     
00465     // Parse special lines after PAPER SIZES FROM THE DEVMODE :   
00466     if (readingSizes) {
00467       QRegExp rx2("^.*mm *(\\w)+.*$");  // [ 0]   215.90  279.40 mm  Letter
00468       rx2.setMinimal(true);
00469       if (rx2.indexIn(_line) > -1)
00470         printerOptions["PaperSize"] += rx2.cap(1);
00471       continue;
00472     }
00473 
00474     QRegExp rx("^ *DC_(\\w+) *(\\w+) *$"); // DC_SOMETHING    <num>
00475     rx.setMinimal(true);                   // Non-greedy matching
00476     if(rx.indexIn(_line) == -1)      // No matches?
00477       continue;
00478     QStringList capt = rx.capturedTexts();
00479     if (capt.size() != 3)              // We are only interested in some options.
00480       continue;
00481     
00482     if (capt[1] == "DUPLEX" && capt[2].toInt() > 0)
00483       printerOptions["Duplex"] = "Yes No"; 
00484     if (capt[1] == "COLORDEVICE" && capt[2].toInt() > 0)
00485       printerOptions["ColorModel"] = "Monochrome Gray Color";
00486     if (capt[1] == "COLLATE")
00487       if (capt[2].toInt() > 0)
00488         printerOptions["Collate"] = "No *Yes";
00489       else
00490         printerOptions["Collate"] = "*No Yes";
00491     
00492     if (capt[1] == "ENUMRESOLUTIONS") {
00493       resolutionsCounter = capt[2].toInt();   // The next iterations are special
00494       //printerOptions["Resolution"] = QString();
00495     }
00496   }
00497   
00498   emit doneReading();
00499 }
00500 
00505 QList<QPair<QString,QString> >
00506 WinQTMPrinterSettings::availablePrinters() {
00507   QList<QPair<QString,QString> > _ret;
00508   foreach(QPrinterInfo printer, QPrinterInfo::availablePrinters())
00509     _ret << QPair<QString,QString>(printer.printerName(), printer.printerName());
00510   return _ret;
00511 }
00512 
00513 #endif
00514