From 1b1ed9451bcb43db8f66ddce49f038c833c29673 Mon Sep 17 00:00:00 2001 From: John Layt Date: Mon, 26 Nov 2007 21:43:54 +0000 Subject: [PATCH] Enable Okular printing features: * Add FilePrinter class to enable printing via postscript files * DJVU, PDF, and PS backends print FilePrinter * All backends enable printing of bookmarked pages * Print and Print Preview actions enabled/disabled depending on backends printing ability Note that FilePrinter only works on *NIX platforms with Cups, lpr, or lp. svn path=/trunk/KDE/kdegraphics/okular/; revision=741990 --- CMakeLists.txt | 2 + core/document.cpp | 90 +++ core/document.h | 32 + core/fileprinter.cpp | 662 +++++++++++++++++++ core/fileprinter.h | 198 ++++++ core/generator.h | 6 +- generators/comicbook/generator_comicbook.cpp | 24 +- generators/djvu/generator_djvu.cpp | 31 +- generators/dvi/dviexport.cpp | 10 +- generators/kimgio/generator_kimgio.cpp | 16 +- generators/poppler/generator_pdf.cpp | 149 ++--- generators/poppler/generator_pdf.h | 3 + generators/spectre/generator_ghostview.cpp | 59 +- generators/tiff/generator_tiff.cpp | 10 +- part.cpp | 180 +++-- part.h | 3 +- 16 files changed, 1236 insertions(+), 239 deletions(-) create mode 100644 core/fileprinter.cpp create mode 100644 core/fileprinter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f6f41269a..fc61362ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ set(okularcore_SRCS core/textdocumentgenerator.cpp core/textpage.cpp core/utils.cpp + core/fileprinter.cpp ) install( FILES @@ -64,6 +65,7 @@ install( FILES core/textdocumentgenerator.h core/textpage.h core/utils.h + core/fileprinter.h DESTINATION ${INCLUDE_INSTALL_DIR}/okular/core ) install( FILES diff --git a/core/document.cpp b/core/document.cpp index 9eebcc766..d0b199a8b 100644 --- a/core/document.cpp +++ b/core/document.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -2186,6 +2187,68 @@ BookmarkManager * Document::bookmarkManager() const return d->m_bookmarkManager; } +QList Document::bookmarkedPageList() const +{ + QList list; + uint docPages = pages(); + + //pages are 0-indexed internally, but 1-indexed externally + for ( uint i = 0; i < docPages; i++ ) + { + if ( bookmarkManager()->isBookmarked( i ) ) + { + list << i + 1; + } + } + return list; +} + +QString Document::bookmarkedPageRange() const +{ + // Code formerly in Part::slotPrint() + // range detecting + QString range; + uint docPages = pages(); + int startId = -1; + int endId = -1; + + for ( uint i = 0; i < docPages; ++i ) + { + if ( bookmarkManager()->isBookmarked( i ) ) + { + if ( startId < 0 ) + startId = i; + if ( endId < 0 ) + endId = startId; + else + ++endId; + } + else if ( startId >= 0 && endId >= 0 ) + { + if ( !range.isEmpty() ) + range += ','; + + if ( endId - startId > 0 ) + range += QString( "%1-%2" ).arg( startId + 1 ).arg( endId + 1 ); + else + range += QString::number( startId + 1 ); + startId = -1; + endId = -1; + } + } + if ( startId >= 0 && endId >= 0 ) + { + if ( !range.isEmpty() ) + range += ','; + + if ( endId - startId > 0 ) + range += QString( "%1-%2" ).arg( startId + 1 ).arg( endId + 1 ); + else + range += QString::number( startId + 1 ); + } + return range; +} + void Document::processAction( const Action * action ) { if ( !action ) @@ -2396,6 +2459,33 @@ void Document::processSourceReference( const SourceReference * ref ) QProcess::startDetached( p ); } +Document::PrintingType Document::printingSupport() const +{ + if ( d->m_generator ) + { + + if ( d->m_generator->hasFeature( Generator::PrintNative ) ) + { + return NativePrinting; + } + +#ifndef Q_OS_WIN + if ( d->m_generator->hasFeature( Generator::PrintPostscript ) ) + { + return PostscriptPrinting; + } +#endif + + } + + return NoPrinting; +} + +bool Document::supportsPrintToFile() const +{ + return d->m_generator ? d->m_generator->hasFeature( Generator::PrintToFile ) : false; +} + bool Document::print( QPrinter &printer ) { return d->m_generator ? d->m_generator->print( printer ) : false; diff --git a/core/document.h b/core/document.h index 0b431f698..048d1c12a 100644 --- a/core/document.h +++ b/core/document.h @@ -24,6 +24,7 @@ #include class QPrinter; +class QPrintDialog; class KComponentData; class KBookmark; class KConfigDialog; @@ -415,6 +416,16 @@ class OKULAR_EXPORT Document : public QObject */ void processAction( const Action *action ); + /** + * Returns a list of the bookmarked.pages + */ + QList bookmarkedPageList() const; + + /** + * Returns the range of the bookmarked.pages + */ + QString bookmarkedPageRange() const; + /** * Processes/Executes the given source @p reference. */ @@ -425,6 +436,27 @@ class OKULAR_EXPORT Document : public QObject */ bool canConfigurePrinter() const; + /** + * What type of printing a document supports + */ + enum PrintingType + { + NoPrinting, ///< Printing Not Supported + NativePrinting, ///< Native Cross-Platform Printing + PostscriptPrinting ///< Postscript file printing + }; + + /** + * Returns what sort of printing the document supports: + * Native, Postscript, None + */ + PrintingType printingSupport() const; + + /** + * Returns whether the document supports printing to both PDF and PS files. + */ + bool supportsPrintToFile() const; + /** * Prints the document to the given @p printer. */ diff --git a/core/fileprinter.cpp b/core/fileprinter.cpp new file mode 100644 index 000000000..7c11bda39 --- /dev/null +++ b/core/fileprinter.cpp @@ -0,0 +1,662 @@ +/*************************************************************************** + * Copyright (C) 2007 by John Layt * + * * + * FilePrinterPreview based on KPrintPreview (originally LGPL) * + * Copyright (c) 2007 Alex Merry * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +#include "fileprinter.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace Okular; + +int FilePrinter::printFile( QPrinter &printer, QString file, FileDeletePolicy fileDeletePolicy, + PageSelectPolicy pageSelectPolicy, const QString &pageRange ) +{ + FilePrinter fp; + return fp.doPrintFiles( printer, QStringList( file ), fileDeletePolicy, pageSelectPolicy, pageRange ); +} + +int FilePrinter::printFiles( QPrinter &printer, const QStringList &fileList, FileDeletePolicy fileDeletePolicy ) +{ + FilePrinter fp; + return fp.doPrintFiles( printer, fileList, fileDeletePolicy, FilePrinter::ApplicationSelectsPages, QString() ); +} + +int FilePrinter::doPrintFiles( QPrinter &printer, QStringList fileList, FileDeletePolicy fileDeletePolicy, + PageSelectPolicy pageSelectPolicy, const QString &pageRange ) +{ + QString exe("lpr"); + + if ( KStandardDirs::findExe(exe).isEmpty() ) { + exe = "lp"; + } + + if ( KStandardDirs::findExe(exe).isEmpty() ) { + return -9; + } + + if ( fileList.size() < 1 ) { + return -8; + } + + for (QStringList::ConstIterator it = fileList.begin(); it != fileList.end(); ++it) { + if (!QFile::exists(*it)) { + return -7; + } + } + + if ( printer.printerState() == QPrinter::Aborted || printer.printerState() == QPrinter::Error ) { + return -6; + } + + // Print to File if a filename set, assumes there must be only 1 file + if ( !printer.outputFileName().isEmpty() ) { + + if ( QFile::exists( printer.outputFileName() ) ) { + QFile::remove( printer.outputFileName() ); + } + + int res = QFile::copy( fileList[0], printer.outputFileName() ); + + if ( fileDeletePolicy == FilePrinter::SystemDeletesFiles ) { + QFile::remove( fileList[0] ); + } + + if ( res ) return 0; + + } + + bool useCupsOptions = cupsAvailable(); + QStringList argList = printArguments( printer, fileDeletePolicy, pageSelectPolicy, useCupsOptions, pageRange, exe ) + << fileList; + kDebug() << "Executing " << exe << " with arguments" << argList; + + int ret = KProcess::execute( exe, argList ); + + // If we used the Cups options and the command failed, try again without them in case Cups lpr/lp not installed. + // I'm not convinced this will work, I don't think KProcess returns the result of the command, but rather + // that it was able to be executed? + if ( useCupsOptions && ret < 0 ) { + + argList = printArguments( printer, fileDeletePolicy, pageSelectPolicy, useCupsOptions, pageRange, exe ) + << fileList; + kDebug() << "Retrying " << exe << " without cups arguments" << argList; + + ret = KProcess::execute( exe, argList ); + } + + return ret; +} + +QList FilePrinter::pageList( QPrinter &printer, int lastPage, const QList &selectedPageList ) +{ + if ( printer.printRange() == QPrinter::Selection) { + return selectedPageList; + } + + int startPage, endPage; + QList list; + + if ( printer.printRange() == QPrinter::PageRange ) { + startPage = printer.fromPage(); + endPage = printer.toPage(); + } else { //AllPages + startPage = 1; + endPage = lastPage; + } + + for (int i = startPage; i <= endPage; i++ ) { + list << i; + } + return list; +} + +QString FilePrinter::pageRange( QPrinter &printer, int lastPage, const QList &selectedPageList ) +{ + if ( printer.printRange() == QPrinter::Selection) { + return pageListToPageRange( selectedPageList ); + } + + if ( printer.printRange() == QPrinter::PageRange ) { + return QString("%1-%2").arg(printer.fromPage()).arg(printer.toPage()); + } + + return QString("1-%2").arg( lastPage ); +} + +QString FilePrinter::pageListToPageRange( const QList &pageList ) +{ + QString pageRange; + int count = pageList.count(); + int i = 0; + int seqStart = i; + int seqEnd; + + while ( i != count ) { + + if ( i + 1 == count || pageList[i] + 1 != pageList[i+1] ) { + + seqEnd = i; + + if ( !pageRange.isEmpty() ) { + pageRange.append(","); + } + + if ( seqStart == seqEnd ) { + pageRange.append(pageList[i]); + } else { + pageRange.append("%1-%2").arg(seqStart).arg(seqEnd); + } + + seqStart = i + 1; + } + + i++; + } + + return pageRange; +} + +bool FilePrinter::cupsAvailable() +{ + FilePrinter fp; + return ( fp.detectCupsConfig() /*&& fp.detectCupsService()*/ ); +} + +bool FilePrinter::detectCupsService() +{ + // copied from KdeprintChecker::checkService() + // Copyright (c) 2001 Michael Goffioul + // original license LGPL + KLocalSocket sock; + sock.connectToPath("/ipp"); + kDebug() << "socket wait = " << sock.waitForConnected(); + kDebug() << "socket error = " << sock.error(); + kDebug() << "socket isOpen() = " << sock.isOpen(); + return sock.isOpen(); +} + +bool FilePrinter::detectCupsConfig() +{ + if ( QFile::exists("/etc/cups/cupsd.conf") ) return true; + if ( QFile::exists("/usr/etc/cups/cupsd.conf") ) return true; + if ( QFile::exists("/usr/local/etc/cups/cupsd.conf") ) return true; + if ( QFile::exists("/opt/etc/cups/cupsd.conf") ) return true; + if ( QFile::exists("/opt/local/etc/cups/cupsd.conf") ) return true; + return false; +} + +QSize FilePrinter::psPaperSize( QPrinter &printer ) +{ + QSize size; + + switch ( printer.pageSize() ) { + case QPrinter::A0: size = QSize( 2384, 3370 ); break; + case QPrinter::A1: size = QSize( 1684, 2384 ); break; + case QPrinter::A2: size = QSize( 1191, 1684 ); break; + case QPrinter::A3: size = QSize( 842, 1191 ); break; + case QPrinter::A4: size = QSize( 595, 842 ); break; + case QPrinter::A5: size = QSize( 420, 595 ); break; + case QPrinter::A6: size = QSize( 298, 420 ); break; + case QPrinter::A7: size = QSize( 210, 298 ); break; + case QPrinter::A8: size = QSize( 147, 210 ); break; + case QPrinter::A9: size = QSize( 105, 147 ); break; + case QPrinter::B0: size = QSize( 2835, 4008 ); break; + case QPrinter::B1: size = QSize( 2004, 2835 ); break; + case QPrinter::B2: size = QSize( 1417, 2004 ); break; + case QPrinter::B3: size = QSize( 1001, 1417 ); break; + case QPrinter::B4: size = QSize( 709, 1001 ); break; + case QPrinter::B5: size = QSize( 499, 709 ); break; + case QPrinter::B6: size = QSize( 354, 499 ); break; + case QPrinter::B7: size = QSize( 249, 354 ); break; + case QPrinter::B8: size = QSize( 176, 249 ); break; + case QPrinter::B9: size = QSize( 125, 176 ); break; + case QPrinter::B10: size = QSize( 88, 125 ); break; + case QPrinter::C5E: size = QSize( 459, 649 ); break; + case QPrinter::Comm10E: size = QSize( 297, 684 ); break; + case QPrinter::DLE: size = QSize( 312, 624 ); break; + case QPrinter::Executive: size = QSize( 522, 756 ); break; + case QPrinter::Folio: size = QSize( 595, 935 ); break; + case QPrinter::Ledger: size = QSize( 1224, 792 ); break; + case QPrinter::Legal: size = QSize( 612, 1008 ); break; + case QPrinter::Letter: size = QSize( 612, 792 ); break; + case QPrinter::Tabloid: size = QSize( 792, 1224 ); break; + case QPrinter::Custom: return QSize( (int) printer.widthMM() * ( 25.4 / 72 ), + (int) printer.heightMM() * ( 25.4 / 72 ) ); + default: return QSize(); + } + + if ( printer.orientation() == QPrinter::Landscape ) { + size.transpose(); + } + + return size; +} + + + + +QStringList FilePrinter::printArguments( QPrinter &printer, FileDeletePolicy fileDeletePolicy, + PageSelectPolicy pageSelectPolicy, bool useCupsOptions, + const QString &pageRange, const QString &version ) +{ + QStringList argList; + + if ( ! destination( printer, version ).isEmpty() ) { + argList << destination( printer, version ); + } + + if ( ! copies( printer, version ).isEmpty() ) { + argList << copies( printer, version ); + } + + if ( ! jobname( printer, version ).isEmpty() ) { + argList << jobname( printer, version ); + } + + if ( ! pages( printer, pageSelectPolicy, pageRange, useCupsOptions, version ).isEmpty() ) { + argList << pages( printer, pageSelectPolicy, pageRange, useCupsOptions, version ); + } + + if ( useCupsOptions && ! cupsOptions( printer ).isEmpty() ) { + argList << cupsOptions( printer ); + } + + if ( ! deleteFile( printer, fileDeletePolicy, version ).isEmpty() ) { + argList << deleteFile( printer, fileDeletePolicy, version ); + } + + if ( version == "lp" ) { + argList << "--"; + } + + return argList; +} + +QStringList FilePrinter::destination( QPrinter &printer, const QString &version ) +{ + if ( version == "lp" ) { + return QStringList("-d") << printer.printerName(); + } + + if ( version == "lpr" ) { + return QStringList("-P") << printer.printerName(); + } + + return QStringList(); +} + +QStringList FilePrinter::copies( QPrinter &printer, const QString &version ) +{ + // Can't use QPrinter::numCopies(), as if CUPS will always return 1, not sure if this behaves same way as well? + int cp = printer.printEngine()->property( QPrintEngine::PPK_NumberOfCopies ).toInt(); + + if ( version == "lp" ) { + return QStringList("-n") << QString("%1").arg( cp ); + } + + if ( version == "lpr" ) { + return QStringList() << QString("-#%1").arg( cp ); + } + + return QStringList(); +} + +QStringList FilePrinter::jobname( QPrinter &printer, const QString &version ) +{ + if ( ! printer.docName().isEmpty() ) { + + if ( version == "lp" ) { + return QStringList("-t") << printer.docName(); + } + + if ( version == "lpr" ) { + return QStringList("-J") << printer.docName(); + } + } + + return QStringList(); +} + +QStringList FilePrinter::deleteFile( QPrinter &printer, FileDeletePolicy fileDeletePolicy, const QString &version ) +{ + if ( fileDeletePolicy == FilePrinter::SystemDeletesFiles && version == "lpr" ) { + return QStringList("-r"); + } + + return QStringList(); +} + +QStringList FilePrinter::pages( QPrinter &printer, PageSelectPolicy pageSelectPolicy, const QString &pageRange, + bool useCupsOptions, const QString &version ) +{ + if ( pageSelectPolicy == FilePrinter::SystemSelectsPages ) { + + if ( printer.printRange() == QPrinter::Selection && ! pageRange.isEmpty() ) { + + if ( version == "lp" ) { + return QStringList("-P") << pageRange ; + } + + if ( version == "lpr" && useCupsOptions ) { + return QStringList("-o") << QString("page-ranges=%1").arg( pageRange ); + } + + } + + if ( printer.printRange() == QPrinter::PageRange ) { + + if ( version == "lp" ) { + return QStringList("-P") << QString("%1-%2").arg( printer.fromPage() ) + .arg( printer.toPage() ); + } + + if ( version == "lpr" && useCupsOptions ) { + return QStringList("-o") << QString("page-ranges=%1-%2").arg( printer.fromPage() ) + .arg( printer.toPage() ); + } + + } + + } + + return QStringList(); // AllPages +} + +QStringList FilePrinter::cupsOptions( QPrinter &printer ) +{ + QStringList optionList; + + if ( ! optionMedia( printer ).isEmpty() ) { + optionList << optionMedia( printer ); + } + + if ( ! optionOrientation( printer ).isEmpty() ) { + optionList << optionOrientation( printer ); + } + + if ( ! optionDoubleSidedPrinting( printer ).isEmpty() ) { + optionList << optionDoubleSidedPrinting( printer ); + } + + if ( ! optionPageOrder( printer ).isEmpty() ) { + optionList << optionPageOrder( printer ); + } + + if ( ! optionCollateCopies( printer ).isEmpty() ) { + optionList << optionCollateCopies( printer ); + } + + return optionList; +} + +QStringList FilePrinter::optionMedia( QPrinter &printer ) +{ + if ( ! mediaPageSize( printer ).isEmpty() && + ! mediaPaperSource( printer ).isEmpty() ) { + return QStringList("-o") << + QString("media=%1,%2").arg( mediaPageSize( printer ) ) + .arg( mediaPaperSource( printer ) ); + } + + if ( ! mediaPageSize( printer ).isEmpty() ) { + return QStringList("-o") << + QString("media=%1").arg( mediaPageSize( printer ) ); + } + + if ( ! mediaPaperSource( printer ).isEmpty() ) { + return QStringList("-o") << + QString("media=%1").arg( mediaPaperSource( printer ) ); + } + + return QStringList(); +} + +QString FilePrinter::mediaPageSize( QPrinter &printer ) +{ + switch ( printer.pageSize() ) { + case QPrinter::A0: return "A0"; + case QPrinter::A1: return "A1"; + case QPrinter::A2: return "A2"; + case QPrinter::A3: return "A3"; + case QPrinter::A4: return "A4"; + case QPrinter::A5: return "A5"; + case QPrinter::A6: return "A6"; + case QPrinter::A7: return "A7"; + case QPrinter::A8: return "A8"; + case QPrinter::A9: return "A9"; + case QPrinter::B0: return "B0"; + case QPrinter::B1: return "B1"; + case QPrinter::B10: return "B10"; + case QPrinter::B2: return "B2"; + case QPrinter::B3: return "B3"; + case QPrinter::B4: return "B4"; + case QPrinter::B5: return "B5"; + case QPrinter::B6: return "B6"; + case QPrinter::B7: return "B7"; + case QPrinter::B8: return "B8"; + case QPrinter::B9: return "B9"; + case QPrinter::C5E: return "C5"; //Correct Translation? + case QPrinter::Comm10E: return "Comm10"; //Correct Translation? + case QPrinter::DLE: return "DL"; //Correct Translation? + case QPrinter::Executive: return "Executive"; + case QPrinter::Folio: return "Folio"; + case QPrinter::Ledger: return "Ledger"; + case QPrinter::Legal: return "Legal"; + case QPrinter::Letter: return "Letter"; + case QPrinter::Tabloid: return "Tabloid"; + case QPrinter::Custom: return QString("Custom.%1x%2mm") + .arg( printer.heightMM() ) + .arg( printer.widthMM() ); + default: return QString(); + } +} + +// What about Upper and MultiPurpose? And others in PPD??? +QString FilePrinter::mediaPaperSource( QPrinter &printer ) +{ + switch ( printer.paperSource() ) { + case QPrinter::Auto: return QString(); + case QPrinter::Cassette: return "Cassette"; + case QPrinter::Envelope: return "Envelope"; + case QPrinter::EnvelopeManual: return "EnvelopeManual"; + case QPrinter::FormSource: return "FormSource"; + case QPrinter::LargeCapacity: return "LargeCapacity"; + case QPrinter::LargeFormat: return "LargeFormat"; + case QPrinter::Lower: return "Lower"; + case QPrinter::MaxPageSource: return "MaxPageSource"; + case QPrinter::Middle: return "Middle"; + case QPrinter::Manual: return "Manual"; + case QPrinter::OnlyOne: return "OnlyOne"; + case QPrinter::Tractor: return "Tractor"; + case QPrinter::SmallFormat: return "SmallFormat"; + default: return QString(); + } +} + +QStringList FilePrinter::optionOrientation( QPrinter &printer ) +{ + switch ( printer.orientation() ) { + case QPrinter::Portrait: return QStringList("-o") << "portrait"; + case QPrinter::Landscape: return QStringList("-o") << "landscape"; + default: return QStringList(); + } +} + +QStringList FilePrinter::optionDoubleSidedPrinting( QPrinter &printer ) +{ + if ( printer.doubleSidedPrinting() ) { + if ( printer.orientation() == QPrinter::Landscape ) { + return QStringList("-o") << "sides=two-sided-short-edge"; + } else { + return QStringList("-o") << "sides=two-sided-long-edge"; + } + } + return QStringList("-o") << "sides=one-sided"; +} + +QStringList FilePrinter::optionPageOrder( QPrinter &printer ) +{ + if ( printer.pageOrder() == QPrinter::LastPageFirst ) { + return QStringList("-o") << "outputorder=reverse"; + } + return QStringList("-o") << "outputorder=normal"; +} + +QStringList FilePrinter::optionCollateCopies( QPrinter &printer ) +{ + if ( printer.collateCopies() ) { + return QStringList("-o") << "Collate=True"; + } + return QStringList("-o") << "Collate=False"; +} + +// This code copied from KPrintPreview by Alex Merry, adapted to do PS files instead of PDF + +class Okular::FilePrinterPreviewPrivate +{ +public: + FilePrinterPreviewPrivate( FilePrinterPreview *host, const QString & _filename ) + : q(host) + , mainWidget(new QWidget(host)) + , previewPart(0) + , failMessage(0) + { + filename = _filename; + } + + void getPart(); + bool doPreview(); + void fail(); + + FilePrinterPreview *q; + + QWidget *mainWidget; + + QString filename; + + KParts::ReadOnlyPart *previewPart; + QWidget *failMessage; +}; + +void FilePrinterPreviewPrivate::getPart() +{ + if (previewPart) { + kDebug(500) << "already got a part"; + return; + } + kDebug(500) << "querying trader for application/ps service"; + + KPluginFactory *factory(0); + KService::List offers = + KMimeTypeTrader::self()->query("application/postscript", "KParts/ReadOnlyPart"); + + KService::List::ConstIterator it = offers.begin(); + while (!factory && it != offers.end()) { + KPluginLoader loader(**it); + factory = loader.factory(); + if (!factory) { + kDebug(500) << "Loading failed:" << loader.errorString(); + } + ++it; + } + if (factory) { + kDebug(500) << "Trying to create a part"; + previewPart = factory->create(q, (QVariantList() << "Print/Preview")); + if (!previewPart) { + kDebug(500) << "Part creation failed"; + } + } +} + +bool FilePrinterPreviewPrivate::doPreview() +{ + if (!QFile::exists(filename)) { + kWarning() << "Nothing was produced to be previewed"; + return false; + } + + getPart(); + if (!previewPart) { + //TODO: error dialog + kWarning() << "Could not find a PS viewer for the preview dialog"; + fail(); + return false; + } else { + q->setMainWidget(previewPart->widget()); + return previewPart->openUrl(filename); + } +} + +void FilePrinterPreviewPrivate::fail() +{ + if (!failMessage) { + failMessage = new QLabel(i18n("Could not load print preview part"), q); + } + q->setMainWidget(failMessage); +} + + + + +FilePrinterPreview::FilePrinterPreview( const QString &filename, QWidget *parent ) + : KDialog( parent ) + , d( new FilePrinterPreviewPrivate( this, filename ) ) +{ + kDebug(500) << "kdeprint: creating preview dialog"; + + // Set up the dialog + setCaption(i18n("Print Preview")); + setButtons(KDialog::Close); +} + +FilePrinterPreview::~FilePrinterPreview() +{ + delete d; +} + +void FilePrinterPreview::showEvent(QShowEvent *event) +{ + if (!event->spontaneous()) { + // being shown for the first time + if (!d->doPreview()) { + event->accept(); + return; + } + } + KDialog::showEvent(event); +} + +#include "fileprinter.moc" + + + + + diff --git a/core/fileprinter.h b/core/fileprinter.h new file mode 100644 index 000000000..aa5f97f9d --- /dev/null +++ b/core/fileprinter.h @@ -0,0 +1,198 @@ +/*************************************************************************** + * Copyright (C) 2007 by John Layt * + * * + * FilePrinterPreview based on KPrintPreview (originally LGPL) * + * Copyright (c) 2007 Alex Merry * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ + +// This Class is a temporary addition to Okular for the duration of KDE 4.0. +// In KDE 4.1 this class will either be moved to kdelibs if still required, +// or replaced with a Qt 4.4 based solution. + +#ifndef FILEPRINTER_H +#define FILEPRINTER_H + +#include +#include + +#include + +#include + +class QPrinter; +class QSize; + +namespace Okular { + +class OKULAR_EXPORT FilePrinter +{ +public: + + /** Whether file(s) get deleted by the application or by the print system. + * + * You may need to chose system deletion if your temp file clean-up + * deletes the file before the print system is finished with it. + */ + enum FileDeletePolicy { ApplicationDeletesFiles, SystemDeletesFiles }; + + /** Whether pages to be printed are selected by the application or the print system. + * + * If application side, then the generated file will only contain those pages + * selected by the user, so FilePrinter will print all the pages in the file. + * + * If system side, then the file will contain all the pages in the document, and + * the print system will print the users selected print range from out of the file. + * + * Note system side only works in CUPS, not LPR. + */ + enum PageSelectPolicy { ApplicationSelectsPages, SystemSelectsPages }; + + /** Print a file using the settings in QPrinter + * + * Only supports CUPS and LPR on *NIX. Page Range only supported in CUPS. + * Most settings unsupported by LPR, some settings unsupported by CUPS. + * + * @param printer the print settings to use + * @param file the file to print + * @param fileDeletePolicy if the application or system deletes the file + * @param pageSelectPolicy if the application or system selects the pages to print + * @param pageRange page range to print if SystemSlectsPages and user chooses Selection in Print Dialog + * + * @returns Returns exit code: + * -9 if lpr not found + * -8 if empty file name + * -7 if unable to find file + * -6 if invalid printer state + * -2 if the KProcess could not be started + * -1 if the KProcess crashed + * otherwise the KProcess exit code + */ + + static int printFile( QPrinter &printer, const QString file, + FileDeletePolicy fileDeletePolicy = FilePrinter::ApplicationDeletesFiles, + PageSelectPolicy pageSelectPolicy = FilePrinter::ApplicationSelectsPages, + const QString &pageRange = QString() ); + + /** Print a list of files using the settings in QPrinter + * + * Only supports CUPS and LPR on *NIX. + * Most settings unsupported by LPR, some settings unsupported by CUPS. + * + * @param printer the print settings to use + * @param fileList the files to print + * @param fileDeletePolicy if the application or system deletes the file + * + * @returns Returns exit code: + * -9 if lpr not found + * -8 if empty file list + * -7 if unable to find a file + * -6 if invalid printer state + * -2 if the KProcess could not be started + * -1 if the KProcess crashed + * otherwise the KProcess exit code + */ + + static int printFiles( QPrinter &printer, const QStringList &fileList, + FileDeletePolicy fileDeletePolicy = FilePrinter::ApplicationDeletesFiles ); + + /** Return the list of pages selected by the user in the Print Dialog + * + * @param printer the print settings to use + * @param lastPage the last page number, needed if AllPages option is selected + * @param selectedPageList list of pages to use if Selection option is selected + * @returns Returns list of pages to print + */ + static QList pageList( QPrinter &printer, int lastPage, const QList &selectedPageList ); + + /** Return the range of pages selected by the user in the Print Dialog + * + * @param printer the print settings to use + * @param lastPage the last page number, needed if AllPages option is selected + * @param selectedPageList list of pages to use if Selection option is selected + * @returns Returns range of pages to print + */ + static QString pageRange( QPrinter &printer, int lastPage, const QList &selectedPageList ); + + /** convert a Page List into a Page Range + * + * @param pageList list of pages to convert + * @returns Returns equivalent page range + */ + static QString pageListToPageRange( const QList &pageList ); + + /** Return if CUPS Print System is available on this system + * + * @returns Returns true if CUPS available + */ + static bool cupsAvailable(); + + /** Returns the postscript standard page size + * + * @returns Returns paper size in ps points + */ + static QSize psPaperSize( QPrinter &printer ); + +protected: + + bool detectCupsService(); + bool detectCupsConfig(); + + int doPrintFiles( QPrinter &printer, const QStringList fileList, + FileDeletePolicy fileDeletePolicy, PageSelectPolicy pageSelectPolicy, + const QString &pageRange ); + + QStringList printArguments( QPrinter &printer, + FileDeletePolicy fileDeletePolicy, PageSelectPolicy pageSelectPolicy, + bool useCupsOptions, const QString &pageRange, const QString &version ); + + QStringList destination( QPrinter &printer, const QString &version ); + QStringList copies( QPrinter &printer, const QString &version ); + QStringList jobname( QPrinter &printer, const QString &version ); + QStringList deleteFile( QPrinter &printer, FileDeletePolicy fileDeletePolicy, + const QString &version ); + QStringList pages( QPrinter &printer, PageSelectPolicy pageSelectPolicy, + const QString &pageRange, bool useCupsOptions, const QString &version ); + + QStringList cupsOptions( QPrinter &printer ); + QStringList optionMedia( QPrinter &printer ); + QString mediaPageSize( QPrinter &printer ); + QString mediaPaperSource( QPrinter &printer ); + QStringList optionOrientation( QPrinter &printer ); + QStringList optionDoubleSidedPrinting( QPrinter &printer ); + QStringList optionPageOrder( QPrinter &printer ); + QStringList optionCollateCopies( QPrinter &printer ); +}; + +// This code copied from KPrintPreview by Alex Merry, adapted to do PS files instead of PDF + +class FilePrinterPreviewPrivate; + +class OKULAR_EXPORT FilePrinterPreview : public KDialog +{ + Q_OBJECT + +public: + /** + * Create a Print Preview dialog for a given file. + * + * @param printer file to print preview + * @param parent pointer to the parent widget for the dialog + */ + explicit FilePrinterPreview( const QString &filename, QWidget *parent = 0 ); + virtual ~FilePrinterPreview(); + +protected: + void showEvent( QShowEvent *event ); + +private: + FilePrinterPreviewPrivate * const d; +}; + +} + +#endif // FILEPRINTER_H diff --git a/core/generator.h b/core/generator.h index 4890002df..e32509343 100644 --- a/core/generator.h +++ b/core/generator.h @@ -33,6 +33,7 @@ class QMutex; class QPrinter; +class QPrintDialog; class KAboutData; class KComponentData; class KIcon; @@ -196,7 +197,10 @@ class OKULAR_EXPORT Generator : public QObject TextExtraction, ///< Whether the Generator can extract text from the document in the form of TextPage's ReadRawData, ///< Whether the Generator can read a document directly from its raw data. FontInfo, ///< Whether the Generator can provide information about the fonts used in the document - PageSizes ///< Whether the Generator can change the size of the document pages. + PageSizes, ///< Whether the Generator can change the size of the document pages. + PrintNative, ///< Whether the Generator supports native cross-platform printing (QPainter-based). + PrintPostscript, ///< Whether the Generator supports postscript-based file printing. + PrintToFile ///< Whether the Generator supports export to PDF & PS through the Print Dialog }; /** diff --git a/generators/comicbook/generator_comicbook.cpp b/generators/comicbook/generator_comicbook.cpp index a37237c6e..96c41a9a9 100644 --- a/generators/comicbook/generator_comicbook.cpp +++ b/generators/comicbook/generator_comicbook.cpp @@ -12,7 +12,9 @@ #include #include +#include #include +#include OKULAR_EXPORT_PLUGIN(ComicBookGenerator) @@ -20,6 +22,8 @@ ComicBookGenerator::ComicBookGenerator() : Generator() { setFeature( Threaded ); + setFeature( PrintNative ); + setFeature( PrintToFile ); } ComicBookGenerator::~ComicBookGenerator() @@ -70,19 +74,17 @@ bool ComicBookGenerator::print( QPrinter& printer ) { QPainter p( &printer ); - for ( int i = 0; i < mDocument.pages(); ++i ) { - QImage image = mDocument.pageImage( i ); - uint left, top, right, bottom; - left = printer.paperRect().left() - printer.pageRect().left(); - top = printer.paperRect().top() - printer.pageRect().top(); - right = printer.paperRect().right() - printer.pageRect().right(); - bottom = printer.paperRect().bottom() - printer.pageRect().bottom(); + QList pageList = Okular::FilePrinter::pageList( printer, document()->pages(), + document()->bookmarkedPageList() ); - int pageWidth = printer.width() - right; - int pageHeight = printer.height() - bottom; + for ( int i = 0; i < pageList.count(); ++i ) { - if ( (image.width() > pageWidth) || (image.height() > pageHeight) ) - image = image.scaled( pageWidth, pageHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); + QImage image = mDocument.pageImage( pageList[i] - 1 ); + + if ( ( image.width() > printer.width() ) || ( image.height() > printer.height() ) ) + + image = image.scaled( printer.width(), printer.height(), + Qt::KeepAspectRatio, Qt::SmoothTransformation ); if ( i != 0 ) printer.newPage(); diff --git a/generators/djvu/generator_djvu.cpp b/generators/djvu/generator_djvu.cpp index 315e42d8b..0e05107d2 100644 --- a/generators/djvu/generator_djvu.cpp +++ b/generators/djvu/generator_djvu.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,7 @@ DjVuGenerator::DjVuGenerator() { setFeature( TextExtraction ); setFeature( Threaded ); + setFeature( PrintPostscript ); m_djvu = new KDjVu(); @@ -185,30 +187,31 @@ const Okular::DocumentSynopsis * DjVuGenerator::generateDocumentSynopsis() bool DjVuGenerator::print( QPrinter& printer ) { -/* This printing method unsupported in QPrinter, looking for alternative. - - QList pageList; - if ( !printer.previewOnly() ) - pageList = printer.pageList(); - else - { - int pages = m_djvu->pages().count(); - for( int i = 1; i <= pages; ++i ) - pageList.push_back(i); - } + bool result = false; + // Create tempfile to write to KTemporaryFile tf; tf.setSuffix( ".ps" ); if ( !tf.open() ) return false; QMutexLocker locker( userMutex() ); + QList pageList = Okular::FilePrinter::pageList( printer, m_djvu->pages().count(), + document()->bookmarkedPageList() ); + if ( m_djvu->exportAsPostScript( &tf, pageList ) ) { - return printer.printFiles( QStringList( tf.fileName() ), false ); + tf.setAutoRemove( false ); + int ret = Okular::FilePrinter::printFile( printer, tf.fileName(), + Okular::FilePrinter::SystemDeletesFiles, + Okular::FilePrinter::ApplicationSelectsPages, + document()->bookmarkedPageRange() ); + result = ( ret >=0 ); } -*/ - return false; + + tf.close(); + + return result; } QVariant DjVuGenerator::metaData( const QString &key, const QVariant &option ) const diff --git a/generators/dvi/dviexport.cpp b/generators/dvi/dviexport.cpp index 3742a9b24..8d3cd3978 100644 --- a/generators/dvi/dviexport.cpp +++ b/generators/dvi/dviexport.cpp @@ -478,9 +478,13 @@ void DVIExportToPS::finished_impl(int exit_code) { if (printer_ && !output_name_.isEmpty()) { const QFileInfo output(output_name_); - if (output.exists() && output.isReadable()) - //Unsupported in Qt - //printer_->printFiles(QStringList(output_name_), true); + if (output.exists() && output.isReadable()) { + // I'm not 100% sure on this, think we still need to select pages in export to ps above + FilePrinter::printFile( printer_, output_name_, + FilePrinter::ApplicationDeletesFiles, + FilePrinter::ApplicationSelectsPages, + QString() ); + } } #ifndef DVIEXPORT_USE_QPROCESS diff --git a/generators/kimgio/generator_kimgio.cpp b/generators/kimgio/generator_kimgio.cpp index 08a0f5e16..24d244b0e 100644 --- a/generators/kimgio/generator_kimgio.cpp +++ b/generators/kimgio/generator_kimgio.cpp @@ -31,6 +31,8 @@ KIMGIOGenerator::KIMGIOGenerator() { setFeature( ReadRawData ); setFeature( Threaded ); + setFeature( PrintNative ); + setFeature( PrintToFile ); KAboutData *about = new KAboutData( "okular_kimgio", @@ -122,18 +124,12 @@ bool KIMGIOGenerator::print( QPrinter& printer ) { QPainter p( &printer ); - uint left, top, right, bottom; - left = printer.paperRect().left() - printer.pageRect().left(); - top = printer.paperRect().top() - printer.pageRect().top(); - right = printer.paperRect().right() - printer.pageRect().right(); - bottom = printer.paperRect().bottom() - printer.pageRect().bottom(); + QImage image( m_img ); - int pageWidth = printer.width() - right; - int pageHeight = printer.height() - bottom; + if ( ( image.width() > printer.width() ) || ( image.height() > printer.height() ) ) - QImage image( m_img ); - if ( (image.width() > pageWidth) || (image.height() > pageHeight) ) - image = image.scaled( pageWidth, pageHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation ); + image = image.scaled( printer.width(), printer.height(), + Qt::KeepAspectRatio, Qt::SmoothTransformation ); p.drawImage( 0, 0, image ); diff --git a/generators/poppler/generator_pdf.cpp b/generators/poppler/generator_pdf.cpp index 8b1cc38f3..3ee4ee103 100644 --- a/generators/poppler/generator_pdf.cpp +++ b/generators/poppler/generator_pdf.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -106,15 +107,14 @@ class PDFOptionsPage : public QWidget layout->addStretch(1); } - void getOptions( QMap& opts, bool incldef = false ) + bool printForceRaster() { - Q_UNUSED(incldef); - opts[ "kde-okular-poppler-forceRaster" ] = QString::number( m_forceRaster->isChecked() ); + return m_forceRaster->isChecked(); } - void setOptions( const QMap& opts ) + void setPrintForceRaster( bool forceRaster ) { - m_forceRaster->setChecked( opts[ "kde-okular-poppler-forceRaster" ].toInt() ); + m_forceRaster->setChecked( forceRaster ); } private: @@ -292,7 +292,7 @@ OKULAR_EXPORT_PLUGIN(PDFGenerator) PDFGenerator::PDFGenerator() : Generator(), pdfdoc( 0 ), ready( true ), pixmapRequest( 0 ), docInfoDirty( true ), docSynopsisDirty( true ), - docEmbeddedFilesDirty( true ) + docEmbeddedFilesDirty( true ), pdfOptionsPage( 0 ) { // ### TODO fill after the KDE 4.0 unfreeze KAboutData *about = new KAboutData( @@ -307,8 +307,10 @@ PDFGenerator::PDFGenerator() setAboutData( about ); setFeature( TextExtraction ); setFeature( FontInfo ); + setFeature( PrintPostscript ); #ifdef HAVE_POPPLER_0_6 setFeature( ReadRawData ); + pdfOptionsPage = new PDFOptionsPage(); #endif // update the configuration reparseConfig(); @@ -325,6 +327,8 @@ PDFGenerator::~PDFGenerator() generatorThread->wait(); delete generatorThread; } + + delete pdfOptionsPage; } //BEGIN Generator inherited functions @@ -842,119 +846,104 @@ Okular::TextPage* PDFGenerator::textPage( Okular::Page *page ) bool PDFGenerator::print( QPrinter& printer ) { -/* This printing method unsupported in QPrinter, looking for alternative. - int width, height; - // PageSize is a CUPS artificially created setting - QString ps = printer.option( "PageSize" ); - QRegExp sizere( "w(\\d+)h(\\d+)" ); - int marginTop, marginLeft, marginRight, marginBottom; - marginTop = (int)printer.option("kde-margin-top").toDouble(); - marginLeft = (int)printer.option("kde-margin-left").toDouble(); - marginRight = (int)printer.option("kde-margin-right").toDouble(); - marginBottom = (int)printer.option("kde-margin-bottom").toDouble(); - if ( sizere.exactMatch( ps ) ) - { - // size not supported by Qt, CUPS gives us the size as wWIDTHhHEIGHT, at least on the printers i tested - width = sizere.cap( 1 ).toInt(); - height = sizere.cap( 2 ).toInt(); - } - else - { - // size is supported by Qt, we get either the pageSize name or nothing because the CUPS driver - // does not do any translation, then use KPrinter::pageSize to get the page size - KPrinter::PageSize qtPageSize; - if (!ps.isEmpty()) - { - bool ok; - qtPageSize = pageNameToPageSize(ps, &ok); - // If we could not decode page size from the cups text try KPrinter::pageSize as last resort :-D - if (!ok) qtPageSize = printer.pageSize(); - } - else qtPageSize = printer.pageSize(); - - QPrinter dummy(QPrinter::PrinterResolution); - dummy.setOrientation((QPrinter::Orientation)printer.orientation()); - dummy.setFullPage(true); - dummy.setPageSize((QPrinter::PageSize)qtPageSize); - - width = dummy.width(); - height = dummy.height(); - } - + // Get the real page size to pass to the ps generator + QPrinter dummy( QPrinter::PrinterResolution ); + dummy.setFullPage( true ); + dummy.setOrientation( printer.orientation() ); + int width = dummy.width(); + int height = dummy.height(); + + // Create the tempfile to send to FilePrinter, which will manage the deletion KTemporaryFile tf; tf.setSuffix( ".ps" ); if ( !tf.open() ) return false; QString tempfilename = tf.fileName(); -#if !POPPLER_HAVE_PSCONVERTER_SETOUTPUTDEVICE - tf.close(); -#endif - QList pageList; - if (!printer.previewOnly()) pageList = printer.pageList(); - else for(int i = 1; i <= pdfdoc->numPages(); i++) pageList.push_back(i); - + // Generate the list of pages to be printed as selected in the print dialog + QList pageList = Okular::FilePrinter::pageList( printer, pdfdoc->numPages(), + document()->bookmarkedPageList() ); + // TODO rotation + #ifdef HAVE_POPPLER_0_6 - double xScale = ((double)width - (double)marginLeft - (double)marginRight) / (double)width; - double yScale = ((double)height - (double)marginBottom - (double)marginTop) / (double)height; - bool strictMargins = false; - if ( abs((int)(xScale * 100) - (int)(yScale * 100)) > 5 ) { - int result = KMessageBox::questionYesNo(document()->widget(), - i18n("The margins you specified are changing the page aspect ratio. Do you want to print with the aspect ratio changed or do you want the margins to be adapted so that aspect ratio is preserved?"), - i18n("Aspect ratio change"), - KGuiItem( i18n("Print with specified margins") ), - KGuiItem( i18n("Print adapting margins to keep aspect ratio") ), - "kpdfStrictlyObeyMargins"); - if (result == KMessageBox::Yes) strictMargins = true; - } + +#if POPPLER_HAVE_PSCONVERTER_SETOUTPUTDEVICE + tf.setAutoRemove(false); +#else + tf.close(); +#endif + QString pstitle = metaData(QLatin1String("Title"), QVariant()).toString(); if ( pstitle.trimmed().isEmpty() ) { pstitle = document()->currentDocument().fileName(); } - bool forceRasterize = printer.option("kde-okular-poppler-forceRaster").toInt(); + + bool forceRasterize = pdfOptionsPage->printForceRaster(); + Poppler::PSConverter *psConverter = pdfdoc->psConverter(); + #if POPPLER_HAVE_PSCONVERTER_SETOUTPUTDEVICE psConverter->setOutputDevice(&tf); #else psConverter->setOutputFileName(tempfilename); #endif + psConverter->setPageList(pageList); psConverter->setPaperWidth(width); psConverter->setPaperHeight(height); - psConverter->setRightMargin(marginRight); - psConverter->setBottomMargin(marginBottom); - psConverter->setLeftMargin(marginLeft); - psConverter->setTopMargin(marginTop); - psConverter->setStrictMargins(strictMargins); + psConverter->setRightMargin(0); + psConverter->setBottomMargin(0); + psConverter->setLeftMargin(0); + psConverter->setTopMargin(0); + psConverter->setStrictMargins(false); psConverter->setForceRasterize(forceRasterize); psConverter->setTitle(pstitle); + userMutex()->lock(); if (psConverter->convert()) { userMutex()->unlock(); delete psConverter; - return printer.printFiles(QStringList(tempfilename), true); + int ret = Okular::FilePrinter::printFile( printer, tempfilename, + Okular::FilePrinter::SystemDeletesFiles, + Okular::FilePrinter::ApplicationSelectsPages, + document()->bookmarkedPageRange() ); + if ( ret >= 0 ) return true; } else { delete psConverter; -#else + userMutex()->unlock(); + return false; + } + +#else // Not HAVE_POPPLER_0_6 + userMutex()->lock(); - if (pdfdoc->print(tempfilename, pageList, 72, 72, 0, width, height)) + + if ( pdfdoc->print( tempfilename, pageList, 72, 72, 0, width, height ) ) { userMutex()->unlock(); - return printer.printFiles(QStringList(tempfilename), true); + tf.setAutoRemove( false ); + int ret = Okular::FilePrinter::printFile( printer, tempfilename, + Okular::FilePrinter::SystemDeletesFiles, + Okular::FilePrinter::ApplicationSelectsPages, + document()->bookmarkedPageRange() ); + if ( ret >= 0 ) return true; } else { -#endif userMutex()->unlock(); return false; } -*/ - return false; + +#endif // HAVE_POPPLER_0_6 + + tf.close(); + + return false; } QVariant PDFGenerator::metaData( const QString & key, const QVariant & option ) const @@ -1515,11 +1504,7 @@ void PDFGenerator::loadPdfSync( const QString & filePath, QVector QWidget* PDFGenerator::printConfigurationWidget() const { -#ifdef HAVE_POPPLER_0_6 - return new PDFOptionsPage(); -#else - return 0; -#endif + return pdfOptionsPage; } diff --git a/generators/poppler/generator_pdf.h b/generators/poppler/generator_pdf.h index ee0a24dc4..920cacdac 100644 --- a/generators/poppler/generator_pdf.h +++ b/generators/poppler/generator_pdf.h @@ -26,6 +26,7 @@ namespace Okular { class ObjectRect; } +class PDFOptionsPage; class PDFPixmapGeneratorThread; /** @@ -131,6 +132,8 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p mutable QList docEmbeddedFiles; QVector rectsGenerated; + + PDFOptionsPage * pdfOptionsPage; }; diff --git a/generators/spectre/generator_ghostview.cpp b/generators/spectre/generator_ghostview.cpp index 66808c94b..88f2c6a3e 100644 --- a/generators/spectre/generator_ghostview.cpp +++ b/generators/spectre/generator_ghostview.cpp @@ -19,9 +19,11 @@ #include #include #include +#include #include #include +#include #include "ui_gssettingswidget.h" #include "gssettings.h" @@ -37,6 +39,9 @@ GSGenerator::GSGenerator() : m_docInfo(0), m_request(0) { + setFeature( PrintPostscript ); + setFeature( PrintToFile ); + // ### TODO fill after the KDE 4.0 unfreeze KAboutData *about = new KAboutData( "okular_ghostview", @@ -75,22 +80,54 @@ void GSGenerator::addPages( KConfigDialog *dlg ) bool GSGenerator::print( QPrinter& printer ) { -/* This printing method unsupported in QPrinter, looking for alternative. + bool result = false; + // Create tempfile to write to KTemporaryFile tf; tf.setSuffix( ".ps" ); - if ( tf.open() ) + if ( !tf.open() ) + return false; + + // Get list of pages to print + QList pageList = Okular::FilePrinter::pageList( printer, + spectre_document_get_n_pages( m_internalDocument ), + document()->bookmarkedPageList() ); + + // Default to Postscript export, but if printing to PDF use that instead + SpectreExporterFormat exportFormat = SPECTRE_EXPORTER_FORMAT_PS; + if ( printer.outputFileName().right(3) == "pdf" ) { - bool result = false; - if ( internalDoc->savePages( tf.fileName(), printer.pageList() ) ) - { - result = printer.printFiles( QStringList( tf.fileName() ), true ); - } - tf.close(); - return result; + exportFormat = SPECTRE_EXPORTER_FORMAT_PDF; + tf.setSuffix(".pdf"); + } + + SpectreExporter *exporter = spectre_exporter_new( m_internalDocument, exportFormat ); + SpectreStatus exportStatus = spectre_exporter_begin( exporter, tf.fileName().toAscii() ); + + int i = 0; + while ( i < pageList.count() && exportStatus == SPECTRE_STATUS_SUCCESS ) + { + exportStatus = spectre_exporter_do_page( exporter, i ); + i++; } -*/ - return false; + + SpectreStatus endStatus = spectre_exporter_end( exporter ); + + spectre_exporter_free( exporter ); + + if ( exportStatus == SPECTRE_STATUS_SUCCESS && endStatus == SPECTRE_STATUS_SUCCESS ) + { + tf.setAutoRemove( false ); + int ret = Okular::FilePrinter::printFile( printer, tf.fileName(), + Okular::FilePrinter::SystemDeletesFiles, + Okular::FilePrinter::ApplicationSelectsPages, + document()->bookmarkedPageRange() ); + if ( ret >= 0 ) result = true; + } + + tf.close(); + + return result; } bool GSGenerator::loadDocument( const QString & fileName, QVector< Okular::Page * > & pagesVector ) diff --git a/generators/tiff/generator_tiff.cpp b/generators/tiff/generator_tiff.cpp index b942f0adf..01263b5a9 100644 --- a/generators/tiff/generator_tiff.cpp +++ b/generators/tiff/generator_tiff.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -50,6 +51,8 @@ TIFFGenerator::TIFFGenerator() d( new Private ), m_docInfo( 0 ) { setFeature( Threaded ); + setFeature( PrintNative ); + setFeature( PrintToFile ); KAboutData *about = new KAboutData( "okular_tiff", @@ -220,9 +223,12 @@ bool TIFFGenerator::print( QPrinter& printer ) QPainter p( &printer ); - for ( tdir_t i = 0; i < dirs; ++i ) + QList pageList = Okular::FilePrinter::pageList( printer, document()->pages(), + document()->bookmarkedPageList() ); + + for ( tdir_t i = 0; i < pageList.count(); ++i ) { - if ( !TIFFSetDirectory( d->tiff, i ) ) + if ( !TIFFSetDirectory( d->tiff, pageList[i] - 1 ) ) continue; if ( TIFFGetField( d->tiff, TIFFTAG_IMAGEWIDTH, &width ) != 1 || diff --git a/part.cpp b/part.cpp index 733fa99a1..dedb2cadc 100644 --- a/part.cpp +++ b/part.cpp @@ -79,6 +79,7 @@ #include "core/document.h" #include "core/generator.h" #include "core/page.h" +#include "core/fileprinter.h" K_PLUGIN_FACTORY( okularPartFactory, registerPlugin< Part >(); ) K_EXPORT_PLUGIN( okularPartFactory( okularAboutData( "okular", I18N_NOOP( "okular" ) ) ) ) @@ -742,7 +743,7 @@ bool Part::openFile() m_find->setEnabled( ok && canSearch ); m_findNext->setEnabled( ok && canSearch ); m_saveAs->setEnabled( ok ); - m_printPreview->setEnabled( ok ); + m_printPreview->setEnabled( ok && m_document->printingSupport() != Okular::Document::NoPrinting ); m_showProperties->setEnabled( ok ); bool hasEmbeddedFiles = ok && m_document->embeddedFiles() && m_document->embeddedFiles()->count() > 0; m_showEmbeddedFiles->setEnabled( hasEmbeddedFiles ); @@ -815,7 +816,7 @@ bool Part::openUrl(const KUrl &url) setWindowTitleFromDocument(); } - emit enablePrintAction(openOk); + emit enablePrintAction(openOk && m_document->printingSupport() != Okular::Document::NoPrinting); return openOk; } @@ -940,7 +941,7 @@ void Part::slotDoFileDirty() m_sidebar->setCurrentIndex( m_sidebar->currentIndex() ); } if (m_wasPresentationOpen) slotShowPresentation(); - emit enablePrintAction(true); + emit enablePrintAction(true && m_document->printingSupport() != Okular::Document::NoPrinting); } else { @@ -1295,38 +1296,33 @@ void Part::slotPrintPreview() { if (m_document->pages() == 0) return; - double width, height; - int landscape, portrait; QPrinter printer; - const Okular::Page *page; -// printer.setMinMax(1, m_document->pages()); -// printer.setPreviewOnly( true ); - - // if some pages are landscape and others are not the most common win as kprinter does - // not accept a per page setting - landscape = 0; - portrait = 0; - for (uint i = 0; i < m_document->pages(); i++) + // Native printing supports KPrintPreview, Postscript needs to use FilePrinterPreview + if ( m_document->printingSupport() == Okular::Document::NativePrinting ) { - page = m_document->page(i); - width = page->width(); - height = page->height(); - if (page->orientation() == 90 || page->orientation() == 270) qSwap(width, height); - if (width > height) landscape++; - else portrait++; + KPrintPreview previewdlg( &printer, widget() ); + setupPrint( printer ); + doPrint( printer ); + previewdlg.exec(); } - if (landscape > portrait) + else { - // printer.setOption("orientation-requested", "4"); - printer.setOrientation( QPrinter::Landscape ); + // Generate a temp filename for Print to File, then release the file so generator can write to it + KTemporaryFile tf; + tf.setAutoRemove( true ); + tf.setSuffix( ".ps" ); + tf.open(); + printer.setOutputFileName( tf.fileName() ); + tf.close(); + setupPrint( printer ); + doPrint( printer ); + if ( QFile::exists( printer.outputFileName() ) ) + { + Okular::FilePrinterPreview previewdlg( printer.outputFileName(), widget() ); + previewdlg.exec(); + } } - - KPrintPreview previewdlg( &printer, widget() ); - - doPrint(printer); - - previewdlg.exec(); } @@ -1495,21 +1491,61 @@ void Part::slotPrint() { if (m_document->pages() == 0) return; - double width, height; - int landscape, portrait; QPrinter printer; - const Okular::Page *page; + QPrintDialog *printDialog = 0; + QWidget *printConfigWidget = 0; + + // Must do certain QPrinter setup before creating QPrintDialog + setupPrint( printer ); + + // Create the Print Dialog with extra config widgets if required + if ( m_document->canConfigurePrinter() ) + { + printConfigWidget = m_document->printConfigurationWidget(); + } + if ( printConfigWidget ) + { + printDialog = KdePrint::createPrintDialog( &printer, QList() << printConfigWidget, widget() ); + } + else + { + printDialog = KdePrint::createPrintDialog( &printer, widget() ); + } + + if ( printDialog ) + { + + // Set the available Print Range + printDialog->setMinMax( 1, m_document->pages() ); + printDialog->setFromTo( 1, m_document->pages() ); + + // If the user has bookmarked pages for printing, then enable Selection + if ( !m_document->bookmarkedPageRange().isEmpty() ) + { + printDialog->addEnabledOption( QAbstractPrintDialog::PrintSelection ); + } -/* Disable as QPrinter does not support most of this page management stuff. - Besides no point sorting this out until we solve the main printFiles problem. - However leave basic printing in place as some formats still support it. + // If the Document type doesn't support print to both PS & PDF then disable the Print Dialog option + if ( printDialog->isOptionEnabled( QAbstractPrintDialog::PrintToFile ) && + !m_document->supportsPrintToFile() ) + { + printDialog->setEnabledOptions( printDialog->enabledOptions() ^ QAbstractPrintDialog::PrintToFile ); + } - printer.setPageSelection(KPrinter::ApplicationSide); - printer.setMinMax(1, m_document->pages()); - printer.setCurrentPage(m_document->currentPage()+1); -*/ + if ( printDialog->exec() ) + doPrint( printer ); - // if some pages are landscape and others are not the most common win as kprinter does + } +} + + +void Part::setupPrint( QPrinter &printer ) +{ + double width, height; + int landscape, portrait; + const Okular::Page *page; + + // if some pages are landscape and others are not the most common win as QPrinter does // not accept a per page setting landscape = 0; portrait = 0; @@ -1524,50 +1560,6 @@ void Part::slotPrint() } if (landscape > portrait) printer.setOrientation(QPrinter::Landscape); -/* - // range detecting - QString range; - uint pages = m_document->pages(); - int startId = -1; - int endId = -1; - - for ( uint i = 0; i < pages; ++i ) - { - if ( m_document->bookmarkManager()->isBookmarked( i ) ) - { - if ( startId < 0 ) - startId = i; - if ( endId < 0 ) - endId = startId; - else - ++endId; - } - else if ( startId >= 0 && endId >= 0 ) - { - if ( !range.isEmpty() ) - range += ','; - - if ( endId - startId > 0 ) - range += QString( "%1-%2" ).arg( startId + 1 ).arg( endId + 1 ); - else - range += QString::number( startId + 1 ); - startId = -1; - endId = -1; - } - } - if ( startId >= 0 && endId >= 0 ) - { - if ( !range.isEmpty() ) - range += ','; - - if ( endId - startId > 0 ) - range += QString( "%1-%2" ).arg( startId + 1 ).arg( endId + 1 ); - else - range += QString::number( startId + 1 ); - } - printer.setOption( "kde-range", range ); -*/ - // title QString title = m_document->metaData( "DocumentTitle" ).toString(); if ( title.isEmpty() ) @@ -1578,26 +1570,6 @@ void Part::slotPrint() { printer.setDocName( title ); } - - QPrintDialog *printDialog; - QWidget * w; - - if ( m_document->canConfigurePrinter() ) - { - w = m_document->printConfigurationWidget(); - } - - if ( w ) - { - printDialog = KdePrint::createPrintDialog( &printer, QList() << w, widget() ); - } - else - { - printDialog = KdePrint::createPrintDialog( &printer, widget() ); - } - - if ( printDialog->exec() ) - doPrint( printer ); } diff --git a/part.h b/part.h index e3434ca11..86604c06d 100644 --- a/part.h +++ b/part.h @@ -164,7 +164,8 @@ class Part : public KParts::ReadOnlyPart, public Okular::DocumentObserver, publi void psTransformEnded(int, QProcess::ExitStatus); private: - void doPrint( QPrinter& printer ); + void setupPrint( QPrinter &printer ); + void doPrint( QPrinter &printer ); bool handleCompressed( QString &destpath, const QString &path, const QString &compressedMimetype ); void rebuildBookmarkMenu( bool unplugActions = true ); void updateAboutBackendAction(); -- GitLab