00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#include "ppdloader.h"
00021
#include "foomatic2loader.h"
00022
#include "driver.h"
00023
00024
#include <kfilterdev.h>
00025
#include <kdebug.h>
00026
#include <klocale.h>
00027
#include <qfile.h>
00028
#include <math.h>
00029
00030
void kdeprint_ppdscanner_init(
QIODevice* );
00031
void kdeprint_ppdscanner_terminate(
bool deleteIt =
true );
00032
int kdeprint_ppdscanner_numberoflines();
00033
00034
static QString processLocaleString(
const QString& s )
00035 {
00036
QString res;
00037 uint pos = 0;
00038
while ( pos < s.
length() )
00039 {
00040
QChar c = s[ pos++ ];
00041
if ( c ==
'<' )
00042 {
00043
bool flag =
false;
00044 uint hc = 0;
00045
while ( pos < s.length() )
00046 {
00047
QChar cc = s[ pos++ ];
00048 uint _hc = 0;
00049
if ( cc ==
'>' )
00050
break;
00051
else if ( cc.
isDigit() )
00052 _hc = cc.
digitValue();
00053
else
00054 _hc = cc.
lower().latin1() -
'a' + 10;
00055
if ( flag )
00056 {
00057 hc |= _hc;
00058 res.
append(
QChar( hc ) );
00059 hc = 0;
00060 }
00061
else
00062 hc = ( _hc << 4 );
00063 flag = !flag;
00064 }
00065 }
00066
else
00067 {
00068 res.
append( c );
00069 }
00070 }
00071
return res;
00072 }
00073
00074
static QValueList<float> splitNumberString(
const QString& _s )
00075 {
00076
QString s = _s.
simplifyWhiteSpace();
00077
QValueList<float> l;
00078
int p1 = 1, p2 = 0;
00079
while (
true )
00080 {
00081 p2 = s.
find(
' ', p1 );
00082
if ( p2 != -1 )
00083 {
00084 l.
append( s.
mid( p1, p2-p1 ).toFloat() );
00085 p1 = p2+1;
00086 }
00087
else
00088 {
00089
00090 l.
append( s.
mid( p1, s.
length() - p1 - 1 ).toFloat() );
00091
break;
00092 }
00093 }
00094
return l;
00095 }
00096
00097
struct PS_private
00098 {
00099
QString name;
00100
struct
00101
{
00102
float width, height;
00103 } size;
00104
struct
00105
{
00106
float left, bottom, right, top;
00107 } area;
00108 };
00109
00110 PPDLoader::PPDLoader()
00111 {
00112 m_option = 0;
00113 m_ps.setAutoDelete(
true );
00114 }
00115
00116 PPDLoader::~PPDLoader()
00117 {
00118 }
00119
00120 DrMain* PPDLoader::readFromFile(
const QString& filename )
00121 {
00122
00123 m_groups.clear();
00124 m_option = NULL;
00125 m_fonts.clear();
00126
00127
QIODevice *d = KFilterDev::deviceForFile( filename );
00128
if ( d && d->
open( IO_ReadOnly ) )
00129 {
00130 DrMain *driver =
new DrMain;
00131
bool result =
true;
00132
00133 m_groups.push( driver );
00134 kdeprint_ppdscanner_init( d );
00135
if ( kdeprint_ppdparse(
this ) != 0 )
00136 result =
false;
00137 kdeprint_ppdscanner_terminate(
true );
00138
00139
if ( result )
00140 {
00141
if ( m_groups.size() > 1 )
00142 kdWarning( 500 ) <<
"PPD syntax error, GROUP specification not correctly closed" << endl;
00143
if ( driver->has(
"foodata" ) )
00144 {
00145 Foomatic2Loader loader;
00146
if ( loader.readFromBuffer( driver->get(
"foodata" ) ) )
00147 {
00148 driver = loader.modifyDriver( driver );
00149 }
00150
else
00151 kdWarning( 500 ) <<
"PPD syntax error, Foomatic data read failed" << endl;
00152 }
00153 processPageSizes( driver );
00154
if ( !m_fonts.isEmpty() )
00155 driver->set(
"fonts", m_fonts.join(
"," ) );
00156
return driver;
00157 }
00158
else
00159 kdWarning( 500 ) <<
"PPD syntax error, PPD parse failed" << endl;
00160
delete driver;
00161 m_ps.clear();
00162 }
00163
else
00164 kdWarning( 500 ) <<
"PPD read error, unable to open device for file " << filename << endl;
00165
return 0;
00166 }
00167
00168 DrMain* PPDLoader::loadDriver(
const QString& filename,
QString* msg )
00169 {
00170 PPDLoader loader;
00171 DrMain *driver = loader.readFromFile( filename );
00172
if ( !driver && msg )
00173 *msg = filename + i18n(
"(line %1): " ).
arg( kdeprint_ppdscanner_numberoflines() ) + loader.errorMsg();
00174
return driver;
00175 }
00176
00177
bool PPDLoader::openUi(
const QString& name,
const QString& desc,
const QString& type )
00178 {
00179
if ( m_option )
00180 {
00181 qWarning(
"PPD syntax error, UI specification not correctly closed" );
00182 endUi( m_option->name() );
00183 }
00184
00185
if ( type ==
"PickOne" || type ==
"PickMany" )
00186 m_option =
new DrListOption;
00187
else if ( type ==
"Boolean" )
00188 m_option =
new DrBooleanOption;
00189
else
00190
return false;
00191
if ( name[ 0 ] ==
'*' )
00192 m_option->setName( name.mid( 1 ) );
00193
else
00194 m_option->setName( name );
00195
if ( desc.
isEmpty() )
00196 m_option->set(
"text", m_option->name() );
00197
else
00198 m_option->set(
"text", processLocaleString( desc ) );
00199
return true;
00200 }
00201
00202
bool PPDLoader::endUi(
const QString& name )
00203 {
00204
if ( m_option && ( m_option->name() == name || m_option->name() == name.mid( 1 ) ) )
00205 {
00206
if ( m_option->name() ==
"PageRegion" )
00207
delete m_option;
00208
else
00209 {
00210
QString defval = m_option->get(
"default" );
00211 DrGroup *grp = 0;
00212
if ( !defval.
isEmpty() )
00213 m_option->setValueText( defval );
00214
if ( m_groups.size() == 1 )
00215 {
00216
00217
00218 grp = findOrCreateGroupForOption( m_option->name() );
00219 }
00220
else
00221 grp = m_groups.top();
00222 grp->addOption( m_option );
00223
if ( grp->get(
"text" ).contains(
"install",
false ) )
00224 m_option->set(
"fixed",
"1" );
00225 }
00226 m_option = 0;
00227
return true;
00228 }
00229
return false;
00230 }
00231
00232
bool PPDLoader::openGroup(
const QString& name,
const QString& desc )
00233 {
00234 DrGroup *grp =
new DrGroup;
00235 grp->setName( name );
00236
if ( desc.
isEmpty() )
00237 grp->set(
"text", name );
00238
else
00239 grp->set(
"text", processLocaleString( desc ) );
00240 m_groups.top()->addGroup( grp );
00241 m_groups.push( grp );
00242
return true;
00243 }
00244
00245
bool PPDLoader::endGroup(
const QString& name )
00246 {
00247
if ( m_groups.size() > 1 && m_groups.top()->name() == name )
00248 {
00249 m_groups.pop();
00250
return true;
00251 }
00252
return false;
00253 }
00254
00255
bool PPDLoader::putStatement(
const QString& keyword,
const QString& name,
const QString& desc,
const QStringList& values )
00256 {
00257
if ( m_option )
00258 {
00259
if ( !name.isEmpty() && m_option->name() == keyword )
00260 {
00261
if ( m_option->type() >= DrBase::List )
00262 {
00263 DrBase *ch =
new DrBase;
00264 ch->setName( name );
00265
if ( desc.
isEmpty() )
00266 ch->set(
"text", name );
00267
else
00268 ch->set(
"text", processLocaleString( desc ) );
00269 static_cast<DrListOption*>( m_option )->addChoice( ch );
00270 }
00271
else
00272 {
00273
QString fv = m_option->get(
"fixedvals" );
00274
if ( fv.
isEmpty() )
00275 fv = name;
00276
else
00277 fv.
append(
"|" + name );
00278 m_option->set(
"fixedvals", fv );
00279 }
00280 }
00281
else if ( keyword ==
"FoomaticRIPOption" && name == m_option->name()
00282 && values.size() > 1 )
00283 {
00284
QString type = values[ 0 ];
00285
if ( type ==
"float" || type ==
"int" )
00286 {
00287 DrBase *opt = 0;
00288
if ( type ==
"float" )
00289 opt =
new DrFloatOption;
00290
else
00291 opt =
new DrIntegerOption;
00292 opt->setName( m_option->name() );
00293 opt->set(
"text", m_option->get(
"text" ) );
00294 opt->set(
"default", m_option->get(
"default" ) );
00295
if ( m_option->type() == DrBase::List )
00296 {
00297
QStringList vals;
00298
QPtrListIterator<DrBase> it( *( static_cast<DrListOption*>( m_option )->choices() ) );
00299
for ( ; it.
current(); ++it )
00300 vals.append( it.
current()->name() );
00301 opt->set(
"fixedvals", vals.
join(
"|" ) );
00302 }
00303
delete m_option;
00304 m_option = opt;
00305 }
00306
00307 }
00308
else if ( keyword ==
"FoomaticRIPOptionRange" && name == m_option->name()
00309 && values.size() >= 2 && ( m_option->type() == DrBase::Float || m_option->type() == DrBase::Integer ) )
00310 {
00311 m_option->set(
"minval", values[ 0 ] );
00312 m_option->set(
"maxval", values[ 1 ] );
00313 }
00314 }
00315
else if ( keyword ==
"Font" && m_groups.size() > 0 )
00316 {
00317 m_fonts << name;
00318 }
00319
return true;
00320 }
00321
00322
bool PPDLoader::putStatement2(
const QString& keyword,
const QString& value )
00323 {
00324
if ( !m_option && m_groups.size() == 1 )
00325 {
00326 DrGroup *driver = m_groups.top();
00327
if ( keyword ==
"NickName" )
00328 {
00329 driver->set(
"text", value );
00330 driver->set(
"description", value );
00331 }
00332
else if ( keyword ==
"Manufacturer" )
00333 driver->set(
"manufacturer", value );
00334
else if ( keyword ==
"ShortNickName" )
00335 driver->set(
"model", value );
00336
else if ( keyword ==
"ColorDevice" )
00337 driver->set(
"colordevice", value ==
"True" ?
"1" :
"0" );
00338 }
00339
return true;
00340 }
00341
00342
bool PPDLoader::putDefault(
const QString& keyword,
const QString& value )
00343 {
00344
if ( keyword ==
"Resolution" && m_groups.size() > 0 )
00345 {
00346
00347
00348
00349 m_groups[ 0 ]->set(
"resolution", value );
00350 }
00351
00352
if ( m_option && m_option->name() == keyword )
00353 {
00354 m_option->set(
"default", value );
00355
return true;
00356 }
00357
else
00358
return false;
00359 }
00360
00361
bool PPDLoader::putConstraint(
const QString& opt1,
const QString& opt2,
const QString& ch1,
const QString& ch2 )
00362 {
00363
if ( !m_option && m_groups.size() == 1 )
00364 {
00365 DrMain *driver = static_cast<DrMain*>( m_groups.top() );
00366 driver->addConstraint(
new DrConstraint( opt1, opt2, ch1, ch2 ) );
00367 }
00368
return true;
00369 }
00370
00371
bool PPDLoader::putFooData(
const QString& data )
00372 {
00373
if ( !m_option && m_groups.size() == 1 )
00374 {
00375 m_groups.top()->set(
"foodata", m_groups.top()->get(
"foodata" ) + data +
"\n" );
00376 }
00377
return true;
00378 }
00379
00380
bool PPDLoader::putFooProcessedData(
const QVariant& var )
00381 {
00382
QMap<QString,QVariant>::ConstIterator it = var.mapFind(
"args_byname" );
00383
if ( it != var.mapEnd() )
00384 {
00385
QVariant opts = it.data();
00386
for ( it = opts.mapBegin(); it != opts.mapEnd(); ++it )
00387 {
00388
QMap<QString,QVariant> opt = it.data().toMap();
00389
QString type = opt[
"type" ].toString();
00390
if ( type ==
"float" || type ==
"int" )
00391 {
00392 DrBase *o;
00393
if ( type ==
"float" )
00394 o =
new DrFloatOption;
00395
else
00396 o =
new DrIntegerOption;
00397 o->setName( opt[
"name" ].toString() );
00398 o->set(
"text", opt[
"comment" ].toString() );
00399 o->set(
"minval", opt[
"min" ].toString() );
00400 o->set(
"maxval", opt[
"max" ].toString() );
00401 o->set(
"default", opt[
"default" ].toString() );
00402 o->setValueText( o->get(
"default" ) );
00403
00404 DrGroup *grp = 0;
00405 DrBase *old = m_groups.top()->findOption( o->name(), &grp );
00406
if ( old )
00407 {
00408
if ( old->type() == DrBase::List )
00409 {
00410
QStringList vals;
00411
QPtrListIterator<DrBase> it( *( static_cast<DrListOption*>( old )->choices() ) );
00412
for ( ; it.
current(); ++it )
00413 vals.append( it.
current()->name() );
00414 o->set(
"fixedvals", vals.
join(
"|" ) );
00415 }
00416 grp->removeOption( o->name() );
00417 grp->addOption( o );
00418 }
00419
else
00420 {
00421 qWarning(
"Option %s not found in original PPD file", o->name().latin1() );
00422
delete o;
00423 }
00424 }
00425 }
00426 }
00427
return true;
00428 }
00429
00430
bool PPDLoader::putPaperDimension(
const QString& name,
const QString& s )
00431 {
00432
QValueList<float> l = splitNumberString( s );
00433
00434 PS_private *ps = m_ps.find( name );
00435
if ( !ps )
00436 {
00437 ps =
new PS_private;
00438 ps->name = name;
00439 m_ps.insert( name, ps );
00440 }
00441 ps->size.width = l[ 0 ];
00442 ps->size.height = l[ 1 ];
00443
00444
return true;
00445 }
00446
00447
bool PPDLoader::putImageableArea(
const QString& name,
const QString& s )
00448 {
00449
QValueList<float> l = splitNumberString( s );
00450
00451 PS_private *ps = m_ps.find( name );
00452
if ( !ps )
00453 {
00454 ps =
new PS_private;
00455 ps->name = name;
00456 m_ps.insert( name, ps );
00457 }
00458 ps->area.left = l[ 0 ];
00459 ps->area.bottom = l[ 1 ];
00460 ps->area.right = l[ 2 ];
00461 ps->area.top = l[ 3 ];
00462
00463
return true;
00464 }
00465
00466 DrGroup* PPDLoader::findOrCreateGroupForOption(
const QString& optname )
00467 {
00468
QString grpname;
00469
if ( optname ==
"PageSize" ||
00470 optname ==
"InputSlot" ||
00471 optname ==
"ManualFeed" ||
00472 optname ==
"MediaType" ||
00473 optname ==
"MediaColor" ||
00474 optname ==
"MediaWeight" )
00475 grpname =
"General";
00476
else if ( optname.
startsWith(
"stp" ) ||
00477 optname ==
"Cyan" ||
00478 optname ==
"Yellow" ||
00479 optname ==
"Magenta" ||
00480 optname ==
"Density" ||
00481 optname ==
"Contrast" )
00482 grpname =
"Adjustments";
00483
else if ( optname.
startsWith(
"JCL" ) )
00484 grpname =
"JCL";
00485
else
00486 grpname =
"Others";
00487
00488 DrGroup *grp = 0;
00489
for (
QPtrListIterator<DrGroup> it( m_groups[ 0 ]->groups() ); it.
current(); ++it )
00490
if ( it.
current()->name() == grpname )
00491 {
00492 grp = it.
current();
00493
break;
00494 }
00495
if ( !grp )
00496 {
00497 grp =
new DrGroup;
00498 grp->setName( grpname );
00499 grp->set(
"text", grpname );
00500 m_groups[ 0 ]->addGroup( grp );
00501 }
00502
return grp;
00503 }
00504
00505
void PPDLoader::processPageSizes( DrMain *driver )
00506 {
00507
QDictIterator<PS_private> it( m_ps );
00508
for ( ; it.
current(); ++it )
00509 {
00510
00511
00512
00513
00514 driver->addPageSize(
new DrPageSize( it.
current()->name,
00515 (
int )it.
current()->size.width, (
int )it.
current()->size.height,
00516 (
int )it.
current()->area.left, (
int )it.
current()->area.bottom,
00517 (
int )ceil( it.
current()->size.width - it.
current()->area.right ),
00518 (
int )ceil( it.
current()->size.height - it.
current()->area.top ) ) );
00519 }
00520 m_ps.clear();
00521 }
00522
00523
void PPDLoader::setErrorMsg(
const QString& msg )
00524 {
00525 m_errormsg = msg;
00526 }
00527
00528
QString PPDLoader::errorMsg()
const
00529
{
00530
return m_errormsg;
00531 }