• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeprint
 

tdeprint

  • tdeprint
ppdloader.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (c) 2001-2003 Michael Goffioul <tdeprint@swing.be>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License version 2 as published by the Free Software Foundation.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB. If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  **/
19 
20 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE /* Needed for getline */
22 #endif
23 
24 #include "ppdloader.h"
25 #include "foomatic2loader.h"
26 #include "driver.h"
27 
28 #include <kfilterdev.h>
29 #include <kdebug.h>
30 #include <tdelocale.h>
31 #include <tdetempfile.h>
32 #include <tqfile.h>
33 #include <math.h>
34 #include <stdlib.h>
35 
36 void tdeprint_ppdscanner_init( TQIODevice* );
37 void tdeprint_ppdscanner_terminate( bool deleteIt = true );
38 int tdeprint_ppdscanner_numberoflines();
39 
40 static TQString processLocaleString( const TQString& s )
41 {
42  TQString res;
43  uint pos = 0;
44  while ( pos < s.length() )
45  {
46  TQChar c = s[ pos++ ];
47  if ( c == '<' )
48  {
49  bool flag = false;
50  uint hc = 0;
51  while ( pos < s.length() )
52  {
53  TQChar cc = s[ pos++ ];
54  uint _hc = 0;
55  if ( cc == '>' )
56  break;
57  else if ( cc.isDigit() )
58  _hc = cc.digitValue();
59  else
60  _hc = cc.lower().latin1() - 'a' + 10;
61  if ( flag )
62  {
63  hc |= _hc;
64  res.append( TQChar( hc ) );
65  hc = 0;
66  }
67  else
68  hc = ( _hc << 4 );
69  flag = !flag;
70  }
71  }
72  else
73  {
74  res.append( c );
75  }
76  }
77  return res;
78 }
79 
80 static TQValueList<float> splitNumberString( const TQString& _s )
81 {
82  TQString s = _s.simplifyWhiteSpace();
83  TQValueList<float> l;
84  int p1 = 1, p2 = 0;
85  while ( true )
86  {
87  p2 = s.find( ' ', p1 );
88  if ( p2 != -1 )
89  {
90  l.append( s.mid( p1, p2-p1 ).toFloat() );
91  p1 = p2+1;
92  }
93  else
94  {
95  // ignore the final quote
96  l.append( s.mid( p1, s.length() - p1 - 1 ).toFloat() );
97  break;
98  }
99  }
100  return l;
101 }
102 
103 struct PS_private
104 {
105  TQString name;
106  struct
107  {
108  float width, height;
109  } size;
110  struct
111  {
112  float left, bottom, right, top;
113  } area;
114 };
115 
116 PPDLoader::PPDLoader()
117 {
118  m_option = 0;
119  m_ps.setAutoDelete( true );
120 }
121 
122 PPDLoader::~PPDLoader()
123 {
124 }
125 
126 DrMain* PPDLoader::readFromFile( const TQString& filename )
127 {
128  bool ppdFilenameIsTempFile = false;
129  TQString ppdFilename = filename;
130 
131  if (filename.startsWith("compressed-ppd:")) {
132  KTempFile tempFile(TQString::null, "ppd", 0600);
133  tempFile.setAutoDelete(false);
134  ppdFilename = tempFile.name();
135 
136  TQStringList filenameParts = TQStringList::split(":", filename);
137  TQString databaseFilename = TQString::null;
138  TQString compressedFilename = TQString::null;
139  int i = 0;
140  for (TQStringList::Iterator it = filenameParts.begin(); it != filenameParts.end(); ++it) {
141  if (i == 1) {
142  databaseFilename = *it;
143  }
144  else if (i > 1) {
145  compressedFilename += *it;
146  }
147  i++;
148  }
149 
150  TQString command = databaseFilename + " cat " + compressedFilename;
151 
152  FILE* file = popen(command.ascii(), "r");
153  if (file) {
154  char * line = NULL;
155  size_t len = 0;
156  ssize_t read;
157 
158  FILE* tmpFileStream = tempFile.fstream();
159 
160  while ((read = getline(&line, &len, file)) != -1) {
161  fputs(line, tmpFileStream);
162  }
163  if (line) {
164  free(line);
165  }
166 
167  tempFile.close();
168  pclose(file);
169  }
170  else {
171  fprintf(stderr, "Can't open driver file : %s\n", compressedFilename.ascii());
172  return 0;
173  }
174 
175  ppdFilenameIsTempFile = true;
176  }
177 
178  // Initialization
179  m_groups.clear();
180  m_option = NULL;
181  m_fonts.clear();
182  // Open driver file
183  TQIODevice *d = KFilterDev::deviceForFile( ppdFilename );
184  if ( d && d->open( IO_ReadOnly ) )
185  {
186  DrMain *driver = new DrMain;
187  bool result = true;
188 
189  m_groups.push( driver );
190  tdeprint_ppdscanner_init( d );
191  if ( tdeprint_ppdparse( this ) != 0 )
192  result = false;
193  tdeprint_ppdscanner_terminate( true );
194 
195  if ( result )
196  {
197  if ( m_groups.size() > 1 )
198  kdWarning( 500 ) << "PPD syntax error, GROUP specification not correctly closed" << endl;
199  if ( driver->has( "foodata" ) )
200  {
201  Foomatic2Loader loader;
202  if ( loader.readFromBuffer( driver->get( "foodata" ) ) )
203  {
204  driver = loader.modifyDriver( driver );
205  }
206  else
207  kdWarning( 500 ) << "PPD syntax error, Foomatic data read failed" << endl;
208  }
209  processPageSizes( driver );
210  if ( !m_fonts.isEmpty() )
211  driver->set( "fonts", m_fonts.join( "," ) );
212  if (ppdFilenameIsTempFile) {
213  driver->set("temporary-cppd", ppdFilename);
214  }
215  return driver;
216  }
217  else
218  kdWarning( 500 ) << "PPD syntax error, PPD parse failed" << endl;
219  delete driver;
220  m_ps.clear();
221  }
222  else
223  kdWarning( 500 ) << "PPD read error, unable to open device for file " << ppdFilename << endl;
224  return 0;
225 }
226 
227 DrMain* PPDLoader::loadDriver( const TQString& filename, TQString* msg )
228 {
229  PPDLoader loader;
230  DrMain *driver = loader.readFromFile( filename );
231  if ( !driver && msg )
232  *msg = filename + i18n( "(line %1): " ).arg( tdeprint_ppdscanner_numberoflines() ) + loader.errorMsg();
233  return driver;
234 }
235 
236 bool PPDLoader::openUi( const TQString& name, const TQString& desc, const TQString& type )
237 {
238  if ( m_option )
239  {
240  tqWarning( "PPD syntax error, UI specification not correctly closed" );
241  endUi( m_option->name() );
242  }
243 
244  if ( type == "PickOne" || type == "PickMany" )
245  m_option = new DrListOption;
246  else if ( type == "Boolean" )
247  m_option = new DrBooleanOption;
248  else
249  return false;
250  if ( name[ 0 ] == '*' )
251  m_option->setName( name.mid( 1 ) );
252  else
253  m_option->setName( name );
254  if ( desc.isEmpty() )
255  m_option->set( "text", m_option->name() );
256  else
257  m_option->set( "text", processLocaleString( desc ) );
258  return true;
259 }
260 
261 bool PPDLoader::endUi( const TQString& name )
262 {
263  if ( m_option && ( m_option->name() == name || m_option->name() == name.mid( 1 ) ) )
264  {
265  if ( m_option->name() == "PageRegion" )
266  delete m_option;
267  else
268  {
269  TQString defval = m_option->get( "default" );
270  DrGroup *grp = 0;
271  if ( !defval.isEmpty() )
272  m_option->setValueText( defval );
273  if ( m_groups.size() == 1 )
274  {
275  // we don't have any group defined, create the
276  // most adapted one.
277  grp = findOrCreateGroupForOption( m_option->name() );
278  }
279  else
280  grp = m_groups.top();
281  grp->addOption( m_option );
282  if ( grp->get( "text" ).contains( "install", false ) )
283  m_option->set( "fixed", "1" );
284  }
285  m_option = 0;
286  return true;
287  }
288  return false;
289 }
290 
291 bool PPDLoader::openGroup( const TQString& name, const TQString& desc )
292 {
293  DrGroup *grp = new DrGroup;
294  grp->setName( name );
295  if ( desc.isEmpty() )
296  grp->set( "text", name );
297  else
298  grp->set( "text", processLocaleString( desc ) );
299  m_groups.top()->addGroup( grp );
300  m_groups.push( grp );
301  return true;
302 }
303 
304 bool PPDLoader::endGroup( const TQString& name )
305 {
306  if ( m_groups.size() > 1 && m_groups.top()->name() == name )
307  {
308  m_groups.pop();
309  return true;
310  }
311  return false;
312 }
313 
314 bool PPDLoader::putStatement( const TQString& keyword, const TQString& name, const TQString& desc, const TQStringList& values )
315 {
316  if ( m_option )
317  {
318  if ( !name.isEmpty() && m_option->name() == keyword )
319  {
320  if ( m_option->type() >= DrBase::List )
321  {
322  DrBase *ch = new DrBase;
323  ch->setName( name );
324  if ( desc.isEmpty() )
325  ch->set( "text", name );
326  else
327  ch->set( "text", processLocaleString( desc ) );
328  static_cast<DrListOption*>( m_option )->addChoice( ch );
329  }
330  else
331  {
332  TQString fv = m_option->get( "fixedvals" );
333  if ( fv.isEmpty() )
334  fv = name;
335  else
336  fv.append( "|" + name );
337  m_option->set( "fixedvals", fv );
338  }
339  }
340  else if ( keyword == "FoomaticRIPOption" && name == m_option->name()
341  && values.size() > 1 )
342  {
343  TQString type = values[ 0 ];
344  if ( type == "float" || type == "int" )
345  {
346  DrBase *opt = 0;
347  if ( type == "float" )
348  opt = new DrFloatOption;
349  else
350  opt = new DrIntegerOption;
351  opt->setName( m_option->name() );
352  opt->set( "text", m_option->get( "text" ) );
353  opt->set( "default", m_option->get( "default" ) );
354  if ( m_option->type() == DrBase::List )
355  {
356  TQStringList vals;
357  TQPtrListIterator<DrBase> it( *( static_cast<DrListOption*>( m_option )->choices() ) );
358  for ( ; it.current(); ++it )
359  vals.append( it.current()->name() );
360  opt->set( "fixedvals", vals.join( "|" ) );
361  }
362  delete m_option;
363  m_option = opt;
364  }
365  // FIXME: support other option types
366  }
367  else if ( keyword == "FoomaticRIPOptionRange" && name == m_option->name()
368  && values.size() >= 2 && ( m_option->type() == DrBase::Float || m_option->type() == DrBase::Integer ) )
369  {
370  m_option->set( "minval", values[ 0 ] );
371  m_option->set( "maxval", values[ 1 ] );
372  }
373  }
374  else if ( keyword == "Font" && m_groups.size() > 0 )
375  {
376  m_fonts << name;
377  }
378  return true;
379 }
380 
381 bool PPDLoader::putStatement2( const TQString& keyword, const TQString& value )
382 {
383  if ( !m_option && m_groups.size() == 1 )
384  {
385  DrGroup *driver = m_groups.top();
386  if ( keyword == "NickName" )
387  {
388  driver->set( "text", value );
389  driver->set( "description", value );
390  }
391  else if ( keyword == "Manufacturer" )
392  driver->set( "manufacturer", value );
393  else if ( keyword == "ShortNickName" )
394  driver->set( "model", value );
395  else if ( keyword == "ColorDevice" )
396  driver->set( "colordevice", value == "True" ? "1" : "0" );
397  }
398  return true;
399 }
400 
401 bool PPDLoader::putDefault( const TQString& keyword, const TQString& value )
402 {
403  if ( keyword == "Resolution" && m_groups.size() > 0 )
404  {
405  // Store default resolution as it could be fed back
406  // to the application. And default resolution can
407  // occur outside a OpenUI/CloseUI pair.
408  m_groups[ 0 ]->set( "resolution", value );
409  }
410 
411  if ( m_option && m_option->name() == keyword )
412  {
413  m_option->set( "default", value );
414  return true;
415  }
416  else
417  return false;
418 }
419 
420 bool PPDLoader::putConstraint( const TQString& opt1, const TQString& opt2, const TQString& ch1, const TQString& ch2 )
421 {
422  if ( !m_option && m_groups.size() == 1 )
423  {
424  DrMain *driver = static_cast<DrMain*>( m_groups.top() );
425  driver->addConstraint( new DrConstraint( opt1, opt2, ch1, ch2 ) );
426  }
427  return true;
428 }
429 
430 bool PPDLoader::putFooData( const TQString& data )
431 {
432  if ( !m_option && m_groups.size() == 1 )
433  {
434  m_groups.top()->set( "foodata", m_groups.top()->get( "foodata" ) + data + "\n" );
435  }
436  return true;
437 }
438 
439 bool PPDLoader::putFooProcessedData( const TQVariant& var )
440 {
441  TQMap<TQString,TQVariant>::ConstIterator it = var.mapFind( "args_byname" );
442  if ( it != var.mapEnd() )
443  {
444  TQVariant opts = it.data();
445  for ( it = opts.mapBegin(); it != opts.mapEnd(); ++it )
446  {
447  TQMap<TQString,TQVariant> opt = it.data().toMap();
448  TQString type = opt[ "type" ].toString();
449  if ( type == "float" || type == "int" )
450  {
451  DrBase *o;
452  if ( type == "float" )
453  o = new DrFloatOption;
454  else
455  o = new DrIntegerOption;
456  o->setName( opt[ "name" ].toString() );
457  o->set( "text", opt[ "comment" ].toString() );
458  o->set( "minval", opt[ "min" ].toString() );
459  o->set( "maxval", opt[ "max" ].toString() );
460  o->set( "default", opt[ "default" ].toString() );
461  o->setValueText( o->get( "default" ) );
462 
463  DrGroup *grp = 0;
464  DrBase *old = m_groups.top()->findOption( o->name(), &grp );
465  if ( old )
466  {
467  if ( old->type() == DrBase::List )
468  {
469  TQStringList vals;
470  TQPtrListIterator<DrBase> it( *( static_cast<DrListOption*>( old )->choices() ) );
471  for ( ; it.current(); ++it )
472  vals.append( it.current()->name() );
473  o->set( "fixedvals", vals.join( "|" ) );
474  }
475  grp->removeOption( o->name() );
476  grp->addOption( o );
477  }
478  else
479  {
480  tqWarning( "Option %s not found in original PPD file", o->name().latin1() );
481  delete o;
482  }
483  }
484  }
485  }
486  return true;
487 }
488 
489 bool PPDLoader::putPaperDimension( const TQString& name, const TQString& s )
490 {
491  TQValueList<float> l = splitNumberString( s );
492 
493  PS_private *ps = m_ps.find( name );
494  if ( !ps )
495  {
496  ps = new PS_private;
497  ps->name = name;
498  m_ps.insert( name, ps );
499  }
500  ps->size.width = l[ 0 ];
501  ps->size.height = l[ 1 ];
502 
503  return true;
504 }
505 
506 bool PPDLoader::putImageableArea( const TQString& name, const TQString& s )
507 {
508  TQValueList<float> l = splitNumberString( s );
509 
510  PS_private *ps = m_ps.find( name );
511  if ( !ps )
512  {
513  ps = new PS_private;
514  ps->name = name;
515  m_ps.insert( name, ps );
516  }
517  ps->area.left = l[ 0 ];
518  ps->area.bottom = l[ 1 ];
519  ps->area.right = l[ 2 ];
520  ps->area.top = l[ 3 ];
521 
522  return true;
523 }
524 
525 DrGroup* PPDLoader::findOrCreateGroupForOption( const TQString& optname )
526 {
527  TQString grpname;
528  if ( optname == "PageSize" ||
529  optname == "InputSlot" ||
530  optname == "ManualFeed" ||
531  optname == "MediaType" ||
532  optname == "MediaColor" ||
533  optname == "MediaWeight" )
534  grpname = "General";
535  else if ( optname.startsWith( "stp" ) ||
536  optname == "Cyan" ||
537  optname == "Yellow" ||
538  optname == "Magenta" ||
539  optname == "Density" ||
540  optname == "Contrast" )
541  grpname = "Adjustments";
542  else if ( optname.startsWith( "JCL" ) )
543  grpname = "JCL";
544  else
545  grpname = "Others";
546 
547  DrGroup *grp = 0;
548  for ( TQPtrListIterator<DrGroup> it( m_groups[ 0 ]->groups() ); it.current(); ++it )
549  if ( it.current()->name() == grpname )
550  {
551  grp = it.current();
552  break;
553  }
554  if ( !grp )
555  {
556  grp = new DrGroup;
557  grp->setName( grpname );
558  grp->set( "text", grpname );
559  m_groups[ 0 ]->addGroup( grp );
560  }
561  return grp;
562 }
563 
564 void PPDLoader::processPageSizes( DrMain *driver )
565 {
566  TQDictIterator<PS_private> it( m_ps );
567  for ( ; it.current(); ++it )
568  {
569  //tqDebug( "ADDING PAGESIZE: %16s, Size = ( %.2f, %.2f ), Area = ( %.2f, %.2f, %.2f, %.2f )", it.current()->name.latin1(),
570  // it.current()->size.width, it.current()->size.height,
571  // it.current()->area.left, it.current()->area.bottom,
572  // it.current()->area.right, it.current()->area.top );
573  driver->addPageSize( new DrPageSize( it.current()->name,
574  ( int )it.current()->size.width, ( int )it.current()->size.height,
575  ( int )it.current()->area.left, ( int )it.current()->area.bottom,
576  ( int )ceil( it.current()->size.width - it.current()->area.right ),
577  ( int )ceil( it.current()->size.height - it.current()->area.top ) ) );
578  }
579  m_ps.clear();
580 }
581 
582 void PPDLoader::setErrorMsg( const TQString& msg )
583 {
584  m_errormsg = msg;
585 }
586 
587 TQString PPDLoader::errorMsg() const
588 {
589  return m_errormsg;
590 }

tdeprint

Skip menu "tdeprint"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

tdeprint

Skip menu "tdeprint"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeprint by doxygen 1.8.8
This website is maintained by Timothy Pearson.