kdeprint Library API Documentation

ppdloader.cpp

00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (c) 2001-2003 Michael Goffioul <kdeprint@swing.be> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License version 2 as published by the Free Software Foundation. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Library General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Library General Public License 00015 * along with this library; see the file COPYING.LIB. If not, write to 00016 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 * Boston, MA 02111-1307, USA. 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 // ignore the final quote 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 // Initialization 00123 m_groups.clear(); 00124 m_option = NULL; 00125 m_fonts.clear(); 00126 // Open driver file 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 // we don't have any group defined, create the 00217 // most adapted one. 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 // FIXME: support other option types 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 // Store default resolution as it could be fed back 00347 // to the application. And default resolution can 00348 // occur outside a OpenUI/CloseUI pair. 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 //qDebug( "ADDING PAGESIZE: %16s, Size = ( %.2f, %.2f ), Area = ( %.2f, %.2f, %.2f, %.2f )", it.current()->name.latin1(), 00511 // it.current()->size.width, it.current()->size.height, 00512 // it.current()->area.left, it.current()->area.bottom, 00513 // it.current()->area.right, it.current()->area.top ); 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 }
KDE Logo
This file is part of the documentation for kdeprint Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 23:26:41 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003