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 <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 // ignore the final quote 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 // Initialization 00121 m_groups.clear(); 00122 m_option = NULL; 00123 m_fonts.clear(); 00124 // Open driver file 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 // we don't have any group defined, create the 00212 // most adapted one. 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 // FIXME: support other option types 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 // Store default resolution as it could be fed back 00342 // to the application. And default resolution can 00343 // occur outside a OpenUI/CloseUI pair. 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 //qDebug( "ADDING PAGESIZE: %16s, Size = ( %.2f, %.2f ), Area = ( %.2f, %.2f, %.2f, %.2f )", it.current()->name.latin1(), 00506 // it.current()->size.width, it.current()->size.height, 00507 // it.current()->area.left, it.current()->area.bottom, 00508 // it.current()->area.right, it.current()->area.top ); 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 }
KDE Logo
This file is part of the documentation for kdeprint Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 16 17:23:18 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003