kdeprint Library API Documentation

ppdloader.cpp

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