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
00356 printer->
setErrorMessage(i18n(
"<p>Error while reading filter description for <b>%1</b>. Empty command line received.</p>").arg(flist[i]));
00357
return -1;
00358 }
00359
if (i == 0)
00360 inputMimeTypes = filter->inputMimeTypes();
00361
00362
QString subcmd = filter->buildCommand(opts,(i>0),(i<(flist.count()-1)));
00363
delete filter;
00364
if (!subcmd.
isEmpty())
00365 {
00366 filtercmd.
append(subcmd);
00367
if (i < flist.count()-1)
00368 filtercmd.
append(
"| ");
00369 }
00370
else
00371 {
00372 printer->
setErrorMessage(i18n(
"<p>Error while reading filter description for <b>%1</b>. Empty command line received.</p>").arg(flist[i]));
00373
return -1;
00374 }
00375 }
00376 kdDebug(500) <<
"kdeprint: filter command: " << filtercmd << endl;
00377
00378
QString rin(
"%in"), rout(
"%out"), rpsl(
"%psl"), rpsu(
"%psu");
00379
QString ps = pageSizeToPageName( printer->
option(
"kde-printsize" ).
isEmpty() ? printer->
pageSize() : (
KPrinter::
PageSize )printer->
option( "kde-printsize" ).toInt() );
00380
for (QStringList::Iterator it=files.begin(); it!=files.end(); ++it)
00381 {
00382
QString mime = KMimeMagic::self()->findFileType(*it)->mimeType();
00383
if (inputMimeTypes.find(mime) == inputMimeTypes.end())
00384 {
00385
if (KMessageBox::warningContinueCancel(0,
00386
"<p>" + i18n(
"The MIME type %1 is not supported as input of the filter chain "
00387
"(this may happen with non-CUPS spoolers when performing page selection "
00388
"on a non-PostScript file). Do you want KDE to convert the file to a supported "
00389
"format?</p>").arg(mime),
00390 QString::null, i18n(
"Convert")) == KMessageBox::Continue)
00391 {
00392
QStringList ff;
00393
int done(0);
00394
00395 ff << *it;
00396
while (done == 0)
00397 {
00398
bool ok(
false);
00399
QString targetMime = KInputDialog::getItem(
00400 i18n(
"Select MIME Type"),
00401 i18n(
"Select the target format for the conversion:"),
00402 inputMimeTypes, 0,
false, &ok);
00403
if (!ok)
00404 {
00405 printer->
setErrorMessage(i18n(
"Operation aborted."));
00406
return -1;
00407 }
00408
QStringList filters = KXmlCommandManager::self()->autoConvert(mime, targetMime);
00409
if (filters.count() == 0)
00410 {
00411 KMessageBox::error(0, i18n(
"No appropriate filter found. Select another target format."));
00412 }
00413
else
00414 {
00415
int result = doFilterFiles(printer, ff, filters,
QMap<QString,QString>(), flag);
00416
if (result == 1)
00417 {
00418 *it = ff[0];
00419 done = 1;
00420 }
00421
else
00422 {
00423 KMessageBox::error(0,
00424 i18n(
"<qt>Operation failed with message:<br>%1<br>Select another target format.</qt>").arg(printer->
errorMessage()));
00425 }
00426 }
00427 }
00428 }
00429
else
00430 {
00431 printer->
setErrorMessage(i18n(
"Operation aborted."));
00432
return -1;
00433 }
00434 }
00435
00436
QString tmpfile = tempFile();
00437
QString cmd(filtercmd);
00438 cmd.
replace(rout,quote(tmpfile));
00439 cmd.
replace(rpsl,ps.
lower());
00440 cmd.
replace(rpsu,ps);
00441 cmd.
replace(rin,quote(*it));
00442 statusMessage(i18n(
"Filtering print data"), printer);
00443
int status = system(QFile::encodeName(cmd));
00444
if (status < 0 || WEXITSTATUS(status) == 127)
00445 {
00446 printer->
setErrorMessage(i18n(
"Error while filtering. Command was: <b>%1</b>.").arg(filtercmd));
00447
return -1;
00448 }
00449
if (flag)
QFile::remove(*it);
00450 *it = tmpfile;
00451 }
00452
return 1;
00453 }
00454
00455
int KPrinterImpl::autoConvertFiles(
KPrinter *printer,
QStringList& files,
bool flag)
00456 {
00457
QString primaryMimeType =
"application/postscript";
00458
QStringList mimeTypes( primaryMimeType );
00459
if ( printer->
option(
"kde-isspecial" ) ==
"1" )
00460 {
00461
if ( !printer->
option(
"kde-special-command" ).
isEmpty() )
00462 {
00463 KXmlCommand *cmd = KXmlCommandManager::self()->loadCommand( printer->
option(
"kde-special-command" ),
true );
00464
if ( cmd )
00465 {
00466 mimeTypes = cmd->inputMimeTypes();
00467
00468
00469 primaryMimeType = mimeTypes[ 0 ];
00470 }
00471 }
00472 }
00473
else
00474 {
00475 KMFactory::PluginInfo info = KMFactory::self()->pluginInfo(KMFactory::self()->printSystem());
00476 mimeTypes = info.mimeTypes;
00477 primaryMimeType = info.primaryMimeType;
00478 }
00479 KMFactory::PluginInfo info = KMFactory::self()->pluginInfo(KMFactory::self()->printSystem());
00480
int status(0), result;
00481
for (QStringList::Iterator it=files.begin(); it!=files.end(); )
00482 {
00483
QString mime = KMimeMagic::self()->findFileType(*it)->mimeType();
00484
if (mimeTypes.findIndex(mime) == -1)
00485 {
00486
if ((result=KMessageBox::warningYesNoCancel(NULL,
00487 i18n(
"The file format %1 is not directly supported by the current print system. "
00488
"KDE can try to convert this file automatically to a supported format. But you can "
00489
"still try to send the file to the printer without any conversion. Do you want KDE "
00490
"to try to convert this file to %2?").arg(mime).arg(primaryMimeType),
00491 QString::null,
00492 i18n(
"Convert"),
00493 i18n(
"Keep"),
00494 QString::fromLatin1(
"kdeprintAutoConvert"))) == KMessageBox::Yes)
00495 {
00496
00497
QStringList flist = KXmlCommandManager::self()->autoConvert(mime, primaryMimeType);
00498
if (flist.count() == 0)
00499 {
00500
if (KMessageBox::warningYesNo(NULL,
00501 i18n(
"No appropriate filter was found to convert the file "
00502
"format %1 into %2. Do you want to print the "
00503
"file using its original format?").arg(mime).arg(primaryMimeType),
00504 QString::null,
00505 i18n(
"Print"),
00506 i18n(
"Skip")) == KMessageBox::No)
00507 {
00508
if (flag)
00509
QFile::remove(*it);
00510 it = files.remove(it);
00511 }
00512
else
00513 ++it;
00514
continue;
00515 }
00516
QStringList l(*it);
00517
switch (doFilterFiles(printer, l, flist,
QMap<QString,QString>(), flag))
00518 {
00519
case -1:
00520
return -1;
00521
case 0:
00522
break;
00523
case 1:
00524 status = 1;
00525 *it = l[0];
00526
break;
00527 }
00528 }
00529
else if (result == KMessageBox::Cancel)
00530 {
00531 files.clear();
00532
return 0;
00533 }
00534 }
00535 ++it;
00536 }
00537
return status;
00538 }
00539
00540
bool KPrinterImpl::setupSpecialCommand(
QString& cmd,
KPrinter *p,
const QStringList&)
00541 {
00542
QString s(p->
option(
"kde-special-command"));
00543
if (s.
isEmpty())
00544 {
00545 p->
setErrorMessage(
"Empty command.");
00546
return false;
00547 }
00548
00549 s = KMFactory::self()->specialManager()->setupCommand(s, p->
options());
00550
00551
QString ps = pageSizeToPageName( p->
option(
"kde-printsize" ).
isEmpty() ? p->
pageSize() : (
KPrinter::
PageSize )p->
option( "kde-printsize" ).toInt() );
00552 s.
replace(
"%psl", ps.
lower());
00553 s.
replace(
"%psu", ps);
00554 s.
replace(
"%out",
"$out{" + p->
outputFileName() +
"}");
00555 cmd = s;
00556
return true;
00557 }
00558
00559
QString KPrinterImpl::quote(
const QString& s)
00560 {
return KProcess::quote(s); }
00561
00562
void KPrinterImpl::saveOptions(
const QMap<QString,QString>& opts)
00563 {
00564 m_options = opts;
00565 saveAppOptions();
00566 }
00567
00568
void KPrinterImpl::loadAppOptions()
00569 {
00570 KConfig *conf = KGlobal::config();
00571 conf->setGroup(
"KPrinter Settings");
00572
QStringList opts = conf->readListEntry(
"ApplicationOptions");
00573
for (uint i=0; i<opts.count(); i+=2)
00574
if (opts[i].startsWith(
"app-"))
00575 m_options[opts[i]] = opts[i+1];
00576 }
00577
00578
void KPrinterImpl::saveAppOptions()
00579 {
00580
QStringList optlist;
00581
for (
QMap<QString,QString>::ConstIterator it=m_options.begin(); it!=m_options.
end(); ++it)
00582
if (it.key().startsWith(
"app-"))
00583 optlist << it.key() << it.data();
00584
00585 KConfig *conf = KGlobal::config();
00586 conf->setGroup(
"KPrinter Settings");
00587 conf->writeEntry(
"ApplicationOptions", optlist);
00588 }
00589
00590
#include "kprinterimpl.moc"