1 /***************************************************************************
2 * Copyright (C) 2007 by John Layt <john@layt.net> *
4 * FilePrinterPreview based on KPrintPreview (originally LGPL) *
5 * Copyright (c) 2007 Alex Merry <huntedhacker@tiscali.co.uk> *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 ***************************************************************************/
13 #include "fileprinter.h"
15 #include <QtGui/QPrinter>
16 #include <QPrintEngine>
17 #include <QStringList>
20 #include <QtCore/QFile>
21 #include <QtGui/QLabel>
22 #include <QtGui/QShowEvent>
26 #include <klocalsocket.h>
27 #include <kstandarddirs.h>
33 using namespace Okular
;
35 int FilePrinter::printFile( QPrinter
&printer
, const QString file
, FileDeletePolicy fileDeletePolicy
,
36 PageSelectPolicy pageSelectPolicy
, const QString
&pageRange
)
39 return fp
.doPrintFiles( printer
, QStringList( file
), fileDeletePolicy
, pageSelectPolicy
, pageRange
);
42 int FilePrinter::printFiles( QPrinter
&printer
, const QStringList
&fileList
, FileDeletePolicy fileDeletePolicy
)
45 return fp
.doPrintFiles( printer
, fileList
, fileDeletePolicy
, FilePrinter::ApplicationSelectsPages
, QString() );
48 int FilePrinter::doPrintFiles( QPrinter
&printer
, QStringList fileList
, FileDeletePolicy fileDeletePolicy
,
49 PageSelectPolicy pageSelectPolicy
, const QString
&pageRange
)
51 //Decide what executable to use to print with, need the CUPS version of lpr if available
52 //Some distros name the CUPS version of lpr as lpr-cups or lpr.cups so try those first
53 //before default to lpr, or failing that to lp
56 if ( !KStandardDirs::findExe("lpr-cups").isEmpty() ) {
58 } else if ( !KStandardDirs::findExe("lpr.cups").isEmpty() ) {
60 } else if ( !KStandardDirs::findExe("lpr").isEmpty() ) {
62 } else if ( !KStandardDirs::findExe("lp").isEmpty() ) {
68 if ( fileList
.size() < 1 ) {
72 for (QStringList::ConstIterator it
= fileList
.begin(); it
!= fileList
.end(); ++it
) {
73 if (!QFile::exists(*it
)) {
78 if ( printer
.printerState() == QPrinter::Aborted
|| printer
.printerState() == QPrinter::Error
) {
82 // Print to File if a filename set, assumes there must be only 1 file
83 if ( !printer
.outputFileName().isEmpty() ) {
85 if ( QFile::exists( printer
.outputFileName() ) ) {
86 QFile::remove( printer
.outputFileName() );
89 int res
= QFile::copy( fileList
[0], printer
.outputFileName() );
91 if ( fileDeletePolicy
== FilePrinter::SystemDeletesFiles
) {
92 QFile::remove( fileList
[0] );
99 bool useCupsOptions
= cupsAvailable();
100 QStringList argList
= printArguments( printer
, fileDeletePolicy
, pageSelectPolicy
, useCupsOptions
, pageRange
, exe
)
102 kDebug(OkularDebug
) << "Executing" << exe
<< "with arguments" << argList
;
104 int ret
= KProcess::execute( exe
, argList
);
106 // If we used the Cups options and the command failed, try again without them in case Cups lpr/lp not installed.
107 // I'm not convinced this will work, I don't think KProcess returns the result of the command, but rather
108 // that it was able to be executed?
109 if ( useCupsOptions
&& ret
< 0 ) {
111 argList
= printArguments( printer
, fileDeletePolicy
, pageSelectPolicy
, useCupsOptions
, pageRange
, exe
)
113 kDebug(OkularDebug
) << "Retrying" << exe
<< "without CUPS arguments" << argList
;
115 ret
= KProcess::execute( exe
, argList
);
121 QList
<int> FilePrinter::pageList( QPrinter
&printer
, int lastPage
, const QList
<int> &selectedPageList
)
123 if ( printer
.printRange() == QPrinter::Selection
) {
124 return selectedPageList
;
127 int startPage
, endPage
;
130 if ( printer
.printRange() == QPrinter::PageRange
) {
131 startPage
= printer
.fromPage();
132 endPage
= printer
.toPage();
138 for (int i
= startPage
; i
<= endPage
; i
++ ) {
144 QString
FilePrinter::pageRange( QPrinter
&printer
, int lastPage
, const QList
<int> &selectedPageList
)
146 if ( printer
.printRange() == QPrinter::Selection
) {
147 return pageListToPageRange( selectedPageList
);
150 if ( printer
.printRange() == QPrinter::PageRange
) {
151 return QString("%1-%2").arg(printer
.fromPage()).arg(printer
.toPage());
154 return QString("1-%2").arg( lastPage
);
157 QString
FilePrinter::pageListToPageRange( const QList
<int> &pageList
)
160 int count
= pageList
.count();
165 while ( i
!= count
) {
167 if ( i
+ 1 == count
|| pageList
[i
] + 1 != pageList
[i
+1] ) {
171 if ( !pageRange
.isEmpty() ) {
172 pageRange
.append(",");
175 if ( seqStart
== seqEnd
) {
176 pageRange
.append(pageList
[i
]);
178 pageRange
.append("%1-%2").arg(seqStart
).arg(seqEnd
);
190 bool FilePrinter::cupsAvailable()
193 return ( fp
.detectCupsConfig() /*&& fp.detectCupsService()*/ );
196 bool FilePrinter::detectCupsService()
198 // copied from KdeprintChecker::checkService()
199 // Copyright (c) 2001 Michael Goffioul <kdeprint@swing.be>
200 // original license LGPL
202 sock
.connectToPath("/ipp");
203 kDebug(OkularDebug
) << "socket wait =" << sock
.waitForConnected();
204 kDebug(OkularDebug
) << "socket error =" << sock
.error();
205 kDebug(OkularDebug
) << "socket isOpen() =" << sock
.isOpen();
206 return sock
.isOpen();
209 bool FilePrinter::detectCupsConfig()
211 if ( QFile::exists("/etc/cups/cupsd.conf") ) return true;
212 if ( QFile::exists("/usr/etc/cups/cupsd.conf") ) return true;
213 if ( QFile::exists("/usr/local/etc/cups/cupsd.conf") ) return true;
214 if ( QFile::exists("/opt/etc/cups/cupsd.conf") ) return true;
215 if ( QFile::exists("/opt/local/etc/cups/cupsd.conf") ) return true;
219 QSize
FilePrinter::psPaperSize( QPrinter
&printer
)
223 switch ( printer
.pageSize() ) {
224 case QPrinter::A0
: size
= QSize( 2384, 3370 ); break;
225 case QPrinter::A1
: size
= QSize( 1684, 2384 ); break;
226 case QPrinter::A2
: size
= QSize( 1191, 1684 ); break;
227 case QPrinter::A3
: size
= QSize( 842, 1191 ); break;
228 case QPrinter::A4
: size
= QSize( 595, 842 ); break;
229 case QPrinter::A5
: size
= QSize( 420, 595 ); break;
230 case QPrinter::A6
: size
= QSize( 298, 420 ); break;
231 case QPrinter::A7
: size
= QSize( 210, 298 ); break;
232 case QPrinter::A8
: size
= QSize( 147, 210 ); break;
233 case QPrinter::A9
: size
= QSize( 105, 147 ); break;
234 case QPrinter::B0
: size
= QSize( 2835, 4008 ); break;
235 case QPrinter::B1
: size
= QSize( 2004, 2835 ); break;
236 case QPrinter::B2
: size
= QSize( 1417, 2004 ); break;
237 case QPrinter::B3
: size
= QSize( 1001, 1417 ); break;
238 case QPrinter::B4
: size
= QSize( 709, 1001 ); break;
239 case QPrinter::B5
: size
= QSize( 499, 709 ); break;
240 case QPrinter::B6
: size
= QSize( 354, 499 ); break;
241 case QPrinter::B7
: size
= QSize( 249, 354 ); break;
242 case QPrinter::B8
: size
= QSize( 176, 249 ); break;
243 case QPrinter::B9
: size
= QSize( 125, 176 ); break;
244 case QPrinter::B10
: size
= QSize( 88, 125 ); break;
245 case QPrinter::C5E
: size
= QSize( 459, 649 ); break;
246 case QPrinter::Comm10E
: size
= QSize( 297, 684 ); break;
247 case QPrinter::DLE
: size
= QSize( 312, 624 ); break;
248 case QPrinter::Executive
: size
= QSize( 522, 756 ); break;
249 case QPrinter::Folio
: size
= QSize( 595, 935 ); break;
250 case QPrinter::Ledger
: size
= QSize( 1224, 792 ); break;
251 case QPrinter::Legal
: size
= QSize( 612, 1008 ); break;
252 case QPrinter::Letter
: size
= QSize( 612, 792 ); break;
253 case QPrinter::Tabloid
: size
= QSize( 792, 1224 ); break;
254 case QPrinter::Custom
: return QSize( (int) printer
.widthMM() * ( 25.4 / 72 ),
255 (int) printer
.heightMM() * ( 25.4 / 72 ) );
256 default: return QSize();
259 if ( printer
.orientation() == QPrinter::Landscape
) {
269 QStringList
FilePrinter::printArguments( QPrinter
&printer
, FileDeletePolicy fileDeletePolicy
,
270 PageSelectPolicy pageSelectPolicy
, bool useCupsOptions
,
271 const QString
&pageRange
, const QString
&version
)
275 if ( ! destination( printer
, version
).isEmpty() ) {
276 argList
<< destination( printer
, version
);
279 if ( ! copies( printer
, version
).isEmpty() ) {
280 argList
<< copies( printer
, version
);
283 if ( ! jobname( printer
, version
).isEmpty() ) {
284 argList
<< jobname( printer
, version
);
287 if ( ! pages( printer
, pageSelectPolicy
, pageRange
, useCupsOptions
, version
).isEmpty() ) {
288 argList
<< pages( printer
, pageSelectPolicy
, pageRange
, useCupsOptions
, version
);
291 if ( useCupsOptions
&& ! cupsOptions( printer
).isEmpty() ) {
292 argList
<< cupsOptions( printer
);
295 if ( ! deleteFile( printer
, fileDeletePolicy
, version
).isEmpty() ) {
296 argList
<< deleteFile( printer
, fileDeletePolicy
, version
);
299 if ( version
== "lp" ) {
306 QStringList
FilePrinter::destination( QPrinter
&printer
, const QString
&version
)
308 if ( version
== "lp" ) {
309 return QStringList("-d") << printer
.printerName();
312 if ( version
.startsWith( "lpr" ) ) {
313 return QStringList("-P") << printer
.printerName();
316 return QStringList();
319 QStringList
FilePrinter::copies( QPrinter
&printer
, const QString
&version
)
321 // Can't use QPrinter::numCopies(), as if CUPS will always return 1, not sure if this behaves same way as well?
322 int cp
= printer
.printEngine()->property( QPrintEngine::PPK_NumberOfCopies
).toInt();
324 if ( version
== "lp" ) {
325 return QStringList("-n") << QString("%1").arg( cp
);
328 if ( version
.startsWith( "lpr" ) ) {
329 return QStringList() << QString("-#%1").arg( cp
);
332 return QStringList();
335 QStringList
FilePrinter::jobname( QPrinter
&printer
, const QString
&version
)
337 if ( ! printer
.docName().isEmpty() ) {
339 if ( version
== "lp" ) {
340 return QStringList("-t") << printer
.docName();
343 if ( version
.startsWith( "lpr" ) ) {
344 return QStringList("-J") << printer
.docName();
348 return QStringList();
351 QStringList
FilePrinter::deleteFile( QPrinter
&printer
, FileDeletePolicy fileDeletePolicy
, const QString
&version
)
353 if ( fileDeletePolicy
== FilePrinter::SystemDeletesFiles
&& version
.startsWith( "lpr" ) ) {
354 return QStringList("-r");
357 return QStringList();
360 QStringList
FilePrinter::pages( QPrinter
&printer
, PageSelectPolicy pageSelectPolicy
, const QString
&pageRange
,
361 bool useCupsOptions
, const QString
&version
)
363 if ( pageSelectPolicy
== FilePrinter::SystemSelectsPages
) {
365 if ( printer
.printRange() == QPrinter::Selection
&& ! pageRange
.isEmpty() ) {
367 if ( version
== "lp" ) {
368 return QStringList("-P") << pageRange
;
371 if ( version
.startsWith( "lpr" ) && useCupsOptions
) {
372 return QStringList("-o") << QString("page-ranges=%1").arg( pageRange
);
377 if ( printer
.printRange() == QPrinter::PageRange
) {
379 if ( version
== "lp" ) {
380 return QStringList("-P") << QString("%1-%2").arg( printer
.fromPage() )
381 .arg( printer
.toPage() );
384 if ( version
.startsWith( "lpr" ) && useCupsOptions
) {
385 return QStringList("-o") << QString("page-ranges=%1-%2").arg( printer
.fromPage() )
386 .arg( printer
.toPage() );
393 return QStringList(); // AllPages
396 QStringList
FilePrinter::cupsOptions( QPrinter
&printer
)
398 QStringList optionList
;
400 if ( ! optionMedia( printer
).isEmpty() ) {
401 optionList
<< optionMedia( printer
);
404 if ( ! optionOrientation( printer
).isEmpty() ) {
405 optionList
<< optionOrientation( printer
);
408 if ( ! optionDoubleSidedPrinting( printer
).isEmpty() ) {
409 optionList
<< optionDoubleSidedPrinting( printer
);
412 if ( ! optionPageOrder( printer
).isEmpty() ) {
413 optionList
<< optionPageOrder( printer
);
416 if ( ! optionCollateCopies( printer
).isEmpty() ) {
417 optionList
<< optionCollateCopies( printer
);
420 optionList
<< optionCupsProperties( printer
);
425 QStringList
FilePrinter::optionMedia( QPrinter
&printer
)
427 if ( ! mediaPageSize( printer
).isEmpty() &&
428 ! mediaPaperSource( printer
).isEmpty() ) {
429 return QStringList("-o") <<
430 QString("media=%1,%2").arg( mediaPageSize( printer
) )
431 .arg( mediaPaperSource( printer
) );
434 if ( ! mediaPageSize( printer
).isEmpty() ) {
435 return QStringList("-o") <<
436 QString("media=%1").arg( mediaPageSize( printer
) );
439 if ( ! mediaPaperSource( printer
).isEmpty() ) {
440 return QStringList("-o") <<
441 QString("media=%1").arg( mediaPaperSource( printer
) );
444 return QStringList();
447 QString
FilePrinter::mediaPageSize( QPrinter
&printer
)
449 switch ( printer
.pageSize() ) {
450 case QPrinter::A0
: return "A0";
451 case QPrinter::A1
: return "A1";
452 case QPrinter::A2
: return "A2";
453 case QPrinter::A3
: return "A3";
454 case QPrinter::A4
: return "A4";
455 case QPrinter::A5
: return "A5";
456 case QPrinter::A6
: return "A6";
457 case QPrinter::A7
: return "A7";
458 case QPrinter::A8
: return "A8";
459 case QPrinter::A9
: return "A9";
460 case QPrinter::B0
: return "B0";
461 case QPrinter::B1
: return "B1";
462 case QPrinter::B10
: return "B10";
463 case QPrinter::B2
: return "B2";
464 case QPrinter::B3
: return "B3";
465 case QPrinter::B4
: return "B4";
466 case QPrinter::B5
: return "B5";
467 case QPrinter::B6
: return "B6";
468 case QPrinter::B7
: return "B7";
469 case QPrinter::B8
: return "B8";
470 case QPrinter::B9
: return "B9";
471 case QPrinter::C5E
: return "C5"; //Correct Translation?
472 case QPrinter::Comm10E
: return "Comm10"; //Correct Translation?
473 case QPrinter::DLE
: return "DL"; //Correct Translation?
474 case QPrinter::Executive
: return "Executive";
475 case QPrinter::Folio
: return "Folio";
476 case QPrinter::Ledger
: return "Ledger";
477 case QPrinter::Legal
: return "Legal";
478 case QPrinter::Letter
: return "Letter";
479 case QPrinter::Tabloid
: return "Tabloid";
480 case QPrinter::Custom
: return QString("Custom.%1x%2mm")
481 .arg( printer
.heightMM() )
482 .arg( printer
.widthMM() );
483 default: return QString();
487 // What about Upper and MultiPurpose? And others in PPD???
488 QString
FilePrinter::mediaPaperSource( QPrinter
&printer
)
490 switch ( printer
.paperSource() ) {
491 case QPrinter::Auto
: return QString();
492 case QPrinter::Cassette
: return "Cassette";
493 case QPrinter::Envelope
: return "Envelope";
494 case QPrinter::EnvelopeManual
: return "EnvelopeManual";
495 case QPrinter::FormSource
: return "FormSource";
496 case QPrinter::LargeCapacity
: return "LargeCapacity";
497 case QPrinter::LargeFormat
: return "LargeFormat";
498 case QPrinter::Lower
: return "Lower";
499 case QPrinter::MaxPageSource
: return "MaxPageSource";
500 case QPrinter::Middle
: return "Middle";
501 case QPrinter::Manual
: return "Manual";
502 case QPrinter::OnlyOne
: return "OnlyOne";
503 case QPrinter::Tractor
: return "Tractor";
504 case QPrinter::SmallFormat
: return "SmallFormat";
505 default: return QString();
509 QStringList
FilePrinter::optionOrientation( QPrinter
&printer
)
511 switch ( printer
.orientation() ) {
512 case QPrinter::Portrait
: return QStringList("-o") << "portrait";
513 case QPrinter::Landscape
: return QStringList("-o") << "landscape";
514 default: return QStringList();
518 QStringList
FilePrinter::optionDoubleSidedPrinting( QPrinter
&printer
)
520 if ( printer
.doubleSidedPrinting() ) {
521 if ( printer
.orientation() == QPrinter::Landscape
) {
522 return QStringList("-o") << "sides=two-sided-short-edge";
524 return QStringList("-o") << "sides=two-sided-long-edge";
527 return QStringList("-o") << "sides=one-sided";
530 QStringList
FilePrinter::optionPageOrder( QPrinter
&printer
)
532 if ( printer
.pageOrder() == QPrinter::LastPageFirst
) {
533 return QStringList("-o") << "outputorder=reverse";
535 return QStringList("-o") << "outputorder=normal";
538 QStringList
FilePrinter::optionCollateCopies( QPrinter
&printer
)
540 if ( printer
.collateCopies() ) {
541 return QStringList("-o") << "Collate=True";
543 return QStringList("-o") << "Collate=False";
546 QStringList
FilePrinter::optionCupsProperties( QPrinter
&printer
)
548 QStringList dialogOptions
= printer
.printEngine()->property(QPrintEngine::PrintEnginePropertyKey(0xfe00)).toStringList();
549 QStringList cupsOptions
;
551 for ( int i
= 0; i
< dialogOptions
.count(); i
= i
+ 2 ) {
552 if ( dialogOptions
[i
+1].isEmpty() ) {
553 cupsOptions
<< "-o" << dialogOptions
[i
];
555 cupsOptions
<< "-o" << dialogOptions
[i
] + "=" + dialogOptions
[i
+1];