File indexing completed on 2024-05-12 16:41:06

0001 /******************************************************************************
0002   Copyright (C) 2009-2011 by Holger Danielsson (holger.danielsson@versanet.de)
0003             (C) 2019 by Michel Ludwig (michel.ludwig@kdemail.net)
0004  ******************************************************************************/
0005 
0006 /***************************************************************************
0007  *                                                                         *
0008  *   This program is free software; you can redistribute it and/or modify  *
0009  *   it under the terms of the GNU General Public License as published by  *
0010  *   the Free Software Foundation; either version 2 of the License, or     *
0011  *   (at your option) any later version.                                   *
0012  *                                                                         *
0013  ***************************************************************************/
0014 
0015 
0016 #include "pdfdialog.h"
0017 
0018 #include <QCheckBox>
0019 #include <QDateTime>
0020 #include <QDialogButtonBox>
0021 #include <QFile>
0022 #include <QGridLayout>
0023 #include <QGroupBox>
0024 #include <QInputDialog>
0025 #include <QLabel>
0026 #include <QLayout>
0027 #include <QLineEdit>
0028 #include <QLocale>
0029 #include <QProcess>
0030 #include <QPushButton>
0031 #include <QRegExp>
0032 #include <QStandardPaths>
0033 #include <QStringList>
0034 #include <QTemporaryFile>
0035 #include <QTextStream>
0036 #include <QValidator>
0037 #include <QVBoxLayout>
0038 
0039 #include <KComboBox>
0040 #include <KConfigGroup>
0041 #include <KIconLoader>
0042 #include <KLocalizedString>
0043 #include <KMessageBox>
0044 #include <KProcess>
0045 #include <KUrlRequester>
0046 
0047 #include "errorhandler.h"
0048 #include "kileconfig.h"
0049 #include "kiledebug.h"
0050 
0051 
0052 namespace KileDialog
0053 {
0054 
0055 PdfDialog::PdfDialog(QWidget *parent,
0056                      const QString &texfilename,const QString &startdir,
0057                      const QString &latexextensions,
0058                      KileTool::Manager *manager,
0059                      KileErrorHandler *errorHandler, KileWidget::OutputView *output)
0060     : QDialog(parent)
0061     , m_startdir(startdir)
0062     , m_manager(manager)
0063     , m_errorHandler(errorHandler)
0064     , m_output(output)
0065     , m_tempdir(Q_NULLPTR)
0066     , m_proc(Q_NULLPTR)
0067     , m_rearrangeButton(new QPushButton)
0068     , m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Help|QDialogButtonBox::Close))
0069 {
0070     setWindowTitle(i18n("PDF Wizard"));
0071     setModal(true);
0072     QVBoxLayout *mainLayout = new QVBoxLayout;
0073     setLayout(mainLayout);
0074     m_rearrangeButton->setDefault(true);
0075 
0076     // determine if a pdffile already exists
0077     QString pdffilename;
0078     if(!texfilename.isEmpty()) {
0079         // working with a pdf document, so we try to determine the LaTeX source file
0080         QStringList extlist = latexextensions.split(' ');
0081         for (QStringList::Iterator it = extlist.begin(); it != extlist.end(); ++it) {
0082             if (texfilename.indexOf((*it), -(*it).length()) >= 0) {
0083                 pdffilename = texfilename.left(texfilename.length() - (*it).length()) + ".pdf";
0084                 if (!QFileInfo::exists(pdffilename))
0085                     pdffilename.clear();
0086                 break;
0087             }
0088         }
0089     }
0090 
0091     // prepare dialog
0092     QWidget *page = new QWidget(this);
0093     mainLayout->addWidget(page);
0094     m_PdfDialog.setupUi(page);
0095     page->setMinimumWidth(500);
0096     m_PdfDialog.m_pbPrinting->setIcon(QIcon::fromTheme("printer"));
0097     m_PdfDialog.m_pbAll->setIcon(QIcon::fromTheme("list-add"));
0098     m_PdfDialog.m_pbBackgroundColor->setColor(QColor(255, 255, 224));
0099 
0100     // insert KileWidget::CategoryComboBox
0101     m_cbTask = new KileWidget::CategoryComboBox(m_PdfDialog.m_gbParameter);
0102     QGridLayout *paramLayout = static_cast<QGridLayout*>(m_PdfDialog.m_gbParameter->layout());
0103     paramLayout->addWidget(m_cbTask, 4, 1);
0104 
0105     // setup filenames
0106     const QStringList pdfMimeType = {QStringLiteral("application/pdf")};
0107     m_PdfDialog.m_edInfile->setMimeTypeFilters(pdfMimeType);
0108     m_PdfDialog.m_edInfile->lineEdit()->setText(pdffilename);
0109     m_PdfDialog.m_edOutfile->setMimeTypeFilters(pdfMimeType);
0110     m_PdfDialog.m_edOutfile->setMode(KFile::File | KFile::LocalOnly );
0111     m_PdfDialog.m_edOutfile->lineEdit()->setText( getOutfileName(pdffilename) );
0112 
0113     //max password length for pdf files
0114     m_PdfDialog.m_edPassword->setMaxLength(32);
0115 
0116     // set an user button to execute the task and icon for help button
0117     m_rearrangeButton->setText(i18n("Re&arrange"));
0118     m_rearrangeButton->setIcon(QIcon::fromTheme("system-run"));
0119     m_PdfDialog.m_lbParameterIcon->setPixmap(QIcon::fromTheme("help-about").pixmap(KIconLoader::SizeSmallMedium));
0120 
0121     // init important variables
0122     m_numpages = 0;
0123     m_encrypted = false;
0124     m_pdftk = false;
0125     m_pdfpages = false;
0126     m_scriptrunning = false;
0127     m_pagesize = QSize(0,0);
0128 
0129     // setup tasks
0130     m_tasklist << i18n("1 Page + Empty Page --> 2up")           // 0   PDF_PAGE_EMPTY
0131                << i18n("1 Page + Duplicate --> 2up")            // 1   PDF_PAGE_DUPLICATE
0132                << i18n("2 Pages --> 2up")                       // 2   PDF_2UP
0133                << i18n("2 Pages (landscape) --> 2up")           // 3   PDF_2UP_LANDSCAPE
0134                << i18n("4 Pages --> 4up")                       // 4   PDF_4UP
0135                << i18n("4 Pages (landscape) --> 4up")           // 5   PDF_4UP_LANDSCAPE
0136                << i18n("Select Even Pages")                     // 6   PDF_EVEN
0137                << i18n("Select Odd Pages")                      // 7   PDF_ODD
0138                << i18n("Select Even Pages (reverse order)")     // 8   PDF_EVEN_REV
0139                << i18n("Select Odd Pages (reverse order)")      // 9   PDF_ODD_REV
0140                << i18n("Reverse All Pages")                     // 10  PDF_REVERSE
0141                << i18n("Decrypt")                               // 11  PDF_DECRYPT
0142                << i18n("Select Pages")                          // 12  PDF_SELECT
0143                << i18n("Delete Pages")                          // 13  PDF_DELETE
0144                << i18n("Apply a background watermark")          // 14  PDF_PDFTK_BACKGROUND
0145                << i18n("Apply a background color")              // 15  PDF_PDFTK_BGCOLOR
0146                << i18n("Apply a foreground stamp")              // 16  PDF_PDFTK_STAMP
0147                << i18n("pdftk: Choose Parameter")               // 17  PDF_PDFTK_FREE
0148                << i18n("pdfpages: Choose Parameter")            // 18  PDF_PDFPAGES_FREE
0149                ;
0150 
0151     // set data for properties: key/widget
0152     m_pdfInfoKeys << "Title" << "Subject" << "Author" << "Creator" << "Producer" << "Keywords";
0153 
0154     m_pdfInfoWidget["Title"] = m_PdfDialog.m_leTitle;
0155     m_pdfInfoWidget["Subject"] = m_PdfDialog.m_leSubject;
0156     m_pdfInfoWidget["Keywords"] = m_PdfDialog.m_leKeywords;
0157     m_pdfInfoWidget["Author"] = m_PdfDialog.m_leAuthor;
0158     m_pdfInfoWidget["Creator"] = m_PdfDialog.m_leCreator;
0159     m_pdfInfoWidget["Producer"] = m_PdfDialog.m_leProducer;
0160 
0161     // set data for  permissions: key/widget
0162     m_pdfPermissionKeys    << AllowModify << AllowCopy << AllowPrint
0163                            << AllowNotes  << AllowFillForms;
0164 
0165     m_pdfPermissionWidgets << m_PdfDialog.m_cbModify << m_PdfDialog.m_cbCopy << m_PdfDialog.m_cbPrinting
0166                            << m_PdfDialog.m_cbAnnotations << m_PdfDialog.m_cbFormFeeds;
0167 
0168     m_pdfPermissionPdftk   << "ModifyContents" << "CopyContents" << "Printing"
0169                            << "ModifyAnnotations" << "FillIn";
0170 
0171     // default permissions
0172     m_pdfPermissionState << false << false  << false  << false  << false;
0173 
0174     // check for libpoppler pdf library
0175 #if LIBPOPPLER_AVAILABLE
0176     m_poppler = true;
0177     KILE_DEBUG_MAIN << "working with libpoppler pdf library";
0178 #else
0179     m_poppler = false;
0180     KILE_DEBUG_MAIN << "working without libpoppler pdf library";
0181     m_PdfDialog.tabWidget->removeTab(2);
0182     m_PdfDialog.tabWidget->removeTab(1);
0183 #endif
0184 
0185     // init Dialog
0186     m_PdfDialog.m_lbParameterInfo->setTextFormat(Qt::RichText);
0187     m_PdfDialog.m_cbOverwrite->setChecked(false);
0188     updateDialog();
0189 
0190     connect(this, &PdfDialog::output, m_output, &KileWidget::OutputView::receive);
0191     connect(m_PdfDialog.m_edInfile->lineEdit(), &QLineEdit::textChanged, this, &PdfDialog::slotInputfileChanged);
0192 
0193 #if LIBPOPPLER_AVAILABLE
0194     connect(m_PdfDialog.tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotTabwidgetChanged(int)));
0195     connect(m_PdfDialog.m_pbPrinting, SIGNAL(clicked()), this, SLOT(slotPrintingClicked()));
0196     connect(m_PdfDialog.m_pbAll, SIGNAL(clicked()), this, SLOT(slotAllClicked()));
0197 #endif
0198 
0199     m_buttonBox->addButton(m_rearrangeButton, QDialogButtonBox::ActionRole);
0200     connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0201     connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0202     connect(m_buttonBox, &QDialogButtonBox::helpRequested, this, &PdfDialog::slotShowHelp);
0203     connect(m_rearrangeButton, &QPushButton::clicked, this, &PdfDialog::slotExecute);
0204     mainLayout->addWidget(m_buttonBox);
0205 
0206     // find available utilities for this dialog
0207     executeScript("kpsewhich pdfpages.sty", QString(), PDF_SCRIPTMODE_TOOLS);
0208 }
0209 
0210 PdfDialog::~PdfDialog()
0211 {
0212     if (m_cbTask->currentIndex() != -1) {
0213         KileConfig::setPdfWizardLastTask(m_cbTask->currentIndex());
0214     }
0215     delete m_tempdir;
0216     delete m_proc;
0217 }
0218 
0219 void PdfDialog::initUtilities()
0220 {
0221     // find pdfpages.sty?
0222     m_pdfpages = m_outputtext.contains("pdfpages.sty");
0223 
0224     // additionally look for pdftk
0225     m_pdftk = !QStandardPaths::findExecutable("pdftk").isEmpty();
0226 
0227 //m_pdfpages = false;            // <----------- only for testing  HACK
0228 //m_pdftk = false;               // <----------- only for testing  HACK
0229 
0230     KILE_DEBUG_MAIN << "Looking for pdf tools: pdftk=" << m_pdftk << " pdfpages.sty=" << m_pdfpages;
0231 
0232 #if !LIBPOPPLER_AVAILABLE
0233     m_imagemagick = KileConfig::imagemagick();
0234 
0235     // we can't use libpoppler pdf library and need to find another method to determine the number of pdf pages
0236     // Kile will use three options before giving up
0237     if ( m_pdftk )
0238         m_numpagesMode = PDF_SCRIPTMODE_NUMPAGES_PDFTK;
0239     else if ( m_imagemagick )
0240         m_numpagesMode = PDF_SCRIPTMODE_NUMPAGES_IMAGEMAGICK;
0241     else
0242         m_numpagesMode = PDF_SCRIPTMODE_NUMPAGES_GHOSTSCRIPT;
0243 #endif
0244 
0245     // no pdftk, so properties and permissions are readonly
0246     if ( !m_pdftk ) {
0247         // set readonly properties
0248         for (QStringList::const_iterator it = m_pdfInfoKeys.constBegin(); it != m_pdfInfoKeys.constEnd(); ++it) {
0249             m_pdfInfoWidget[*it]->setReadOnly(true);
0250         }
0251 #if LIBPOPPLER_AVAILABLE
0252         // connect permission widgets
0253         for (int i=0; i<m_pdfPermissionKeys.size(); ++i) {
0254             connect(m_pdfPermissionWidgets.at(i), SIGNAL(clicked(bool)), this, SLOT(slotPermissionClicked(bool)));
0255         }
0256 #endif
0257     }
0258 
0259     // if we found at least one utility, we can enable some connections
0260     if ( m_pdftk || m_pdfpages) {
0261         connect(m_PdfDialog.m_edOutfile->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(slotOutputfileChanged(QString)));
0262         connect(m_PdfDialog.m_cbOverwrite, SIGNAL(stateChanged(int)), this, SLOT(slotOverwriteChanged(int)));
0263         connect(m_cbTask, SIGNAL(activated(int)), this, SLOT(slotTaskChanged(int)));
0264     }
0265 
0266     // setup dialog
0267     slotInputfileChanged(m_PdfDialog.m_edInfile->lineEdit()->text());
0268 }
0269 
0270 // read properties and permissions from the PDF document
0271 void PdfDialog::pdfParser(const QString &filename)
0272 {
0273 #if LIBPOPPLER_AVAILABLE
0274     Poppler::Document *doc = Poppler::Document::load(filename);
0275     if ( !doc || doc->isLocked() ) {
0276         KILE_DEBUG_MAIN << "Error: could not open pdf document '" << filename << "'";
0277         return;
0278     }
0279     KILE_DEBUG_MAIN << "Parse pdf document: " << filename;
0280 
0281     // read encryption
0282     m_encrypted = doc->isEncrypted();
0283     m_PdfDialog.m_lbEncryption->setText( (m_encrypted) ? i18n("yes") : i18n("no") );
0284 
0285     // read properties
0286     for (QStringList::const_iterator it = m_pdfInfoKeys.constBegin(); it != m_pdfInfoKeys.constEnd(); ++it) {
0287         QString value = doc->info(*it);
0288         m_pdfInfo[*it] = value;
0289         m_pdfInfoWidget[*it]->setText(value);
0290     }
0291 
0292     // read creation date and modification date
0293     m_PdfDialog.m_lbCreationDate->setText(QLocale().toString(doc->date("CreationDate")));
0294     m_PdfDialog.m_lbModDate->setText(QLocale().toString(doc->date("ModDate")));
0295 
0296     // read PDF version
0297     Poppler::Document::PdfVersion pdfVersion = doc->getPdfVersion();
0298     m_PdfDialog.m_lbFormat->setText( QString("PDF version %1.%2").arg(pdfVersion.major).arg(pdfVersion.minor) );
0299 
0300     // read permissions
0301     for (int i=0; i<m_pdfPermissionKeys.size(); ++i) {
0302         bool value = isAllowed( doc, (PDF_Permission)m_pdfPermissionKeys.at(i) );
0303         m_pdfPermissionWidgets.at(i)->setChecked(value);
0304 
0305         if ( !m_pdftk ) {
0306             m_pdfPermissionState[i] = value;
0307         }
0308     }
0309 
0310     // determine and set number of pages
0311     setNumberOfPages( doc->numPages() );
0312 
0313     // look if all pages have the same size
0314     m_pagesize = allPagesSize(doc);
0315 
0316     delete doc;
0317 #else
0318     /* libpoppler pdf library is not available:
0319      * - we use a brute force method to determine, if this file is encrypted
0320      * - then we try to determine the number of pages with
0321      *   - pdftk (always first choice, if installed)
0322      *   - imagemagick (second choice)
0323      *   - gs (third and last choice)
0324      * - if the pdf file is encrypted, pdftk will ask for a password
0325      */
0326 
0327     // look if the pdf file is encrypted (brute force)
0328     m_encrypted = readEncryption(filename);
0329     KILE_DEBUG_MAIN << "PDF encryption: " << m_encrypted;
0330 
0331     // determine the number of pages of the pdf file
0332     determineNumberOfPages(filename,m_encrypted);
0333     KILE_DEBUG_MAIN << "PDF number of pages: " << m_numpages;
0334 
0335     // clear pagesize
0336     m_pagesize = QSize(0,0);
0337 #endif
0338 
0339 
0340 }
0341 
0342 #if LIBPOPPLER_AVAILABLE
0343 bool PdfDialog::isAllowed(Poppler::Document *doc, PDF_Permission permission) const
0344 {
0345     bool b = true;
0346     switch ( permission )
0347     {
0348     case AllowModify:
0349         b = doc->okToChange();
0350         break;
0351     case AllowCopy:
0352         b = doc->okToCopy();
0353         break;
0354     case AllowPrint:
0355         b = doc->okToPrint();
0356         break;
0357     case AllowNotes:
0358         b = doc->okToAddNotes();
0359         break;
0360     case AllowFillForms:
0361         b = doc->okToFillForm();
0362         break;
0363     default:
0364         ;
0365     }
0366     return b;
0367 }
0368 
0369 QSize PdfDialog::allPagesSize(Poppler::Document *doc)
0370 {
0371     QSize commonsize = QSize(0,0);
0372 
0373     // Access all pages of the PDF file (m_numpages is known)
0374     for ( int i=0; i<m_numpages; ++i ) {
0375         Poppler::Page *pdfpage = doc->page(i);
0376         if ( pdfpage == 0 ) {
0377             KILE_DEBUG_MAIN << "Cannot parse all pages of the PDF file";
0378             delete pdfpage;
0379             return QSize(0,0);
0380         }
0381 
0382         if ( i == 0 ) {
0383             commonsize = pdfpage->pageSize();
0384         } else if ( commonsize != pdfpage->pageSize() ) {
0385             delete pdfpage;
0386             return QSize(0,0);
0387         }
0388         // documentation says: after the usage, the page must be deleted
0389         delete pdfpage;
0390     }
0391 
0392     return commonsize;
0393 }
0394 #endif
0395 
0396 void PdfDialog::setNumberOfPages(int numpages)
0397 {
0398     m_numpages = numpages;
0399     if (m_numpages > 0) {
0400         // show all, if the number of pages is known
0401         m_PdfDialog.tabWidget->widget(0)->setEnabled(true);
0402 
0403         if ( m_encrypted )
0404             m_PdfDialog.m_lbPages->setText(i18nc("%1 is the number of pages", "%1 (encrypted)", QString::number(m_numpages)));
0405         else {
0406             m_PdfDialog.m_lbPages->setText(QString::number(m_numpages));
0407         }
0408     }
0409     else {
0410         // hide all, if the number of pages can't be determined
0411         m_PdfDialog.tabWidget->widget(0)->setEnabled(false);
0412         m_PdfDialog.m_lbPages->setText(i18n("Error: unknown number of pages"));
0413     }
0414 }
0415 
0416 #if !LIBPOPPLER_AVAILABLE
0417 void PdfDialog::determineNumberOfPages(const QString &filename, bool askForPassword)
0418 {
0419     // determine the number of pages of the pdf file (delegate this task)
0420     QString command;
0421     QString passwordparam;
0422     int scriptmode = m_numpagesMode;
0423 
0424     if ( scriptmode==PDF_SCRIPTMODE_NUMPAGES_PDFTK && askForPassword ) {
0425         QString password = QInputDialog::getText(this, i18n("PDFTK-Password"),
0426                            i18n("This PDF file is encrypted and 'pdftk' cannot open it.\n"
0427                                 "Please enter the password for this PDF file\n or leave it blank to try another method: "),
0428                            QLineEdit::Normal, QString()).trimmed();
0429         if(!password.isEmpty()) {
0430             passwordparam = " input_pw " + password;
0431         }
0432         else {
0433             scriptmode = ( m_imagemagick ) ? PDF_SCRIPTMODE_NUMPAGES_IMAGEMAGICK : PDF_SCRIPTMODE_NUMPAGES_GHOSTSCRIPT;
0434         }
0435     }
0436 
0437     // now take the original or changed mode
0438     if ( scriptmode == PDF_SCRIPTMODE_NUMPAGES_PDFTK ) {
0439         command = "pdftk \"" + filename + "\"" + passwordparam + " dump_data | grep NumberOfPages";
0440     }
0441     else if ( scriptmode == PDF_SCRIPTMODE_NUMPAGES_IMAGEMAGICK ) {
0442         command = "identify -format \"%n\" \"" + filename + "\"";
0443     }
0444     else {
0445         command = "gs -q -c \"(" + filename + ") (r) file runpdfbegin pdfpagecount = quit\"";
0446     }
0447 
0448     // run Process
0449     KILE_DEBUG_MAIN << "execute for NumberOfPages: " << command;
0450     executeScript(command, m_tempdir->path(), scriptmode);
0451 }
0452 
0453 void PdfDialog::readNumberOfPages(int scriptmode, const QString &output)
0454 {
0455     int numpages = 0;
0456 
0457     bool ok;
0458     if ( scriptmode == PDF_SCRIPTMODE_NUMPAGES_PDFTK ) {
0459         KILE_DEBUG_MAIN << "pdftk output for NumberOfPages: " << output;
0460         if ( output.contains("OWNER PASSWORD REQUIRED") ) {
0461             determineNumberOfPages(m_PdfDialog.m_edInfile->lineEdit()->text().trimmed(),true);
0462             return;
0463         } else {
0464             QRegExp re("\\d+");
0465             if ( re.indexIn(output) >= 0) {
0466                 numpages = re.cap(0).toInt(&ok);
0467             }
0468         }
0469 
0470     }
0471     else {
0472         QString s = output;
0473         numpages = s.remove('\n').toInt(&ok);
0474     }
0475 
0476     setNumberOfPages(numpages);
0477 }
0478 
0479 bool PdfDialog::readEncryption(const QString &filename)
0480 {
0481     QFile file(filename);
0482     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
0483         return false;
0484     }
0485 
0486     KILE_DEBUG_MAIN << "search for encryption ";
0487     QRegExp re("/Encrypt(\\W|\\s|$)");
0488     QTextStream in(&file);
0489     QString line = in.readLine();
0490     while ( !line.isNull() ) {
0491         if ( re.indexIn(line) >= 0 ) {
0492             KILE_DEBUG_MAIN << "pdf file is encrypted !!!";
0493             return  true;
0494         }
0495         line = in.readLine();
0496     }
0497     return false;
0498 }
0499 #endif
0500 
0501 void PdfDialog::clearDocumentInfo()
0502 {
0503     m_numpages = 0;
0504     m_encrypted = false;
0505     m_PdfDialog.m_lbPassword->setEnabled(false);
0506     m_PdfDialog.m_edPassword->setEnabled(false);
0507     m_PdfDialog.m_edPassword->clear();
0508 
0509     for (QStringList::const_iterator it = m_pdfInfoKeys.constBegin(); it != m_pdfInfoKeys.constEnd(); ++it) {
0510         m_pdfInfoWidget[*it]->clear();
0511     }
0512 
0513     m_PdfDialog.m_lbCreationDate->clear();
0514     m_PdfDialog.m_lbModDate->clear();
0515 
0516     for (int i=0; i<m_pdfPermissionKeys.size(); ++i) {
0517         m_pdfPermissionWidgets.at(i)->setChecked(false);
0518     }
0519 
0520     m_PdfDialog.m_lbPages->clear();
0521     m_PdfDialog.m_lbFormat->clear();
0522     m_PdfDialog.m_lbEncryption->clear();
0523 }
0524 
0525 void PdfDialog::updateOwnerPassword(bool infile_exists)
0526 {
0527     int tabindex = m_PdfDialog.tabWidget->currentIndex();
0528     bool state = ( infile_exists && (m_encrypted || (!m_encrypted && tabindex==2)) ) ? m_pdftk : false;
0529     m_PdfDialog.m_lbPassword->setEnabled(state);
0530     m_PdfDialog.m_edPassword->setEnabled(state);
0531 }
0532 
0533 // update dialog widgets
0534 void PdfDialog::updateDialog()
0535 {
0536     QString infile = m_PdfDialog.m_edInfile->lineEdit()->text().trimmed();
0537     bool infile_exists = QFile(infile).exists();
0538 
0539     updateOwnerPassword(infile_exists);
0540     updateTasks();
0541     updateToolsInfo();
0542 
0543     bool pstate = ( m_encrypted ) ? infile_exists && m_pdftk : infile_exists && (m_pdftk || m_pdfpages);
0544     m_PdfDialog.m_gbParameter->setEnabled(pstate);
0545 
0546     m_PdfDialog.m_gbProperties->setEnabled(infile_exists);
0547     m_PdfDialog.m_gbPermissions->setEnabled(infile_exists);
0548     m_PdfDialog.m_lbPrinting->setEnabled(infile_exists);
0549     m_PdfDialog.m_pbPrinting->setEnabled(infile_exists);
0550     m_PdfDialog.m_lbAll->setEnabled(infile_exists);
0551     m_PdfDialog.m_pbAll->setEnabled(infile_exists);
0552 
0553     // and exec button
0554     QString outfile = m_PdfDialog.m_edOutfile->lineEdit()->text().trimmed();
0555     bool destination = m_PdfDialog.m_cbOverwrite->isChecked() || m_PdfDialog.m_cbView->isChecked();
0556 
0557     bool state = ( infile_exists && (destination || (!destination && !outfile.isEmpty())) );
0558     if ( m_PdfDialog.tabWidget->currentIndex() == 0 ) {
0559         state = state && (m_pdfpages || m_pdftk);
0560     }
0561     else {
0562         state = state && m_pdftk;
0563     }
0564     m_rearrangeButton->setEnabled(state&&!m_scriptrunning);
0565 }
0566 
0567 // update tools information
0568 void PdfDialog::updateToolsInfo()
0569 {
0570     QString info;
0571     QString newline = "<br>";
0572     QString password = i18n("A password is necessary to set or change the current settings.");
0573 
0574     int tabindex = m_PdfDialog.tabWidget->currentIndex();
0575     if (tabindex == 2 ) {
0576         info = ( m_pdftk ) ? i18n("The permissions of this document can be changed with <i>pdftk</i>.") + newline + password
0577                : i18n("<i>pdftk</i> is not available, so no permission can be changed.");
0578     }
0579     else if ( tabindex == 1 ) {
0580         if ( ! m_pdftk ) {
0581             info = i18n("<i>pdftk</i> is not available, so no property can be changed.");
0582         }
0583         else {
0584             info = i18n("The properties of this document can be changed with <i>pdftk</i>.");
0585             if ( m_encrypted ) {
0586                 info += newline + password;
0587             }
0588         }
0589     }
0590     else { // if ( tabindex == 0 )
0591         if ( m_encrypted ) {
0592             info = ( m_pdftk ) ? i18n("This input file is encrypted, so only <i>pdftk</i> works.") + newline
0593                    + i18n("A password is necessary to rearrange pages.")
0594                    : i18n("This input file is encrypted, but <i>pdftk</i> is not installed.");
0595         }
0596         else {
0597             if ( m_pdftk ) { // not encrypted and pdftk
0598                 info = ( m_pdfpages ) ? i18n("This wizard will use <i>pdftk</i> and the LaTeX package <i>pdfpages</i>.")
0599                        : i18n("This wizard will only use <i>pdftk</i> (<i>pdfpages.sty</i> is not installed).");
0600             }
0601             else {           // not encrypted and not pdftk
0602                 info = ( m_pdfpages ) ? i18n("This wizard will only use the LaTeX package <i>pdfpages</i> (<i>pdftk</i> was not found).")
0603                        : i18n("This wizard can't work, because no tool was found (see help section).");
0604             }
0605         }
0606     }
0607 
0608     QString popplerinfo = (m_poppler ) ? QString() : newline + i18n("<i>(Compiled without libpoppler pdf library. Not all tasks are available.)</i>");
0609     info += popplerinfo;
0610 
0611     // set info text
0612     m_PdfDialog.m_lbParameterInfo->setText(info);
0613 }
0614 
0615 // it is important to calculate the task index from the combobox index,
0616 // as not all tasks are available, when an utility was not found
0617 void PdfDialog::updateTasks()
0618 {
0619     // according to QT 4.4 docu the index of QComboBox might change if adding or removing items
0620     // but because we populate the QComboBox before we start the dialog, we can use the index here
0621     int lastindex = m_cbTask->currentIndex();
0622     QString lasttext = m_cbTask->currentText();
0623 
0624     int group = 0;
0625     m_cbTask->clear();
0626     if (m_pdfpages && !m_encrypted) {                               // task index
0627         m_cbTask->addItem( m_tasklist[PDF_PAGE_EMPTY] );             // 0   PDF_PAGE_EMPTY
0628         m_cbTask->addItem( m_tasklist[PDF_PAGE_DUPLICATE] );         // 1   PDF_PAGE_DUPLICATE
0629         m_cbTask->addItem( m_tasklist[PDF_2UP] );                    // 2   PDF_2UP
0630         m_cbTask->addItem( m_tasklist[PDF_2UP_LANDSCAPE] );          // 3   PDF_2UP_LANDSCAPE
0631         m_cbTask->addItem( m_tasklist[PDF_4UP] );                    // 4   PDF_4UP
0632         m_cbTask->addItem( m_tasklist[PDF_4UP_LANDSCAPE] );          // 5   PDF_4UP_LANDSCAPE
0633         group = 1;
0634     }
0635 
0636     if ( (m_pdfpages && !m_encrypted) || m_pdftk ) {
0637         if ( group > 0 ) {
0638             m_cbTask->addCategoryItem("");
0639         }
0640         m_cbTask->addItem( m_tasklist[PDF_EVEN] );                   // 6   PDF_EVEN
0641         m_cbTask->addItem( m_tasklist[PDF_ODD] );                    // 7   PDF_ODD
0642         m_cbTask->addItem( m_tasklist[PDF_EVEN_REV] );               // 8   PDF_EVEN_REV
0643         m_cbTask->addItem( m_tasklist[PDF_ODD_REV] );                // 9   PDF_ODD_REV
0644         m_cbTask->addItem( m_tasklist[PDF_REVERSE] );                // 10  PDF_REVERSE
0645         if (m_encrypted) {
0646             m_cbTask->addItem( m_tasklist[PDF_DECRYPT] );             // 11  PDF_DECRYPT
0647         }
0648         m_cbTask->addCategoryItem("");
0649         m_cbTask->addItem( m_tasklist[PDF_SELECT] );                 // 12  PDF_SELECT
0650         m_cbTask->addItem( m_tasklist[PDF_DELETE] );                 // 13  PDF_DELETE
0651         group = 2;
0652     }
0653 
0654     if (m_pdftk) {
0655         m_cbTask->addCategoryItem("");
0656         m_cbTask->addItem( m_tasklist[PDF_PDFTK_BACKGROUND] );       // 14  PDF_PDFTK_BACKGROUND
0657         if ( ! m_pagesize.isNull() ) {
0658             m_cbTask->addItem( m_tasklist[PDF_PDFTK_BGCOLOR] );       // 15  PDF_PDFTK_BGCOLOR
0659         }
0660         m_cbTask->addItem( m_tasklist[PDF_PDFTK_STAMP] );            // 16  PDF_PDFTK_STAMP
0661         m_cbTask->addCategoryItem("");
0662         m_cbTask->addItem( m_tasklist[PDF_PDFTK_FREE] );             // 17  PDF_PDFTK_FREE
0663         group = 3;
0664     }
0665 
0666     if (m_pdfpages && !m_encrypted) {
0667         if ( group < 3 ) {
0668             m_cbTask->addCategoryItem("");
0669         }
0670         m_cbTask->addItem( m_tasklist[PDF_PDFPAGES_FREE] );          // 17  PDF_PDFPAGES_FREE
0671     }
0672 
0673     // choose one common task (need to calculate the combobox index)
0674     int index = m_cbTask->findText(lasttext);
0675     if ( lastindex==-1 || index==-1 ) {
0676         int lastTask = KileConfig::pdfWizardLastTask();
0677         int task = ( lastTask < m_cbTask->count() ) ? lastTask : PDF_SELECT;
0678         index = m_cbTask->findText(m_tasklist[task]);
0679         if ( index == -1 ) {
0680             index = 0;
0681         }
0682     }
0683 
0684     m_cbTask->setCurrentIndex(index);
0685     slotTaskChanged(index);
0686 
0687     setFocusProxy(m_PdfDialog.m_edInfile);
0688     m_PdfDialog.m_edInfile->setFocus();
0689 }
0690 
0691 QString PdfDialog::getOutfileName(const QString &infile)
0692 {
0693     return ( infile.isEmpty() ) ? QString() : infile.left(infile.length()-4) + "-out" + ".pdf";
0694 }
0695 
0696 // calculate task index from comboxbox index
0697 int PdfDialog::taskIndex()
0698 {
0699     return m_tasklist.indexOf( m_cbTask->currentText() );
0700 }
0701 
0702 void PdfDialog::setPermissions(bool print, bool other)
0703 {
0704     for (int i = 0; i<m_pdfPermissionKeys.size(); ++i) {
0705         QCheckBox *box = m_pdfPermissionWidgets.at(i);
0706         bool state = ( box == m_PdfDialog.m_cbPrinting ) ? print : other;
0707         box->setChecked(state);
0708     }
0709 }
0710 
0711 // read permissions
0712 QString PdfDialog::readPermissions()
0713 {
0714     QString permissions;
0715     for (int i = 0; i < m_pdfPermissionKeys.size(); ++i) {
0716         if ( m_pdfPermissionWidgets.at(i)->isChecked() ) {
0717             permissions += m_pdfPermissionPdftk.at(i) + ' ';
0718         }
0719     }
0720     return permissions;
0721 }
0722 
0723 //-------------------- slots --------------------
0724 
0725 void PdfDialog::slotTabwidgetChanged(int index)
0726 {
0727     m_rearrangeButton->setText(index == 0 ? i18n("Re&arrange") : i18n("&Update"));
0728     updateDialog();
0729 }
0730 
0731 void PdfDialog::slotPrintingClicked()
0732 {
0733     if ( m_pdftk ) {
0734         setPermissions(true, false);
0735     }
0736 }
0737 
0738 void PdfDialog::slotAllClicked()
0739 {
0740     if ( m_pdftk ) {
0741         setPermissions(true, true);
0742     }
0743 }
0744 
0745 void PdfDialog::slotPermissionClicked(bool)
0746 {
0747     for (int i = 0; i < m_pdfPermissionKeys.size(); ++i) {
0748         QCheckBox *box = m_pdfPermissionWidgets.at(i);
0749         if ( box->isChecked() != m_pdfPermissionState[i] ) {
0750             box->setChecked( m_pdfPermissionState[i] );
0751         }
0752     }
0753 }
0754 
0755 void PdfDialog::slotInputfileChanged(const QString &text)
0756 {
0757     clearDocumentInfo();
0758     if ( QFile(text).exists() ) {
0759         m_PdfDialog.m_edOutfile->lineEdit()->setText( getOutfileName(text) );
0760         pdfParser(text);
0761     }
0762 
0763     updateDialog();
0764 }
0765 
0766 void PdfDialog::slotOverwriteChanged(int state)
0767 {
0768     bool checked = (state!=Qt::Checked);
0769     m_PdfDialog.m_lbOutfile->setEnabled(checked);
0770     m_PdfDialog.m_edOutfile->setEnabled(checked);
0771 
0772     updateDialog();
0773 }
0774 
0775 void PdfDialog::slotOutputfileChanged(const QString &)
0776 {
0777     updateDialog();
0778 }
0779 
0780 void PdfDialog::slotTaskChanged(int)
0781 {
0782     if ( m_PdfDialog.tabWidget->currentIndex() > 0 ) {
0783         return;
0784     }
0785 
0786     int taskindex = taskIndex();
0787     if ( isParameterTask(taskindex) ) {
0788         QString s,labeltext;
0789         if ( taskindex==PDF_SELECT || taskindex==PDF_DELETE ) {
0790             labeltext = i18n("Pages:");
0791             s = i18n("Comma separated page list: 1,4-7,9");
0792             QRegExp re("((\\d+(-\\d+)?),)*\\d+(-\\d+)?");
0793             m_PdfDialog.m_edParameter->setValidator(new QRegExpValidator(re, m_PdfDialog.m_edParameter));
0794         }
0795         else if (taskindex==PDF_PDFTK_FREE) {
0796             labeltext = i18n("Parameter:");
0797             s = i18n("All options for 'pdftk'");
0798             m_PdfDialog.m_edParameter->setValidator(0);
0799         }
0800         else { //if (taskindex==PDF_PDFPAGES_FREE) {
0801             labeltext = i18n("Parameter:");
0802             s = i18n("All options for 'pdfpages'");
0803             m_PdfDialog.m_edParameter->setValidator(0);
0804         }
0805         m_PdfDialog.m_lbParamInfo->setText(" (" + s + ')');
0806 
0807         m_PdfDialog.m_lbParameter->setText(labeltext);
0808         m_PdfDialog.m_lbParameter->show();
0809         m_PdfDialog.m_edParameter->clear();
0810         m_PdfDialog.m_edParameter->show();
0811         m_PdfDialog.m_lbParamInfo->show();
0812     }
0813     else {
0814         m_PdfDialog.m_lbParameter->hide();
0815         m_PdfDialog.m_edParameter->hide();
0816         m_PdfDialog.m_lbParamInfo->hide();
0817     }
0818 
0819     if ( isOverlayTask(taskindex) ) {
0820         m_PdfDialog.m_lbStamp->show();
0821         m_PdfDialog.m_edStamp->show();
0822 
0823         if ( taskindex == PDF_PDFTK_BACKGROUND ) {
0824             m_PdfDialog.m_edStamp->setWhatsThis(i18n("Applies a PDF watermark to the background of a single input PDF. "
0825                                                 "Pdftk uses only the first page from the background PDF and applies it to every page of the input PDF. "
0826                                                 "This page is scaled and rotated as needed to fit the input page.") );
0827         }
0828         else if ( taskindex == PDF_PDFTK_STAMP ) {
0829             m_PdfDialog.m_edStamp->setWhatsThis( i18n("Applies a foreground stamp on top of the input PDF document's pages. "
0830                                                  "Pdftk uses only the first page from the stamp PDF and applies it to every page of the input PDF. "
0831                                                  "This page is scaled and rotated as needed to fit the input page. "
0832                                                  "This works best if the stamp PDF page has a transparent background.") );
0833         }
0834     }
0835     else {
0836         m_PdfDialog.m_lbStamp->hide();
0837         m_PdfDialog.m_edStamp->hide();
0838     }
0839 
0840     if (isBackgroundColor(taskindex)) {
0841         m_PdfDialog.m_lbBackgroundColor->show();
0842         m_PdfDialog.m_pbBackgroundColor->show();
0843     }
0844     else {
0845         m_PdfDialog.m_lbBackgroundColor->hide();
0846         m_PdfDialog.m_pbBackgroundColor->hide();
0847     }
0848     if (isOverlayTask(taskindex) || isBackgroundColor(taskindex) || isFreeTask(taskindex)) {
0849         m_rearrangeButton->setText(i18n("&Apply"));
0850     }
0851     else {
0852         m_rearrangeButton->setText(i18n("Re&arrange"));
0853     }
0854 }
0855 
0856 // execute commands
0857 void PdfDialog::slotExecute()
0858 {
0859     if(!m_tempdir) {
0860         // create tempdir
0861         m_tempdir = new QTemporaryDir(QDir::tempPath() + QLatin1String("/kile-pdfwizard"));
0862         m_tempdir->setAutoRemove(true);
0863         KILE_DEBUG_MAIN << "tempdir: " << m_tempdir->path();
0864     }
0865 
0866     if(!m_tempdir->isValid()) {
0867         KMessageBox::error(this, i18n("Failed to create a temporary directory.\n\nThis wizard cannot be used."));
0868         reject();
0869         return;
0870     }
0871 
0872     int tabindex = m_PdfDialog.tabWidget->currentIndex();
0873 
0874     switch (tabindex) {
0875     case 0:
0876         if (checkParameter()) {
0877             executeAction();
0878         }
0879         break;
0880     case 1:
0881         if (checkProperties()) {
0882             executeProperties();
0883         }
0884         break;
0885     case 2:
0886         if (checkPermissions()) {
0887             executePermissions();
0888         }
0889         break;
0890     }
0891 }
0892 
0893 void PdfDialog::slotShowHelp()
0894 {
0895     QString message = i18n("<center>PDF-Wizard</center><br>"
0896                            "This wizard uses 'pdftk' and the LaTeX package 'pdfpages' to"
0897                            "<ul>"
0898                            "<li>rearrange pages of an existing PDF document</li>"
0899                            "<li>read and update documentinfo of a PDF document (only pdftk)</li>"
0900                            "<li>read, set or change some permissions of a PDF document (only pdftk). "
0901                            "A password is necessary to set or change this document settings. "
0902                            "Additionally PDF encryption is done to lock the file's content behind this password.</li>"
0903                            "</ul>"
0904                            "<p>The package 'pdfpages' will only work with non-encrypted documents. "
0905                            "'pdftk' can handle both kind of documents, but a password is needed for encrypted files. "
0906                            "If one of 'pdftk' or 'pdfpages' is not available, the possible rearrangements are reduced.</p>"
0907                            "<p><i>Warning:</i> Encryption and a password does not provide any real PDF security. The content "
0908                            "is encrypted, but the key is known. You should see it more as a polite but firm request "
0909                            "to respect the author's wishes.</p>");
0910 
0911 #if !LIBPOPPLER_AVAILABLE
0912     message += i18n("<p><i>Information: </i>This version of Kile was compiled without libpoppler library. "
0913                     "Setting, changing and removing of properties and permissions is not possible.</p>");
0914 #endif
0915 
0916     KMessageBox::information(this, message, i18n("PDF Tools"));
0917 }
0918 
0919 void PdfDialog::executeAction()
0920 {
0921     QString command = buildActionCommand();
0922     if ( command.isEmpty() ) {
0923         return;
0924     }
0925 
0926     m_errorHandler->clearMessages();
0927     QFileInfo from(m_inputfile);
0928     QFileInfo to(m_outputfile);
0929 
0930     // output for log window
0931     QString program = (m_execLatex) ? i18n("LaTeX with 'pdfpages' package") : i18n("pdftk");
0932     QString msg = i18n("Rearranging PDF file: %1", from.fileName());
0933     if (!to.fileName().isEmpty())
0934         msg += " ---> " + to.fileName();
0935     m_errorHandler->printMessage(KileTool::Info, msg, program);
0936 
0937     // some output logs
0938     m_output->clear();
0939     QString s = QString("*****\n")
0940                 + i18n("***** tool:        ") + program + '\n'
0941                 + i18n("***** input file:  ") + from.fileName()+ '\n'
0942                 + i18n("***** output file: ") + to.fileName()+ '\n'
0943                 + i18n("***** param:       ") + m_param + '\n'
0944                 + i18n("***** command:     ") + command + '\n'
0945                 + i18n("***** viewer:      ") + ((m_PdfDialog.m_cbView->isChecked()) ? i18n("yes") : i18n("no")) + '\n'
0946                 + "*****\n";
0947     emit( output(s) );
0948 
0949     // run Process
0950     executeScript(command, m_tempdir->path(), PDF_SCRIPTMODE_ACTION);
0951 }
0952 
0953 void PdfDialog::executeProperties()
0954 {
0955     // create temporary file
0956     QTemporaryFile infotemp(m_tempdir->path() + QLatin1String("/kile-pdfdialog-XXXXXX.txt"));
0957     infotemp.setAutoRemove(false);
0958 
0959     if(!infotemp.open()) {
0960         KILE_DEBUG_MAIN << "Could not create tempfile for key/value pairs in QString PdfDialog::executeProperties()" ;
0961         return;
0962     }
0963     QString infofile = infotemp.fileName();
0964 
0965     // create a text file with key/value pairs for pdftk
0966     QTextStream infostream(&infotemp);
0967     for (QStringList::const_iterator it = m_pdfInfoKeys.constBegin(); it != m_pdfInfoKeys.constEnd(); ++it) {
0968         infostream << "InfoKey: " << (*it) << "\n";
0969         infostream << "InfoValue: " << m_pdfInfoWidget[*it]->text().trimmed() << "\n";
0970     }
0971     // add modification Date
0972     QString datetime = QDateTime::currentDateTimeUtc().toString("%Y%m%d%H%M%S%:z");
0973     datetime = datetime.replace(":","'");
0974     infostream << "InfoKey: " << "ModDate" << "\n";
0975     infostream << "InfoValue: " << "D:" << datetime << "'\n";
0976     infotemp.close();
0977 
0978     // build command
0979     QString inputfile = m_PdfDialog.m_edInfile->lineEdit()->text().trimmed();
0980     QString password =  m_PdfDialog.m_edPassword->text().trimmed();
0981     QString pdffile = m_tempdir->path() + QFileInfo(m_inputfile).baseName() + "-props.pdf";
0982 
0983     // read permissions
0984     QString permissions = readPermissions();
0985 
0986     // build param
0987     QString param = "\"" + inputfile + "\"";
0988     if ( m_encrypted ) {
0989         param += " input_pw " + password;
0990     }
0991 
0992     param += " update_info " + infofile + " output \"" + pdffile+ "\"";
0993     if ( m_encrypted ) {
0994         param += " encrypt_128bit";
0995         if ( !permissions.isEmpty() )
0996             param += " allow " + permissions;
0997         param += " owner_pw " + password;
0998     }
0999     QString command = "pdftk " + param;
1000 
1001     // move destination file
1002     m_move_filelist.clear();
1003     m_move_filelist << pdffile << inputfile;
1004 
1005     // execute script
1006     showLogs("Updating properties", inputfile, param);
1007     executeScript(command, QString(), PDF_SCRIPTMODE_PROPERTIES);
1008 
1009 }
1010 
1011 void PdfDialog::executePermissions()
1012 {
1013     // read permissions
1014     QString permissions = readPermissions();
1015 
1016     // build command
1017     QString inputfile = m_PdfDialog.m_edInfile->lineEdit()->text().trimmed();
1018     QString password =  m_PdfDialog.m_edPassword->text().trimmed();
1019     QString pdffile = m_tempdir->path() + QFileInfo(m_inputfile).baseName() + "-perms.pdf";
1020 
1021     QString param = "\"" + inputfile + "\"";
1022     if ( m_encrypted ) {
1023         param += " input_pw " + password;
1024     }
1025     param += " output \"" + pdffile + "\" encrypt_128bit";
1026     if ( !permissions.isEmpty() ) {
1027         param += " allow " + permissions;
1028     }
1029     param += " owner_pw " + password;
1030     QString command = "pdftk " + param;
1031 
1032     // move destination file
1033     m_move_filelist.clear();
1034     m_move_filelist << pdffile << inputfile;
1035 
1036     // execute script
1037     showLogs("Updating permissions", inputfile, param);
1038     executeScript(command, QString(), PDF_SCRIPTMODE_PERMISSIONS);
1039 
1040 }
1041 
1042 void PdfDialog::showLogs(const QString &title, const QString &inputfile, const QString &param)
1043 {
1044     // some info for log widget
1045     m_errorHandler->clearMessages();
1046     m_errorHandler->printMessage(KileTool::Info, title, "pdftk" );
1047 
1048     // some info for output widget
1049     QFileInfo input(inputfile);
1050     m_output->clear();
1051     QString s = QString("*****\n")
1052                 + i18n("***** tool:        ") + "pdftk" + '\n'
1053                 + i18n("***** input file:  ") + input.fileName()+ '\n'
1054                 + i18n("***** param:       ") + param + '\n'
1055                 + "*****\n";
1056     emit( output(s) );
1057 }
1058 
1059 void PdfDialog::executeScript(const QString &command, const QString &dir, int scriptmode)
1060 {
1061     // delete old KProcess
1062     if(m_proc) {
1063         delete m_proc;
1064     }
1065 
1066     m_scriptmode = scriptmode;
1067     m_outputtext = "";
1068 
1069     m_proc = new KProcess();
1070     if (!dir.isEmpty()) {
1071         m_proc->setWorkingDirectory(dir);
1072     }
1073     m_proc->setShellCommand(command);
1074     m_proc->setOutputChannelMode(KProcess::MergedChannels);
1075     m_proc->setReadChannel(QProcess::StandardOutput);
1076 
1077     connect(m_proc, &QProcess::readyReadStandardOutput,
1078             this, &PdfDialog::slotProcessOutput);
1079 
1080     connect(m_proc, &QProcess::readyReadStandardError,
1081             this, &PdfDialog::slotProcessOutput);
1082 
1083     connect(m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
1084             this, &PdfDialog::slotProcessExited);
1085 
1086     connect(m_proc, &QProcess::errorOccurred,
1087             this, [this]() { slotProcessExited(-1, QProcess::CrashExit); });
1088 
1089     KILE_DEBUG_MAIN << "=== PdfDialog::runPdfutils() ====================";
1090     KILE_DEBUG_MAIN << "execute '" << command << "'";
1091     m_scriptrunning = true;
1092     m_rearrangeButton->setEnabled(false);
1093     m_buttonBox->button(QDialogButtonBox::Close)->setEnabled(false);
1094     m_proc->start();
1095 }
1096 
1097 void PdfDialog::slotProcessOutput()
1098 {
1099     m_outputtext += m_proc->readAll();
1100 }
1101 
1102 
1103 void PdfDialog::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
1104 {
1105     if(exitCode != 0 || exitStatus != QProcess::NormalExit) {
1106         if (m_scriptmode != PDF_SCRIPTMODE_TOOLS)
1107             showError(i18n("An error occurred while executing the task."));
1108     }
1109     else {
1110         bool state = ( exitCode == 0 );
1111         if ( m_scriptmode == PDF_SCRIPTMODE_TOOLS ) {
1112             initUtilities();
1113         }
1114 #if !LIBPOPPLER_AVAILABLE
1115         else if ( m_scriptmode==PDF_SCRIPTMODE_NUMPAGES_PDFTK
1116                   || m_scriptmode==PDF_SCRIPTMODE_NUMPAGES_IMAGEMAGICK
1117                   || m_scriptmode==PDF_SCRIPTMODE_NUMPAGES_GHOSTSCRIPT ) {
1118             readNumberOfPages(m_scriptmode,m_outputtext);
1119         }
1120 #endif
1121         else {
1122             finishPdfAction(state);
1123         }
1124     }
1125 
1126     m_scriptrunning = false;
1127     m_buttonBox->button(QDialogButtonBox::Close)->setEnabled(true);
1128     updateDialog();
1129 }
1130 
1131 void PdfDialog::finishPdfAction(bool state)
1132 {
1133     // output window
1134     emit( output(m_outputtext) );
1135 
1136     // log window
1137     QString program = (m_scriptmode==PDF_SCRIPTMODE_ACTION && m_execLatex) ? "LaTeX with 'pdfpages' package" : "pdftk";
1138 
1139     if ( state ) {
1140         m_errorHandler->printMessage(KileTool::Info, "finished", program);
1141 
1142         // should we move the temporary pdf file
1143         if ( ! m_move_filelist.isEmpty() ) {
1144             QFile::remove( m_move_filelist[1] );
1145             QFile::rename( m_move_filelist[0], m_move_filelist[1] );
1146             KILE_DEBUG_MAIN << "move file: " << m_move_filelist[0] << " --->  " << m_move_filelist[1];
1147         }
1148 
1149         // run viewer
1150         if ( m_PdfDialog.m_cbView->isChecked() && m_scriptmode==PDF_SCRIPTMODE_ACTION ) {
1151             runViewer();
1152         }
1153 
1154         // file properties/permissions could be changed
1155         if ( (m_scriptmode==PDF_SCRIPTMODE_ACTION && m_PdfDialog.m_cbOverwrite->isChecked())
1156                 || m_scriptmode==PDF_SCRIPTMODE_PROPERTIES || m_scriptmode==PDF_SCRIPTMODE_PERMISSIONS ) {
1157             slotInputfileChanged( m_PdfDialog.m_edInfile->lineEdit()->text().trimmed() );
1158         }
1159     }
1160     else {
1161         QString msg;
1162         if (m_outputtext.indexOf("OWNER PASSWORD") >= 0 ) {
1163             msg = i18n("Finished with an error (wrong password)");
1164         }
1165         else {
1166             msg = i18n("Finished with an error");
1167         }
1168         m_errorHandler->printMessage(KileTool::Error, msg, program);
1169     }
1170 }
1171 
1172 void PdfDialog::runViewer()
1173 {
1174     m_errorHandler->printMessage(KileTool::Info, "Running viewer", "ViewPDF");
1175 
1176     // call ViewPDF
1177     QString cfg = KileTool::configName("ViewPDF", m_manager->config());
1178     KileTool::View *tool = dynamic_cast<KileTool::View*>(m_manager->createTool("ViewPDF", cfg, false));
1179     if(!tool) {
1180         m_errorHandler->printMessage(KileTool::Error, i18n("Could not create the ViewPDF tool"), i18n("ViewPDF"));
1181         return;
1182     }
1183     tool->setFlags(0);
1184     tool->setSource(m_outputfile);
1185     m_manager->run(tool);
1186 }
1187 
1188 QString PdfDialog::buildActionCommand()
1189 {
1190     // build action: parameter
1191     m_execLatex = true;           // default
1192     m_inputfile = m_PdfDialog.m_edInfile->lineEdit()->text().trimmed();
1193     m_outputfile = m_PdfDialog.m_edOutfile->lineEdit()->text().trimmed();
1194 
1195     QColor bgcolor;
1196     QString bgfile;
1197     int taskindex = taskIndex();
1198     switch (taskindex) {
1199     case PDF_PAGE_EMPTY:
1200         m_param = "nup=1x2,landscape,pages=" + buildPageRange(PDF_PAGE_EMPTY);
1201         break;
1202 
1203     case PDF_PAGE_DUPLICATE:
1204         m_param = "nup=1x2,landscape,pages=" + buildPageRange(PDF_PAGE_DUPLICATE);
1205         break;
1206 
1207     case PDF_2UP:
1208         m_param = "nup=1x2,landscape,pages=1-";
1209         break;
1210 
1211     case PDF_2UP_LANDSCAPE:
1212         m_param = "nup=1x2,pages=1-";
1213         break;
1214 
1215     case PDF_4UP:
1216         m_param = "nup=2x2,pages=1-";
1217         break;
1218 
1219     case PDF_4UP_LANDSCAPE:
1220         m_param = "nup=2x2,landscape,pages=1-";
1221         break;
1222 
1223     case PDF_EVEN:
1224         if ( m_pdftk ) {
1225             m_param = "cat 1-endeven";
1226             m_execLatex = false;
1227         }
1228         else {
1229             m_param = buildPageList(true);
1230         }
1231         break;
1232 
1233     case PDF_ODD:
1234         if ( m_pdftk ) {
1235             m_param = "cat 1-endodd";
1236             m_execLatex = false;
1237         }
1238         else {
1239             m_param = buildPageList(false);
1240         }
1241         break;
1242 
1243     case PDF_EVEN_REV:
1244         if ( m_pdftk ) {
1245             m_param = "cat end-1even";
1246             m_execLatex = false;
1247         }
1248         else {
1249             m_param = buildReversPageList(true);
1250         }
1251         break;
1252 
1253     case PDF_ODD_REV:
1254         if ( m_pdftk ) {
1255             m_param = "cat end-1odd";
1256             m_execLatex = false;
1257         }
1258         else {
1259             m_param = buildReversPageList(false);
1260         }
1261         break;
1262 
1263     case PDF_REVERSE:
1264         if ( m_pdftk ) {
1265             m_param = "cat end-1";
1266             m_execLatex = false;
1267         }
1268         else {
1269             m_param = "last-1";
1270         }
1271         break;
1272 
1273     case PDF_DECRYPT:
1274         m_param.clear();
1275         m_execLatex = false;
1276         break;
1277 
1278     case PDF_SELECT:
1279     case PDF_DELETE:
1280         m_param = ( taskindex == PDF_SELECT ) ? buildSelectPageList() : buildDeletePageList();
1281         if ( m_pdftk ) {
1282             m_param = "cat " + m_param.replace(","," ");
1283             m_execLatex = false;
1284         }
1285         else {
1286             m_param = "pages={" + m_param + "}";
1287         }
1288         break;
1289 
1290     case PDF_PDFTK_BACKGROUND:
1291         m_param = "background \"" + m_PdfDialog.m_edStamp->text().trimmed() + "\"";
1292         m_execLatex = false;
1293         break;
1294 
1295     case PDF_PDFTK_BGCOLOR:
1296         bgcolor = m_PdfDialog.m_pbBackgroundColor->color();
1297         bgfile = buildPdfBackgroundFile(&bgcolor);
1298         m_param = "background " + bgfile;
1299         m_execLatex = false;
1300         break;
1301 
1302     case PDF_PDFTK_STAMP:
1303         m_param = "stamp \"" + m_PdfDialog.m_edStamp->text().trimmed() + "\"";
1304         m_execLatex = false;
1305         break;
1306 
1307     case PDF_PDFTK_FREE:
1308         m_param = m_PdfDialog.m_edParameter->text().trimmed();
1309         m_execLatex = false;
1310         break;
1311 
1312     case PDF_PDFPAGES_FREE:
1313         m_param = m_PdfDialog.m_edParameter->text().trimmed();
1314         break;
1315     }
1316 
1317     // build action: command
1318     QString command,latexfile,pdffile;
1319     if ( m_execLatex ) {
1320         latexfile = buildLatexFile(m_param);
1321         pdffile = latexfile + ".pdf";
1322         command = "pdflatex -interaction=nonstopmode " + latexfile + ".tex";
1323     }
1324     else {
1325         pdffile = m_tempdir->path() + QFileInfo(m_inputfile).baseName() + "-temp.pdf";
1326         command = "pdftk \"" + m_inputfile + "\"";
1327         if ( m_encrypted ) {
1328             QString password =  m_PdfDialog.m_edPassword->text().trimmed();
1329             command += " input_pw " + password;
1330         }
1331         command += " " + m_param + " output \"" + pdffile+ "\"";
1332     }
1333 
1334     // additional actions
1335     bool viewer = m_PdfDialog.m_cbView->isChecked();
1336 
1337     bool equalfiles = (m_PdfDialog.m_cbOverwrite->isChecked() || m_inputfile==m_outputfile);
1338     if (equalfiles) {
1339         m_outputfile = m_inputfile;
1340     }
1341 
1342     // move destination file
1343     m_move_filelist.clear();
1344     if ( equalfiles ) {
1345         m_move_filelist << pdffile << m_inputfile;
1346     }
1347     else if ( !m_outputfile.isEmpty() ) {
1348         m_move_filelist << pdffile << m_outputfile;
1349     }
1350 
1351     // viewer
1352     if ( viewer && m_outputfile.isEmpty() ) {
1353         m_outputfile = pdffile;
1354     }
1355 
1356     return command;
1357 }
1358 
1359 // create a temporary file to run latex with package pdfpages.sty
1360 QString PdfDialog::buildLatexFile(const QString &param)
1361 {
1362     QTemporaryFile temp(m_tempdir->path() + QLatin1String("/kile-pdfdialog-XXXXXX.tex"));
1363     temp.setAutoRemove(false);
1364 
1365     if(!temp.open()) {
1366         KILE_DEBUG_MAIN << "Could not create tempfile in PdfDialog::buildLatexFile()" ;
1367         return QString();
1368     }
1369     QString tempname = temp.fileName();
1370 
1371     QTextStream stream(&temp);
1372     stream << "\\documentclass[a4paper,12pt]{article}\n";
1373     stream << "\\usepackage[final]{pdfpages}\n";
1374     stream << "\\begin{document}\n";
1375     stream << "\\includepdf[" << param << "]{" << m_inputfile << "}\n";
1376     stream << "\\end{document}\n";
1377 
1378     // everything is prepared to do the job
1379     temp.close();
1380     return(tempname.left(tempname.length() - 4));
1381 }
1382 
1383 // create a temporary pdf file to set a background color
1384 QString PdfDialog::buildPdfBackgroundFile(QColor *color)
1385 {
1386     QTemporaryFile temp(m_tempdir->path() + QLatin1String("/kile-pdfdialog-XXXXXX.pdf"));
1387     temp.setAutoRemove(false);
1388 
1389     if(!temp.open()) {
1390         KILE_DEBUG_MAIN << "Could not create tempfile in PdfDialog::buildPdfBackgroundFile()" ;
1391         return QString();
1392     }
1393     QString tempname = temp.fileName();
1394 
1395     QTextStream stream(&temp);
1396     stream << "%PDF-1.4\n";
1397     stream << '%' << '\0' << '\0' << '\0' << '\0' << '\r';
1398     stream << "5 0 obj \n"
1399            "<<\n"
1400            "/Type /ExtGState\n"
1401            "/OPM 1\n"
1402            ">>\n"
1403            "endobj \n"
1404            "4 0 obj \n"
1405            "<<\n"
1406            "/R7 5 0 R\n"
1407            ">>\n"
1408            "endobj \n"
1409            "6 0 obj \n"
1410            "<<\n"
1411            "/Length 83\n"
1412            ">>\n"
1413            "stream\n"
1414            "q 0.1 0 0 0.1 0 0 cm\n"
1415            "/R7 gs\n";
1416     stream << color->redF() << " " << color->greenF() << " " << color->blueF() << " rg\n";
1417     stream << "0 0 " << 10*m_pagesize.width() << " " << 10*m_pagesize.height() << " re\n";
1418     stream << "f\n"
1419            "0 g\n"
1420            "Q\n"
1421            "\n"
1422            "endstream \n"
1423            "endobj \n"
1424            "3 0 obj \n"
1425            "<<\n"
1426            "/Parent 1 0 R\n";
1427     stream << "/MediaBox [0 0 " << m_pagesize.width() << " " << m_pagesize.height() << "]\n";
1428     stream << "/Resources \n"
1429            "<<\n"
1430            "/ExtGState 4 0 R\n"
1431            "/ProcSet [/PDF]\n"
1432            ">>\n"
1433            "/pdftk_PageNum 1\n"
1434            "/Type /Page\n"
1435            "/Contents 6 0 R\n"
1436            ">>\n"
1437            "endobj \n"
1438            "1 0 obj \n"
1439            "<<\n"
1440            "/Kids [3 0 R]\n"
1441            "/Count 1\n"
1442            "/Type /Pages\n"
1443            ">>\n"
1444            "endobj \n"
1445            "7 0 obj \n"
1446            "<<\n"
1447            "/Pages 1 0 R\n"
1448            "/Type /Catalog\n"
1449            ">>\n"
1450            "endobj \n"
1451            "8 0 obj \n"
1452            "<<\n"
1453            "/Creator ()\n"
1454            "/Producer ())\n"
1455            "/ModDate ()\n"
1456            "/CreationDate ()\n"
1457            ">>\n"
1458            "endobj xref\n"
1459            "0 9\n"
1460            "0000000000 65535 f \n"
1461            "0000000388 00000 n \n"
1462            "0000000000 65536 n \n"
1463            "0000000231 00000 n \n"
1464            "0000000062 00000 n \n"
1465            "0000000015 00000 n \n"
1466            "0000000095 00000 n \n"
1467            "0000000447 00000 n \n"
1468            "0000000498 00000 n \n"
1469            "trailer\n"
1470            "\n"
1471            "<<\n"
1472            "/Info 8 0 R\n"
1473            "/Root 7 0 R\n"
1474            "/Size 9\n"
1475            "/ID [<4a7c31ef3aeb884b18f59c2037a752f5><54079f85d95a11f3400fe5fc3cfc832b>]\n"
1476            ">>\n"
1477            "startxref\n"
1478            "721\n"
1479            "%%EOF\n";
1480 
1481     // everything is prepared to do the job
1482     temp.close();
1483     return tempname;
1484 }
1485 
1486 QString PdfDialog::buildPageRange(int type)
1487 {
1488     QString s;
1489     for (int i = 1; i <= m_numpages; ++i) {
1490         if (type == PDF_PAGE_EMPTY) {
1491             s += QString("%1,{},").arg(i);
1492         }
1493         else {
1494             s += QString("%1,%2,").arg(i).arg(i);
1495         }
1496     }
1497 
1498     return "{" + s.left(s.length()-1) + "}";
1499 }
1500 
1501 QString PdfDialog::buildPageList(bool even)
1502 {
1503     QString s, number;
1504 
1505     int start = ( even ) ? 2 : 1;
1506     for (int i=start; i<=m_numpages; i+=2 ) {
1507         s += number.setNum(i) + ',';
1508     }
1509 
1510     if ( !s.isEmpty() ) {
1511         s.truncate(s.length()-1);
1512     }
1513     return "{" + s + "}";
1514 }
1515 
1516 QString PdfDialog::buildReversPageList(bool even)
1517 {
1518     QString s,number;
1519 
1520     int last = m_numpages;
1521     if ( even ) {
1522         if ( (last & 1) == 1 ) {
1523             last--;
1524         }
1525     }
1526     else {
1527         if ( (last & 1) == 0 ) {
1528             last--;
1529         }
1530     }
1531 
1532     for (int i=last; i>=1; i-=2 ) {
1533         s += number.setNum(i) + ",";
1534     }
1535 
1536     if ( !s.isEmpty() ) {
1537         s.truncate(s.length()-1);
1538     }
1539     return "{" + s + "}";
1540 }
1541 
1542 QString PdfDialog::buildSelectPageList()
1543 {
1544     return m_PdfDialog.m_edParameter->text().trimmed();
1545 }
1546 
1547 QString PdfDialog::buildDeletePageList()
1548 {
1549     // m_numpages is known
1550     QString param = m_PdfDialog.m_edParameter->text().trimmed();
1551     QRegExp re("(\\d+)-(\\d+)");
1552 
1553     // analyze delete list
1554     bool ok;
1555     QBitArray arr(m_numpages + 1,false);
1556     QStringList pagelist = param.split(',');
1557     foreach (const QString &s, pagelist) {
1558         if ( s.contains('-') && re.indexIn(s) >= 0 ) {
1559             int from = re.cap(1).toInt(&ok);
1560             int to = re.cap(2).toInt(&ok);
1561             for (int i=from; i<=to; ++i) {
1562                 arr.setBit(i);
1563             }
1564         }
1565         else {
1566             arr.setBit(s.toInt(&ok));
1567         }
1568     }
1569 
1570     // build select list
1571     QString result;
1572     int page = 1;
1573     while ( page <= m_numpages ) {
1574         int from = searchPages(&arr,page,m_numpages,true);
1575         if ( from > m_numpages ) {
1576             break;
1577         }
1578         int to = searchPages(&arr,from+1,m_numpages,false) - 1;
1579         if ( !result.isEmpty() ) {
1580             result += ',';
1581         }
1582         if ( from < to ) {
1583             result += QString::number(from) + '-' + QString::number(to);
1584         }
1585         else {
1586             result += QString::number(from);
1587         }
1588         page = to + 1;
1589     }
1590 
1591     return result;
1592 }
1593 
1594 int PdfDialog::searchPages(QBitArray *arr, int page, int lastpage, bool value)
1595 {
1596     while ( page <= lastpage ) {
1597         if ( arr->at(page) != value ) {
1598             return page;
1599         }
1600         page++;
1601     }
1602     return lastpage + 1;
1603 }
1604 
1605 bool PdfDialog::checkParameter()
1606 {
1607     if ( !checkInputFile() ) {
1608         return false;
1609     }
1610 
1611     if ( m_encrypted ) {
1612         if ( !checkPassword() ) {
1613             return false;
1614         }
1615     }
1616 
1617     // check parameter
1618     int taskindex = taskIndex();
1619     if ( isParameterTask(taskindex) && m_PdfDialog.m_edParameter->text().trimmed().isEmpty() ) {
1620         showError( i18n("The utility needs some parameters in this mode.") );
1621         return false;
1622     }
1623 
1624     // check select/delete page list (m_numpages is known)
1625     if ( taskindex==PDF_SELECT || taskindex==PDF_DELETE ) {
1626         // m_numpages is known
1627         QString param = m_PdfDialog.m_edParameter->text().trimmed();
1628         QRegExp re("(\\d+)-(\\d+)");
1629 
1630         // analyze page list
1631         bool ok;
1632         QStringList pagelist = param.split(',');
1633         foreach (const QString &s, pagelist) {
1634             if ( s.contains('-') && re.indexIn(s)>=0 ) {
1635                 int from = re.cap(1).toInt(&ok);
1636                 int to = re.cap(2).toInt(&ok);
1637                 if ( from > to ) {
1638                     showError(i18n("Illegal page list 'from-to': %1 is bigger than %2.",from,to));
1639                     return false;
1640                 }
1641                 if ( to > m_numpages ) {
1642                     showError(i18n("Illegal pagenumber: %1.",to));
1643                     return false;
1644                 }
1645             }
1646             else {
1647                 int page = s.toInt(&ok);
1648                 if ( page > m_numpages ) {
1649                     showError(i18n("Illegal pagenumber: %1.",page));
1650                     return false;
1651                 }
1652             }
1653         }
1654     }
1655 
1656     // check background/stamp parameter
1657     if ( isOverlayTask(taskindex) ) {
1658         QString filename = m_PdfDialog.m_edStamp->text().trimmed();
1659 
1660         if ( filename.isEmpty() ) {
1661             QString message = ( taskindex == PDF_PDFTK_STAMP )
1662                               ? i18n("You need to define a PDF file as foreground stamp.")
1663                               : i18n("You need to define a PDF file as background watermark.");
1664             showError(message);
1665             return false;
1666         }
1667 
1668         QFileInfo fs(filename);
1669         if (fs.completeSuffix() != "pdf") {
1670             showError(i18n("Unknown file format: only '.pdf' is accepted as image file in this mode."));
1671             return false;
1672         }
1673 
1674         if ( !QFile::exists(filename) ) {
1675             showError(i18n("The given file doesn't exist."));
1676             return false;
1677         }
1678     }
1679 
1680     // overwrite mode: no output file is needed
1681     if ( m_PdfDialog.m_cbOverwrite->isChecked() ) {
1682         return true;
1683     }
1684 
1685     // create a different output file
1686     QString outfile = m_PdfDialog.m_edOutfile->lineEdit()->text().trimmed();
1687     if ( outfile.isEmpty() ) {
1688         showError(i18n("You need to define an output file."));
1689         return false;
1690     }
1691 
1692     // outfile file must have extension pdf
1693     QFileInfo fo(outfile);
1694     if (fo.completeSuffix() != "pdf") {
1695         showError(i18n("Unknown file format: only '.pdf' is accepted as output file."));
1696         return false;
1697     }
1698 
1699     // check, if this output file already exists
1700     if ( fo.exists() ) {
1701         QString s = i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?", fo.fileName());
1702         if (KMessageBox::questionTwoActions(this,
1703                                             "<center>" + s + "</center>",
1704                                             i18n("PDF Tools"),
1705                                             KStandardGuiItem::overwrite(), KStandardGuiItem::cancel()
1706                                             ) == KMessageBox::SecondaryAction) {
1707             return false;
1708         }
1709     }
1710 
1711     return true;
1712 }
1713 
1714 bool PdfDialog::checkProperties()
1715 {
1716     if ( !checkInputFile() ) {
1717         return false;
1718     }
1719 
1720     return ( m_encrypted ) ? checkPassword() : true;
1721 }
1722 
1723 bool PdfDialog::checkPermissions()
1724 {
1725     if ( !checkInputFile() ) {
1726         return false;
1727     }
1728 
1729     return checkPassword();
1730 }
1731 
1732 bool PdfDialog::checkInputFile()
1733 {
1734     QString infile = m_PdfDialog.m_edInfile->lineEdit()->text().trimmed();
1735     if (infile.isEmpty()) {
1736         showError(i18n("No input file is given."));
1737         return false;
1738     }
1739 
1740     QFileInfo fi(infile);
1741     QString suffix = fi.completeSuffix();
1742     if (suffix != "pdf") {
1743         showError(i18n("Unknown file format: only '.pdf' are accepted for input files."));
1744         return false;
1745     }
1746 
1747     if (!fi.exists()) {
1748         showError(i18n("This input file does not exist."));
1749         return false;
1750     }
1751 
1752     return true;
1753 }
1754 
1755 bool PdfDialog::checkPassword()
1756 {
1757     // check password
1758     QString password = m_PdfDialog.m_edPassword->text().trimmed();
1759     if (password.isEmpty()) {
1760         showError(i18n("No password is given."));
1761         return false;
1762     }
1763 
1764     if (password.length() < 6) {
1765         showError(i18n("The password should be at least 6 characters long."));
1766         return false;
1767     }
1768 
1769     return true;
1770 }
1771 
1772 void PdfDialog::showError(const QString &text)
1773 {
1774     KMessageBox::error(this, i18n("<center>") + text + i18n("</center>"), i18n("PDF Tools"));
1775 }
1776 
1777 // check tasks
1778 bool PdfDialog::isParameterTask(int task)
1779 {
1780     return ( task==PDF_SELECT || task==PDF_DELETE || task==PDF_PDFPAGES_FREE || task==PDF_PDFTK_FREE );
1781 }
1782 
1783 bool PdfDialog::isOverlayTask(int task)
1784 {
1785     return ( task==PDF_PDFTK_BACKGROUND || task==PDF_PDFTK_STAMP );
1786 }
1787 
1788 bool PdfDialog::isBackgroundColor(int task)
1789 {
1790     return ( task == PDF_PDFTK_BGCOLOR ) ? true : false;
1791 }
1792 
1793 bool PdfDialog::isFreeTask(int task)
1794 {
1795     return ( task==PDF_PDFPAGES_FREE || task==PDF_PDFTK_FREE );
1796 }
1797 
1798 }