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