00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include "kprinterimpl.h"
00022
#include "kprinter.h"
00023
#include "kmfactory.h"
00024
#include "kmmanager.h"
00025
#include "kmuimanager.h"
00026
#include "kxmlcommand.h"
00027
#include "kmspecialmanager.h"
00028
#include "kmthreadjob.h"
00029
#include "kmprinter.h"
00030
#include "driver.h"
00031
00032
#include <qfile.h>
00033
#include <qregexp.h>
00034
#include <kinputdialog.h>
00035
#include <klocale.h>
00036
#include <dcopclient.h>
00037
#include <kapplication.h>
00038
#include <kstandarddirs.h>
00039
#include <kdatastream.h>
00040
#include <kdebug.h>
00041
#include <kmimemagic.h>
00042
#include <kmessagebox.h>
00043
#include <kprocess.h>
00044
#include <kconfig.h>
00045
00046
#include <stdlib.h>
00047
00048
void dumpOptions(
const QMap<QString,QString>&);
00049
void initEditPrinter(KMPrinter *p)
00050 {
00051
if (!p->isEdited())
00052 {
00053 p->setEditedOptions(p->defaultOptions());
00054 p->setEdited(
true);
00055 }
00056 }
00057
00058
00059
00060 KPrinterImpl::KPrinterImpl(
QObject *parent,
const char *name)
00061 :
QObject(parent,name)
00062 {
00063 loadAppOptions();
00064 }
00065
00066 KPrinterImpl::~KPrinterImpl()
00067 {
00068 }
00069
00070
void KPrinterImpl::preparePrinting(
KPrinter *printer)
00071 {
00072
00073
00074
00075 KMManager *mgr = KMFactory::self()->manager();
00076 DrMain *driver = mgr->loadPrinterDriver(mgr->findPrinter(printer->
printerName()),
false);
00077
if (driver)
00078 {
00079
00080
00081
00082
QString psname = printer->
option(
"PageSize");
00083
if (psname.isEmpty())
00084 {
00085 DrListOption *opt = (DrListOption*)driver->findOption(
"PageSize");
00086
if (opt) psname = opt->get(
"default");
00087 }
00088
if (!psname.isEmpty())
00089 {
00090 printer->
setOption(
"kde-pagesize",QString::number((
int)pageNameToPageSize(psname)));
00091 DrPageSize *ps = driver->findPageSize(psname);
00092
if (ps)
00093 {
00094 printer->
setRealPageSize( ps );
00095 }
00096 }
00097
00098
00099
00100
00101
00102
00103
00104
QString res = printer->
option(
"Resolution" );
00105
if ( res.isEmpty() )
00106 {
00107 DrBase *opt = driver->findOption(
"Resolution" );
00108
if ( opt )
00109 res = opt->get(
"default" );
00110
if ( res.isEmpty() )
00111 res = driver->get(
"resolution" );
00112 }
00113
if ( !res.isEmpty() )
00114 {
00115
QRegExp re(
"(\\d+)(?:x(\\d+))?dpi" );
00116
if ( re.search( res ) != -1 )
00117 {
00118
if ( !re.cap( 2 ).isEmpty() )
00119 printer->
setOption(
"kde-resolution", re.cap( 2 ) );
00120
else
00121 printer->
setOption(
"kde-resolution", re.cap( 1 ) );
00122 }
00123 }
00124
00125
00126
QString fonts = driver->get(
"fonts" );
00127
if ( !fonts.isEmpty() )
00128 printer->
setOption(
"kde-fonts", fonts );
00129
00130
delete driver;
00131 }
00132
00133 }
00134
00135
bool KPrinterImpl::setupCommand(
QString&,
KPrinter*)
00136 {
00137
return false;
00138 }
00139
00140
bool KPrinterImpl::printFiles(
KPrinter *p,
const QStringList& f,
bool flag)
00141 {
00142
QString cmd;
00143
if (p->
option(
"kde-isspecial") ==
"1")
00144 {
00145
if (p->
option(
"kde-special-command").isEmpty() && p->
outputToFile())
00146 {
00147 KURL url( p->
outputFileName() );
00148
if ( !url.isLocalFile() )
00149 {
00150 cmd = ( flag ?
"mv" :
"cp" ) + (
" %in $out{" + p->
outputFileName() +
"}" );
00151 }
00152
else
00153 {
00154
if (f.count() > 1)
00155 {
00156 p->
setErrorMessage(i18n(
"Cannot copy multiple files into one file."));
00157
return false;
00158 }
00159
else
00160 {
00161 KProcess proc;
00162 proc << (flag?
"mv":
"cp") << f[0] << p->
outputFileName();
00163
if (!proc.start(KProcess::Block) || !proc.normalExit() || proc.exitStatus() != 0)
00164 {
00165 p->
setErrorMessage(i18n(
"Cannot save print file to %1. Check that you have write access to it.").arg(p->
outputFileName()));
00166
return false;
00167 }
00168 }
00169
return true;
00170 }
00171 }
00172
else if (!setupSpecialCommand(cmd,p,f))
00173
return false;
00174 }
00175
else if (!setupCommand(cmd,p))
00176
return false;
00177
return startPrinting(cmd,p,f,flag);
00178 }
00179
00180
void KPrinterImpl::broadcastOption(
const QString& key,
const QString& value)
00181 {
00182
00183
QPtrList<KMPrinter> *printers = KMFactory::self()->manager()->printerListComplete(
false);
00184
if (printers)
00185 {
00186
QPtrListIterator<KMPrinter> it(*printers);
00187
for (;it.current();++it)
00188 {
00189 initEditPrinter(it.current());
00190 it.current()->setEditedOption(key,value);
00191 }
00192 }
00193 }
00194
00195
int KPrinterImpl::dcopPrint(
const QString& cmd,
const QStringList& files,
bool removeflag)
00196 {
00197 kdDebug(500) <<
"kdeprint: print command: " << cmd << endl;
00198
00199
int result = 0;
00200 DCOPClient *dclient = kapp->dcopClient();
00201
if (!dclient || (!dclient->isAttached() && !dclient->attach()))
00202 {
00203
return result;
00204 }
00205
00206
QByteArray data, replyData;
00207
QCString replyType;
00208
QDataStream arg( data, IO_WriteOnly );
00209 arg << cmd;
00210 arg << files;
00211 arg << removeflag;
00212
if (dclient->call(
"kded",
"kdeprintd",
"print(QString,QStringList,bool)", data, replyType, replyData ))
00213 {
00214
if (replyType ==
"int")
00215 {
00216
QDataStream _reply_stream( replyData, IO_ReadOnly );
00217 _reply_stream >> result;
00218 }
00219 }
00220
return result;
00221 }
00222
00223
void KPrinterImpl::statusMessage(
const QString& msg,
KPrinter *printer)
00224 {
00225 kdDebug(500) <<
"kdeprint: status message: " << msg << endl;
00226 KConfig *conf = KMFactory::self()->printConfig();
00227 conf->setGroup(
"General");
00228
if (!conf->readBoolEntry(
"ShowStatusMsg",
true))
00229
return;
00230
00231
QString message(msg);
00232
if (printer && !msg.isEmpty())
00233 message.prepend(i18n(
"Printing document: %1").arg(printer->
docName())+
"\n");
00234
00235 DCOPClient *dclient = kapp->dcopClient();
00236
if (!dclient || (!dclient->isAttached() && !dclient->attach()))
00237 {
00238
return;
00239 }
00240
00241
QByteArray data;
00242
QDataStream arg( data, IO_WriteOnly );
00243 arg << message;
00244 arg << (
int)getpid();
00245 arg << kapp->caption();
00246 dclient->send(
"kded",
"kdeprintd",
"statusMessage(QString,int,QString)", data );
00247 }
00248
00249
bool KPrinterImpl::startPrinting(
const QString& cmd,
KPrinter *printer,
const QStringList& files,
bool flag)
00250 {
00251 statusMessage(i18n(
"Sending print data to printer: %1").arg(printer->
printerName()), printer);
00252
00253
QString command(cmd), filestr;
00254
QStringList printfiles;
00255
if (command.find(
"%in") == -1) command.append(
" %in");
00256
00257
for (QStringList::ConstIterator it=files.begin(); it!=files.end(); ++it)
00258
if (QFile::exists(*it))
00259 {
00260
00261 filestr.append(quote(QFile::encodeName(*it))).append(
" ");
00262 printfiles.append(*it);
00263 }
00264
else
00265 kdDebug(500) <<
"File not found: " << (*it) << endl;
00266
00267
if (printfiles.count() > 0)
00268 {
00269 command.replace(
"%in",filestr);
00270
int pid = dcopPrint(command,files,flag);
00271
if (pid > 0)
00272 {
00273
if (printer)
00274 KMThreadJob::createJob(pid,printer->
printerName(),printer->
docName(),getenv(
"USER"),0);
00275
return true;
00276 }
00277
else
00278 {
00279
QString msg = i18n(
"Unable to start child print process. ");
00280
if (pid == 0)
00281 msg += i18n(
"The KDE print server (<b>kdeprintd</b>) could not be contacted. Check that this server is running.");
00282
else
00283 msg += i18n(
"1 is the command that <files> is given to",
"Check the command syntax:\n%1 <files>").arg(cmd);
00284 printer->
setErrorMessage(msg);
00285
return false;
00286 }
00287 }
00288
00289
00290 printer->
setErrorMessage(i18n(
"No valid file was found for printing. Operation aborted."));
00291
return false;
00292
00293 }
00294
00295
QString KPrinterImpl::tempFile()
00296 {
00297
QString f;
00298
00299
do f = locateLocal(
"tmp",
"kdeprint_") + KApplication::randomString(8);
while (QFile::exists(f));
00300
return f;
00301 }
00302
00303
int KPrinterImpl::filterFiles(
KPrinter *printer,
QStringList& files,
bool flag)
00304 {
00305
QStringList flist = QStringList::split(
',',printer->
option(
"_kde-filters"),
false);
00306
QMap<QString,QString> opts = printer->
options();
00307
00308
00309
00310
00311
00312
00313
00314
if (printer->
pageSelection() == KPrinter::SystemSide &&
00315 (printer->
option(
"kde-isspecial") ==
"1" || !(KMFactory::self()->uiManager()->pluginPageCap() & KMUiManager::PSSelect)) &&
00316 (printer->
pageOrder() == KPrinter::LastPageFirst ||
00317 !printer->
option(
"kde-range").isEmpty() ||
00318 printer->
pageSet() != KPrinter::AllPages))
00319 {
00320
if (flist.findIndex(
"psselect") == -1)
00321 {
00322
int index = KXmlCommandManager::self()->insertCommand(flist,
"psselect",
false);
00323
if (index == -1 || !KXmlCommandManager::self()->checkCommand(
"psselect"))
00324 {
00325 printer->
setErrorMessage(i18n(
"<p>Unable to perform the requested page selection. The filter <b>psselect</b> "
00326
"cannot be inserted in the current filter chain. See <b>Filter</b> tab in the "
00327
"printer properties dialog for further information.</p>"));
00328
return -1;
00329 }
00330 }
00331
if (printer->
pageOrder() == KPrinter::LastPageFirst)
00332 opts[
"_kde-psselect-order"] =
"r";
00333
if (!printer->
option(
"kde-range").isEmpty())
00334 opts[
"_kde-psselect-range"] = printer->
option(
"kde-range");
00335
if (printer->
pageSet() != KPrinter::AllPages)
00336 opts[
"_kde-psselect-set"] = (printer->
pageSet() == KPrinter::OddPages ?
"-o" :
"-e");
00337 }
00338
00339
return doFilterFiles(printer, files, flist, opts, flag);
00340 }
00341
00342
int KPrinterImpl::doFilterFiles(
KPrinter *printer,
QStringList& files,
const QStringList& flist,
const QMap<QString,QString>& opts,
bool flag)
00343 {
00344
00345
if (flist.count() == 0)
00346
return 0;
00347
00348
QString filtercmd;
00349
QStringList inputMimeTypes;
00350
for (uint i=0;i<flist.count();i++)
00351 {
00352 KXmlCommand *filter = KXmlCommandManager::self()->loadCommand(flist[i]);
00353
if (!filter)
00354 {
00355 printer->
setErrorMessage(i18n(
"<p>Could not load filter description for <b>%1</b>.</p>").arg(flist[i]));
00356
return -1;
00357 }
00358
if (i == 0)
00359 inputMimeTypes = filter->inputMimeTypes();
00360
00361
QString subcmd = filter->buildCommand(opts,(i>0),(i<(flist.count()-1)));
00362
delete filter;
00363
if (!subcmd.isEmpty())
00364 {
00365 filtercmd.append(subcmd);
00366
if (i < flist.count()-1)
00367 filtercmd.append(
"| ");
00368 }
00369
else
00370 {
00371 printer->
setErrorMessage(i18n(
"<p>Error while reading filter description for <b>%1</b>. Empty command line received.</p>").arg(flist[i]));
00372
return -1;
00373 }
00374 }
00375 kdDebug(500) <<
"kdeprint: filter command: " << filtercmd << endl;
00376
00377
QString rin(
"%in"), rout(
"%out"), rpsl(
"%psl"), rpsu(
"%psu");
00378
QString ps = pageSizeToPageName( printer->
option(
"kde-printsize" ).isEmpty() ? printer->
pageSize() : (
KPrinter::
PageSize )printer->
option(
"kde-printsize" ).toInt() );
00379
for (QStringList::Iterator it=files.begin(); it!=files.end(); ++it)
00380 {
00381
QString mime = KMimeMagic::self()->findFileType(*it)->mimeType();
00382
if (inputMimeTypes.find(mime) == inputMimeTypes.end())
00383 {
00384
if (KMessageBox::warningContinueCancel(0,
00385
"<p>" + i18n(
"The MIME type %1 is not supported as input of the filter chain "
00386
"(this may happen with non-CUPS spoolers when performing page selection "
00387
"on a non-PostScript file). Do you want KDE to convert the file to a supported "
00388
"format?</p>").arg(mime),
00389 QString::null, i18n(
"Convert")) == KMessageBox::Continue)
00390 {
00391
QStringList ff;
00392
int done(0);
00393
00394 ff << *it;
00395
while (done == 0)
00396 {
00397
bool ok(
false);
00398
QString targetMime = KInputDialog::getItem(
00399 i18n(
"Select MIME Type"),
00400 i18n(
"Select the target format for the conversion:"),
00401 inputMimeTypes, 0,
false, &ok);
00402
if (!ok)
00403 {
00404 printer->
setErrorMessage(i18n(
"Operation aborted."));
00405
return -1;
00406 }
00407
QStringList filters = KXmlCommandManager::self()->autoConvert(mime, targetMime);
00408
if (filters.count() == 0)
00409 {
00410 KMessageBox::error(0, i18n(
"No appropriate filter found. Select another target format."));
00411 }
00412
else
00413 {
00414
int result = doFilterFiles(printer, ff, filters,
QMap<QString,QString>(), flag);
00415
if (result == 1)
00416 {
00417 *it = ff[0];
00418 done = 1;
00419 }
00420
else
00421 {
00422 KMessageBox::error(0,
00423 i18n(
"<qt>Operation failed with message:<br>%1<br>Select another target format.</qt>").arg(printer->
errorMessage()));
00424 }
00425 }
00426 }
00427 }
00428
else
00429 {
00430 printer->
setErrorMessage(i18n(
"Operation aborted."));
00431
return -1;
00432 }
00433 }
00434
00435
QString tmpfile = tempFile();
00436
QString cmd(filtercmd);
00437 cmd.replace(rout,quote(tmpfile));
00438 cmd.replace(rpsl,ps.lower());
00439 cmd.replace(rpsu,ps);
00440 cmd.replace(rin,quote(*it));
00441 statusMessage(i18n(
"Filtering print data"), printer);
00442
int status = system(QFile::encodeName(cmd));
00443
if (status < 0 || WEXITSTATUS(status) == 127)
00444 {
00445 printer->
setErrorMessage(i18n(
"Error while filtering. Command was: <b>%1</b>.").arg(filtercmd));
00446
return -1;
00447 }
00448
if (flag) QFile::remove(*it);
00449 *it = tmpfile;
00450 }
00451
return 1;
00452 }
00453
00454
int KPrinterImpl::autoConvertFiles(
KPrinter *printer,
QStringList& files,
bool flag)
00455 {
00456
QString primaryMimeType =
"application/postscript";
00457
QStringList mimeTypes( primaryMimeType );
00458
if ( printer->
option(
"kde-isspecial" ) ==
"1" )
00459 {
00460
if ( !printer->
option(
"kde-special-command" ).isEmpty() )
00461 {
00462 KXmlCommand *cmd = KXmlCommandManager::self()->loadCommand( printer->
option(
"kde-special-command" ),
true );
00463
if ( cmd )
00464 {
00465 mimeTypes = cmd->inputMimeTypes();
00466
00467
00468 primaryMimeType = mimeTypes[ 0 ];
00469 }
00470 }
00471 }
00472
else
00473 {
00474 KMFactory::PluginInfo info = KMFactory::self()->pluginInfo(KMFactory::self()->printSystem());
00475 mimeTypes = info.mimeTypes;
00476 primaryMimeType = info.primaryMimeType;
00477 }
00478 KMFactory::PluginInfo info = KMFactory::self()->pluginInfo(KMFactory::self()->printSystem());
00479
int status(0), result;
00480
for (QStringList::Iterator it=files.begin(); it!=files.end(); )
00481 {
00482
QString mime = KMimeMagic::self()->findFileType(*it)->mimeType();
00483
if ( mime ==
"application/x-zerosize" )
00484 {
00485
00486 KMessageBox::information( NULL,
00487 i18n(
"<qt>The print file is empty and will be ignored:<p>%1</p></qt>" ).arg( *it ),
00488 QString::null,
"emptyFileNotPrinted" );
00489
if ( flag )
00490 QFile::remove( *it );
00491 it = files.remove( it );
00492
continue;
00493 }
00494
else if (mimeTypes.findIndex(mime) == -1)
00495 {
00496
if ((result=KMessageBox::warningYesNoCancel(NULL,
00497 i18n(
"The file format %1 is not directly supported by the current print system. "
00498
"KDE can try to convert this file automatically to a supported format. But you can "
00499
"still try to send the file to the printer without any conversion. Do you want KDE "
00500
"to try to convert this file to %2?").arg(mime).arg(primaryMimeType),
00501 QString::null,
00502 i18n(
"Convert"),
00503 i18n(
"Keep"),
00504 QString::fromLatin1(
"kdeprintAutoConvert"))) == KMessageBox::Yes)
00505 {
00506
00507
QStringList flist = KXmlCommandManager::self()->autoConvert(mime, primaryMimeType);
00508
if (flist.count() == 0)
00509 {
00510
if (KMessageBox::warningYesNo(NULL,
00511 i18n(
"No appropriate filter was found to convert the file "
00512
"format %1 into %2. Do you want to print the "
00513
"file using its original format?").arg(mime).arg(primaryMimeType),
00514 QString::null,
00515 i18n(
"Print"),
00516 i18n(
"Skip")) == KMessageBox::No)
00517 {
00518
if (flag)
00519 QFile::remove(*it);
00520 it = files.remove(it);
00521 }
00522
else
00523 ++it;
00524
continue;
00525 }
00526
QStringList l(*it);
00527
switch (doFilterFiles(printer, l, flist,
QMap<QString,QString>(), flag))
00528 {
00529
case -1:
00530
return -1;
00531
case 0:
00532
break;
00533
case 1:
00534 status = 1;
00535 *it = l[0];
00536
break;
00537 }
00538 }
00539
else if (result == KMessageBox::Cancel)
00540 {
00541 files.clear();
00542
return 0;
00543 }
00544 }
00545 ++it;
00546 }
00547
return status;
00548 }
00549
00550
bool KPrinterImpl::setupSpecialCommand(
QString& cmd,
KPrinter *p,
const QStringList&)
00551 {
00552
QString s(p->
option(
"kde-special-command"));
00553
if (s.isEmpty())
00554 {
00555 p->
setErrorMessage(
"Empty command.");
00556
return false;
00557 }
00558
00559 s = KMFactory::self()->specialManager()->setupCommand(s, p->
options());
00560
00561
QString ps = pageSizeToPageName( p->
option(
"kde-printsize" ).isEmpty() ? p->
pageSize() : (
KPrinter::
PageSize )p->
option(
"kde-printsize" ).toInt() );
00562 s.replace(
"%psl", ps.lower());
00563 s.replace(
"%psu", ps);
00564 s.replace(
"%out",
"$out{" + p->
outputFileName() +
"}");
00565 cmd = s;
00566
return true;
00567 }
00568
00569
QString KPrinterImpl::quote(
const QString& s)
00570 {
return KProcess::quote(s); }
00571
00572
void KPrinterImpl::saveOptions(
const QMap<QString,QString>& opts)
00573 {
00574 m_options = opts;
00575 saveAppOptions();
00576 }
00577
00578
void KPrinterImpl::loadAppOptions()
00579 {
00580 KConfig *conf = KGlobal::config();
00581 conf->setGroup(
"KPrinter Settings");
00582
QStringList opts = conf->readListEntry(
"ApplicationOptions");
00583
for (uint i=0; i<opts.count(); i+=2)
00584
if (opts[i].startsWith(
"app-"))
00585 m_options[opts[i]] = opts[i+1];
00586 }
00587
00588
void KPrinterImpl::saveAppOptions()
00589 {
00590
QStringList optlist;
00591
for (
QMap<QString,QString>::ConstIterator it=m_options.begin(); it!=m_options.end(); ++it)
00592
if (it.key().startsWith(
"app-"))
00593 optlist << it.key() << it.data();
00594
00595 KConfig *conf = KGlobal::config();
00596 conf->setGroup(
"KPrinter Settings");
00597 conf->writeEntry(
"ApplicationOptions", optlist);
00598 }
00599
00600
#include "kprinterimpl.moc"