# kdeprint Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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 }

This file is part of the documentation for kdeprint Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:31:06 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003