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.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 5 07:17:51 2004 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003