File indexing completed on 2024-05-19 12:55:54
0001 /********************************************************************************** 0002 Ccopyright (C) 2005-2007 by Holger Danielsson (holger.danielsson@versanet.de) 0003 **********************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or modify * 0008 * it under the terms of the GNU General Public License as published by * 0009 * the Free Software Foundation; either version 2 of the License, or * 0010 * (at your option) any later version. * 0011 * * 0012 ***************************************************************************/ 0013 0014 // 2007-03-12 dani 0015 // - use KileDocument::Extensions 0016 0017 #include "dialogs/postscriptdialog.h" 0018 0019 #include <QLabel> 0020 #include <QCheckBox> 0021 #include <QGridLayout> 0022 #include <QGroupBox> 0023 #include <QLayout> 0024 #include <QLineEdit> 0025 #include <QProcess> 0026 #include <QSpinBox> 0027 #include <QStringList> 0028 #include <QDialogButtonBox> 0029 #include <QPushButton> 0030 #include <QVBoxLayout> 0031 #include <QStandardPaths> 0032 0033 #include <KComboBox> 0034 #include <KLocalizedString> 0035 #include <KMessageBox> 0036 #include <KProcess> 0037 0038 #include <QTemporaryFile> 0039 #include <KUrlRequester> 0040 #include <KConfigGroup> 0041 #include <KLineEdit> 0042 0043 #include "errorhandler.h" 0044 #include "kiledebug.h" 0045 #include "kiletool_enums.h" 0046 0047 namespace KileDialog 0048 { 0049 0050 PostscriptDialog::PostscriptDialog(QWidget *parent, 0051 const QString &texfilename,const QString &startdir, 0052 const QString &latexextensions, 0053 KileErrorHandler *errorHandler, KileWidget::OutputView *output) : 0054 QDialog(parent), 0055 m_startdir(startdir), 0056 m_errorHandler(errorHandler), 0057 m_output(output), 0058 m_proc(Q_NULLPTR) 0059 { 0060 setWindowTitle(i18n("Rearrange Postscript File")); 0061 setModal(true); 0062 0063 QWidget *mainWidget = new QWidget(this); 0064 QVBoxLayout *mainLayout = new QVBoxLayout; 0065 setLayout(mainLayout); 0066 mainLayout->addWidget(mainWidget); 0067 0068 0069 // determine if a psfile already exists 0070 QString psfilename,psoutfilename; 0071 if(!texfilename.isEmpty()) { 0072 // working with a postscript document, so we try to determine the LaTeX source file 0073 QStringList extlist = latexextensions.split(' '); 0074 for (QStringList::Iterator it = extlist.begin(); it != extlist.end(); ++it) { 0075 if (texfilename.indexOf((*it), -(*it).length()) >= 0) { 0076 QString basename = psfilename = texfilename.left(texfilename.length() - (*it).length()); 0077 psfilename = basename + ".ps"; 0078 psoutfilename = basename + "-out.ps"; 0079 if (!QFileInfo::exists(psfilename)) 0080 psfilename.clear(); 0081 break; 0082 } 0083 } 0084 } 0085 0086 // prepare dialog 0087 QWidget *page = new QWidget(this); 0088 mainLayout->addWidget(page); 0089 m_PostscriptDialog.setupUi(page); 0090 0091 // line 0: QLabel 0092 bool pstops = !QStandardPaths::findExecutable("pstops").isEmpty(); 0093 bool psselect = !QStandardPaths::findExecutable("psselect").isEmpty(); 0094 0095 if (!pstops && !psselect) { 0096 m_PostscriptDialog.m_mwErrors->setMessageType(KMessageWidget::Error); 0097 m_PostscriptDialog.m_mwErrors->setText(i18n("Neither 'pstops' nor 'psselect' found.")); 0098 } else if (!pstops) { 0099 m_PostscriptDialog.m_mwErrors->setMessageType(KMessageWidget::Warning); 0100 m_PostscriptDialog.m_mwErrors->setText(i18n("'pstops' not found.")); 0101 } else if (!psselect) { 0102 m_PostscriptDialog.m_mwErrors->setMessageType(KMessageWidget::Warning); 0103 m_PostscriptDialog.m_mwErrors->setText(i18n("'psselect' not found.")); 0104 } else { 0105 m_PostscriptDialog.m_mwErrors->hide(); 0106 } 0107 0108 m_PostscriptDialog.m_edInfile->lineEdit()->setText(psfilename); 0109 m_PostscriptDialog.m_edOutfile->lineEdit()->setText(psoutfilename); 0110 0111 // according to QT 4.4 docu the index of QComboBox might change if adding or removing items 0112 // but because we populate the QComboBox before we start the dialog, we can use the index here 0113 if (pstops) { 0114 m_PostscriptDialog.m_cbTask->addItem(i18n("1 DIN A5 Page + Empty Page --> DIN A4")); // 0 PS_A5_EMPTY 0115 m_PostscriptDialog.m_cbTask->addItem(i18n("1 DIN A5 Page + Duplicate --> DIN A4")); // 1 PS_A5_DUPLICATE 0116 m_PostscriptDialog.m_cbTask->addItem(i18n("2 DIN A5 Pages --> DIN A4")); // 2 PS_2xA5 0117 m_PostscriptDialog.m_cbTask->addItem(i18n("2 DIN A5L Pages --> DIN A4")); // 3 PS_2xA5L 0118 m_PostscriptDialog.m_cbTask->addItem(i18n("4 DIN A5 Pages --> DIN A4")); // 4 PS_4xA5 0119 m_PostscriptDialog.m_cbTask->addItem(i18n("1 DIN A4 Page + Empty Page --> DIN A4")); // 5 m_PostscriptDialog.PS_A4_EMPTY 0120 m_PostscriptDialog.m_cbTask->addItem(i18n("1 DIN A4 Page + Duplicate --> DIN A4")); // 6 PS_A4_DUPLICATE 0121 m_PostscriptDialog.m_cbTask->addItem(i18n("2 DIN A4 Pages --> DIN A4")); // 7 PS_2xA4 0122 m_PostscriptDialog.m_cbTask->addItem(i18n("2 DIN A4L Pages --> DIN A4")); // 8 PS_2xA4L 0123 } 0124 if (psselect) { 0125 m_PostscriptDialog.m_cbTask->addItem(i18n("Select Even Pages")); // 9 PS_EVEN 0126 m_PostscriptDialog.m_cbTask->addItem(i18n("Select Odd Pages")); // 10 PS_ODD 0127 m_PostscriptDialog.m_cbTask->addItem(i18n("Select Even Pages (reverse order)")); // 11 m_PostscriptDialog.PS_EVEN_REV 0128 m_PostscriptDialog.m_cbTask->addItem(i18n("Select Odd Pages (reverse order)")); // 12 PS_ODD_REV 0129 m_PostscriptDialog.m_cbTask->addItem(i18n("Reverse All Pages")); // 13 PS_REVERSE 0130 m_PostscriptDialog.m_cbTask->addItem(i18n("Copy All Pages (sorted)")); // 14 PS_COPY_SORTED 0131 } 0132 if (pstops) { 0133 m_PostscriptDialog.m_cbTask->addItem(i18n("Copy All Pages (unsorted)")); // 15 PS_COPY_UNSORTED 0134 m_PostscriptDialog.m_cbTask->addItem(i18n("pstops: Choose Parameter")); // 16 PS_PSTOPS_FREE 0135 } 0136 if (psselect) { 0137 m_PostscriptDialog.m_cbTask->addItem(i18n("psselect: Choose Parameter")); // 17 PS_PSSELECT_FREE 0138 } 0139 const QStringList postscriptMimeTypes = { 0140 QStringLiteral("application/postscript"), 0141 QStringLiteral("application/x-gzpostscript"), 0142 }; 0143 m_PostscriptDialog.m_edInfile->setMimeTypeFilters(postscriptMimeTypes); 0144 m_PostscriptDialog.m_edOutfile->setMimeTypeFilters(postscriptMimeTypes); 0145 m_PostscriptDialog.m_edOutfile->setMode(KFile::File | KFile::LocalOnly); 0146 0147 // choose one common task 0148 m_PostscriptDialog.m_cbTask->setCurrentIndex(PS_2xA4); 0149 comboboxChanged(PS_2xA4); 0150 0151 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); 0152 QPushButton *executeButton = new QPushButton; 0153 buttonBox->addButton(executeButton, QDialogButtonBox::ActionRole); 0154 0155 // set an user button to execute the task 0156 buttonBox->button(QDialogButtonBox::Close)->setText(i18n("Done")); 0157 executeButton->setText(i18n("Execute")); 0158 executeButton->setIcon(QIcon::fromTheme("system-run")); 0159 if (!pstops && !psselect) 0160 executeButton->setEnabled(false); 0161 0162 setFocusProxy(m_PostscriptDialog.m_edInfile); 0163 m_PostscriptDialog.m_edInfile->setFocus(); 0164 0165 mainLayout->addWidget(buttonBox); 0166 executeButton->setDefault(true); 0167 mainLayout->addWidget(buttonBox); 0168 connect(buttonBox, &QDialogButtonBox::accepted, 0169 this, &QDialog::accept); 0170 connect(buttonBox, &QDialogButtonBox::rejected, 0171 this, &QDialog::reject); 0172 connect(executeButton, &QPushButton::clicked, 0173 this, &PostscriptDialog::slotExecuteClicked); 0174 connect(m_PostscriptDialog.m_cbTask, static_cast<void (QComboBox::*)(int)>(&KComboBox::activated), 0175 this, &PostscriptDialog::comboboxChanged); 0176 connect(this, &PostscriptDialog::output, m_output, 0177 &KileWidget::OutputView::receive); 0178 } 0179 0180 PostscriptDialog::~PostscriptDialog() 0181 { 0182 if (m_proc) { 0183 delete m_proc; 0184 } 0185 } 0186 0187 void PostscriptDialog::slotExecuteClicked() 0188 { 0189 if (checkParameter()) { 0190 execute(); 0191 } 0192 } 0193 0194 void PostscriptDialog::execute() 0195 { 0196 m_tempfile = buildTempfile(); 0197 0198 if(m_tempfile.isEmpty()) { 0199 m_errorHandler->printMessage(KileTool::Error, i18n("Could not create a temporary file.")); 0200 return; 0201 } 0202 else { 0203 m_errorHandler->clearMessages(); 0204 QFileInfo from(m_PostscriptDialog.m_edInfile->lineEdit()->text()); 0205 QFileInfo to(m_PostscriptDialog.m_edOutfile->lineEdit()->text()); 0206 0207 // output for log window 0208 QString msg = i18n("rearrange ps file: %1", from.fileName()); 0209 if (!to.fileName().isEmpty()) 0210 msg += " ---> " + to.fileName(); 0211 m_errorHandler->printMessage(KileTool::Info, msg, m_program); 0212 0213 // some output logs 0214 m_output->clear(); 0215 QString s = QString("*****\n") 0216 + i18n("***** tool: ") + m_program + ' ' + m_param + '\n' 0217 + i18n("***** input file: ") + from.fileName()+ '\n' 0218 + i18n("***** output file: ") + to.fileName()+ '\n' 0219 + i18n("***** viewer: ") + ((m_PostscriptDialog.m_cbView->isChecked()) ? i18n("yes") : i18n("no")) + '\n' 0220 + "*****\n"; 0221 emit( output(s) ); 0222 0223 // delete old KProcess 0224 if (m_proc) 0225 delete m_proc; 0226 0227 m_proc = new KProcess(); 0228 m_proc->setShellCommand("sh " + m_tempfile); 0229 m_proc->setOutputChannelMode(KProcess::MergedChannels); 0230 m_proc->setReadChannel(QProcess::StandardOutput); 0231 0232 connect(m_proc, SIGNAL(readyReadStandardOutput()), 0233 this, SLOT(slotProcessOutput())); 0234 connect(m_proc, SIGNAL(readyReadStandardError()), 0235 this, SLOT(slotProcessOutput())); 0236 connect(m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), 0237 this, SLOT(slotProcessExited(int,QProcess::ExitStatus))); 0238 0239 KILE_DEBUG_MAIN << "=== PostscriptDialog::runPsutils() ===================="; 0240 KILE_DEBUG_MAIN << " execute '" << m_tempfile << "'"; 0241 m_proc->start(); 0242 } 0243 } 0244 0245 void PostscriptDialog::slotProcessOutput() 0246 { 0247 emit(output(m_proc->readAllStandardOutput())); 0248 emit(output(m_proc->readAllStandardError())); 0249 } 0250 0251 0252 void PostscriptDialog::slotProcessExited(int /* exitCode */, QProcess::ExitStatus exitStatus) 0253 { 0254 if (exitStatus != QProcess::NormalExit) { 0255 showError(i18n("An error occurred while rearranging the file.")); 0256 } 0257 0258 QFile::remove(m_tempfile); 0259 } 0260 0261 QString PostscriptDialog::buildTempfile() 0262 { 0263 // build command 0264 m_program = "pstops"; // default 0265 m_param = ""; 0266 0267 switch (m_PostscriptDialog.m_cbTask->currentIndex()) { 0268 case PS_A5_EMPTY: 0269 m_param = "1:0L(29.7cm,0cm)"; 0270 break; 0271 case PS_A5_DUPLICATE: 0272 m_param = "1:0L(29.7cm,0cm)+0L(29.7cm,14.85cm)"; 0273 break; 0274 case PS_2xA5: 0275 m_param = "2:0L(29.7cm,0cm)+1L(29.7cm,14.85cm)"; 0276 break; 0277 case PS_2xA5L: 0278 break; 0279 case PS_4xA5: 0280 m_param = "4:0@0.7(0cm,8.7cm)" 0281 "+1@0.7(10.5cm,8.7cm)" 0282 "+2@0.7(0cm,-6.15cm)" 0283 "+3@0.7(10.5cm,-6.15cm)"; 0284 break; 0285 case PS_A4_EMPTY: 0286 m_param = "1:0L@0.7(21cm,0cm)"; 0287 break; 0288 case PS_A4_DUPLICATE: 0289 m_param = "1:0L@0.7(21cm,0cm)+0L@0.7(21cm,14.85cm)"; 0290 break; 0291 case PS_2xA4: 0292 m_param = "2:0L@0.7(21cm,0cm)+1L@0.7(21cm,14.85cm)"; 0293 break; 0294 case PS_2xA4L: 0295 m_param = "2:0R@0.7(0cm,29.7cm)+1R@0.7(0cm,14.85cm)"; 0296 break; 0297 case PS_EVEN: 0298 m_program = "psselect"; 0299 m_param = "-e"; 0300 break; 0301 case PS_ODD: 0302 m_program = "psselect"; 0303 m_param = "-o"; 0304 break; 0305 case PS_EVEN_REV: 0306 m_program = "psselect"; 0307 m_param = "-e -r"; 0308 break; 0309 case PS_ODD_REV: 0310 m_program = "psselect"; 0311 m_param = "-o -r"; 0312 break; 0313 case PS_REVERSE: 0314 m_program = "psselect"; 0315 m_param = "-r"; 0316 break; 0317 case PS_COPY_SORTED: 0318 m_program = "psselect"; 0319 m_param = "-p" + duplicateParameter("1-"); 0320 break; 0321 case PS_COPY_UNSORTED: 0322 m_param = "1:" + duplicateParameter("0"); 0323 break; 0324 case PS_PSTOPS_FREE: 0325 m_param = m_PostscriptDialog.m_edParameter->text(); 0326 break; 0327 case PS_PSSELECT_FREE: 0328 m_program = "psselect"; 0329 m_param = m_PostscriptDialog.m_edParameter->text(); 0330 break; 0331 } 0332 0333 // create a temporary file 0334 QTemporaryFile temp; 0335 //code was temp.setSuffix(".sh"); 0336 //Add to constructor and adapt if necessay: QDir::tempPath() + QLatin1String("/myapp_XXXXXX") + QLatin1String(".sh") 0337 temp.setAutoRemove(false); 0338 if(!temp.open()) { 0339 KILE_DEBUG_MAIN << "Could not create tempfile in QString PostscriptDialog::buildTempfile()" ; 0340 return QString(); 0341 } 0342 QString tempname = temp.fileName(); 0343 0344 QTextStream stream(&temp); 0345 stream << "#! /bin/sh" << Qt::endl; 0346 0347 // accept only ".ps" or ".ps.gz" as an input file 0348 QFileInfo fi(m_PostscriptDialog.m_edInfile->lineEdit()->text()); 0349 bool zipped_psfile = (fi.completeSuffix() == "ps.gz") ? true : false; 0350 0351 // there are four possible cases 0352 // outfile view 0353 // 1) + + pstops/psselect + okular 0354 // 2) + - pstops/psselect 0355 // 3) - + pstops/psselect | okular (nur Shell) 0356 // 4) - - error (already detected by checkParameter()) 0357 0358 // some files, which are used 0359 QString command = m_program + " \"" + m_param + "\""; 0360 QString inputfile = "\"" + m_PostscriptDialog.m_edInfile->lineEdit()->text() + "\""; 0361 QString outputfile = "\"" + m_PostscriptDialog.m_edOutfile->lineEdit()->text() + "\""; 0362 bool viewer = m_PostscriptDialog.m_cbView->isChecked(); 0363 0364 bool equalfiles = false; 0365 if (inputfile == outputfile) { 0366 outputfile = tempname + ".tmp"; 0367 equalfiles = true; 0368 } 0369 0370 if (!zipped_psfile) { // unzipped ps files 0371 if (m_PostscriptDialog.m_edOutfile->lineEdit()->text().isEmpty()) { // pstops/psselect | okular 0372 stream << command << " " << inputfile << " | okular -" << Qt::endl; 0373 viewer = false; 0374 } else { // pstops/psselect 0375 stream << command << " " << inputfile << " " << outputfile << Qt::endl; 0376 } 0377 } else { // zipped ps files 0378 if (m_PostscriptDialog.m_edOutfile->lineEdit()->text().isEmpty()) { // pstops/psselect | okular 0379 stream << "gunzip -c " << inputfile 0380 << " | " << command 0381 << " | okular -" 0382 << Qt::endl; 0383 viewer = false; 0384 } else { 0385 stream << "gunzip -c " << inputfile // pstops/psselect 0386 << " | " << command 0387 << " > " << outputfile 0388 << Qt::endl; 0389 } 0390 } 0391 0392 // check, if we should stop 0393 if ( equalfiles || viewer ) { 0394 stream << "if [ $? != 0 ]; then" << Qt::endl; 0395 stream << " exit 1" << Qt::endl; 0396 stream << "fi" << Qt::endl; 0397 } 0398 0399 // replace the original file 0400 if ( equalfiles ) { 0401 stream << "rm " << inputfile << Qt::endl; 0402 stream << "mv " << outputfile << " " << inputfile << Qt::endl; 0403 } 0404 0405 // viewer 0406 if ( viewer ) { // viewer: okular 0407 stream << "okular" << " " 0408 << ((equalfiles) ? inputfile : outputfile) << Qt::endl; 0409 } 0410 0411 // everything is prepared to do the job 0412 temp.close(); 0413 0414 return(tempname); 0415 } 0416 0417 QString PostscriptDialog::duplicateParameter(const QString ¶m) 0418 { 0419 QString s; 0420 for (int i = 0; i < m_PostscriptDialog.m_spCopies->value(); ++i) { 0421 if (i == 0) 0422 s += param; 0423 else 0424 s += ',' + param; 0425 } 0426 0427 return s; 0428 } 0429 0430 0431 bool PostscriptDialog::checkParameter() 0432 { 0433 QString infile = m_PostscriptDialog.m_edInfile->lineEdit()->text(); 0434 if (infile.isEmpty()) { 0435 showError(i18n("No input file is given.")); 0436 return false; 0437 } 0438 0439 QFileInfo fi(infile); 0440 QString suffix = fi.completeSuffix(); 0441 if (suffix != "ps" && suffix != "ps.gz") { 0442 showError(i18n("Unknown file format: only '.ps' and '.ps.gz' are accepted for input files.")); 0443 return false; 0444 } 0445 0446 if (!fi.exists()) { 0447 showError(i18n("This input file does not exist.")); 0448 return false; 0449 } 0450 0451 // check parameter 0452 int index = m_PostscriptDialog.m_cbTask->currentIndex(); 0453 if (m_PostscriptDialog.m_edParameter->text().isEmpty()) { 0454 if (index == PS_PSSELECT_FREE) { 0455 showError( i18n("psselect needs some parameters in this mode.") ); 0456 return false; 0457 } else if (index == PS_PSTOPS_FREE) { 0458 showError( i18n("pstops needs some parameters in this mode.") ); 0459 return false; 0460 } 0461 } 0462 0463 QString outfile = m_PostscriptDialog.m_edOutfile->lineEdit()->text(); 0464 if (outfile.isEmpty() && !m_PostscriptDialog.m_cbView->isChecked()) { 0465 showError(i18n("You need to define an output file or select the viewer.")); 0466 return false; 0467 } 0468 0469 if (! outfile.isEmpty()) { 0470 QFileInfo fo(outfile); 0471 if (fo.completeSuffix() != "ps") { 0472 showError(i18n("Unknown file format: only '.ps' is accepted as output file.")); 0473 return false; 0474 } 0475 0476 if (infile != outfile && fo.exists()) { 0477 QString s = i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?", fo.fileName()); 0478 if (KMessageBox::questionTwoActions(this, 0479 "<center>" + s + "</center>", 0480 "Postscript tools", 0481 KStandardGuiItem::overwrite(), KStandardGuiItem::cancel()) 0482 == KMessageBox::SecondaryAction) { 0483 return false; 0484 } 0485 } 0486 } 0487 0488 return true; 0489 } 0490 0491 void PostscriptDialog::comboboxChanged(int index) 0492 { 0493 KILE_DEBUG_MAIN << index << Qt::endl; 0494 if (index == PS_COPY_SORTED || index == PS_COPY_UNSORTED) { 0495 m_PostscriptDialog.m_lbParameter->setEnabled(true); 0496 m_PostscriptDialog.m_lbParameter->setText(i18n("Copies:")); 0497 m_PostscriptDialog.m_edParameter->hide(); 0498 m_PostscriptDialog.m_spCopies->show(); 0499 m_PostscriptDialog.m_spCopies->setEnabled(true); 0500 } else { 0501 if (index == PS_PSSELECT_FREE || index == PS_PSTOPS_FREE) { 0502 m_PostscriptDialog.m_lbParameter->setEnabled(true); 0503 m_PostscriptDialog.m_lbParameter->setText(i18n("Parameter:")); 0504 m_PostscriptDialog.m_spCopies->hide(); 0505 m_PostscriptDialog.m_edParameter->show(); 0506 m_PostscriptDialog.m_edParameter->setEnabled(true); 0507 } else { 0508 m_PostscriptDialog.m_lbParameter->setEnabled(false); 0509 m_PostscriptDialog.m_edParameter->setEnabled(false); 0510 m_PostscriptDialog.m_spCopies->setEnabled(false); 0511 } 0512 } 0513 } 0514 0515 void PostscriptDialog::showError(const QString &text) 0516 { 0517 KMessageBox::error(this, i18n("<center>") + text + i18n("</center>"), i18n("Postscript Tools")); 0518 } 0519 0520 }