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